difftreelog
fix Unique XCM tests
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 {IKeyringPair} from '@polkadot/types/types';18import {blake2AsHex} from '@polkadot/util-crypto';19import config from '../config';20import {XcmV2TraitsError, XcmV2TraitsOutcome} from '../interfaces';21import {itSub, expect, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingRelayPlaygrounds, usingMoonbeamPlaygrounds} from '../util';2223const UNIQUE_CHAIN = 2037;24const ACALA_CHAIN = 2000;25const MOONBEAM_CHAIN = 2004;2627const relayUrl = config.relayUrl;28const acalaUrl = config.acalaUrl;29const moonbeamUrl = config.moonbeamUrl;3031const ACALA_DECIMALS = 12;3233const TRANSFER_AMOUNT = 2000000000000000000000000n;3435describeXCM('[XCM] Integration test: Exchanging tokens with Acala', () => {36 let alice: IKeyringPair;37 let randomAccount: IKeyringPair;3839 let balanceUniqueTokenInit: bigint;40 let balanceUniqueTokenMiddle: bigint;41 let balanceUniqueTokenFinal: bigint;42 let balanceAcalaTokenInit: bigint;43 let balanceAcalaTokenMiddle: bigint;44 let balanceAcalaTokenFinal: bigint;45 let balanceUniqueForeignTokenInit: bigint;46 let balanceUniqueForeignTokenMiddle: bigint;47 let balanceUniqueForeignTokenFinal: bigint;4849 before(async () => {50 await usingPlaygrounds(async (helper, privateKey) => {51 alice = await privateKey('//Alice');52 [randomAccount] = await helper.arrange.createAccounts([0n], alice);53 });5455 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {56 const destination = {57 V0: {58 X2: [59 'Parent',60 {61 Parachain: UNIQUE_CHAIN,62 },63 ],64 },65 };6667 const metadata = {68 name: 'UNQ',69 symbol: 'UNQ',70 decimals: 18,71 minimalBalance: 1n,72 };7374 await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);75 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);76 balanceAcalaTokenInit = await helper.balance.getSubstrate(randomAccount.address);77 balanceUniqueForeignTokenInit = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});78 });7980 await usingPlaygrounds(async (helper) => {81 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10n * TRANSFER_AMOUNT);82 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);83 });84 });8586 itSub('Should connect and send UNQ to Acala', async ({helper}) => {8788 const destination = {89 V0: {90 X2: [91 'Parent',92 {93 Parachain: ACALA_CHAIN,94 },95 ],96 },97 };9899 const beneficiary = {100 V0: {101 X1: {102 AccountId32: {103 network: 'Any',104 id: randomAccount.addressRaw,105 },106 },107 },108 };109110 const assets = {111 V1: [112 {113 id: {114 Concrete: {115 parents: 0,116 interior: 'Here',117 },118 },119 fun: {120 Fungible: TRANSFER_AMOUNT,121 },122 },123 ],124 };125126 const feeAssetItem = 0;127 const weightLimit = 5000000000;128129 await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, weightLimit);130131 balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);132133 const unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;134 console.log('[Unique -> Acala] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));135 expect(unqFees > 0n).to.be.true;136137 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {138 await helper.wait.newBlocks(3);139140 balanceUniqueForeignTokenMiddle = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});141 balanceAcalaTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);142143 const acaFees = balanceAcalaTokenInit - balanceAcalaTokenMiddle;144 const unqIncomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenInit;145146 console.log(147 '[Unique -> Acala] transaction fees on Acala: %s ACA',148 helper.util.bigIntToDecimals(acaFees, ACALA_DECIMALS),149 );150 console.log('[Unique -> Acala] income %s UNQ', helper.util.bigIntToDecimals(unqIncomeTransfer));151 expect(acaFees == 0n).to.be.true;152 expect(unqIncomeTransfer == TRANSFER_AMOUNT).to.be.true;153 });154 });155156 itSub('Should connect to Acala and send UNQ back', async ({helper}) => {157 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {158 const destination = {159 V1: {160 parents: 1,161 interior: {162 X2: [163 {Parachain: UNIQUE_CHAIN},164 {165 AccountId32: {166 network: 'Any',167 id: randomAccount.addressRaw,168 },169 },170 ],171 },172 },173 };174175 const id = {176 ForeignAsset: 0,177 };178179 const destWeight = 50000000;180181 await helper.xTokens.transfer(randomAccount, id, TRANSFER_AMOUNT, destination, destWeight);182183 balanceAcalaTokenFinal = await helper.balance.getSubstrate(randomAccount.address);184 balanceUniqueForeignTokenFinal = await helper.tokens.accounts(randomAccount.address, id);185186 const acaFees = balanceAcalaTokenMiddle - balanceAcalaTokenFinal;187 const unqOutcomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenFinal;188189 console.log(190 '[Acala -> Unique] transaction fees on Acala: %s ACA',191 helper.util.bigIntToDecimals(acaFees, ACALA_DECIMALS),192 );193 console.log('[Acala -> Unique] outcome %s UNQ', helper.util.bigIntToDecimals(unqOutcomeTransfer));194195 expect(acaFees > 0).to.be.true;196 expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;197 });198199 await helper.wait.newBlocks(3);200201 balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccount.address);202 const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;203 expect(actuallyDelivered > 0).to.be.true;204205 console.log('[Acala -> Unique] actually delivered %s UNQ', helper.util.bigIntToDecimals(actuallyDelivered));206207 const unqFees = TRANSFER_AMOUNT - actuallyDelivered;208 console.log('[Acala -> Unique] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));209 expect(unqFees == 0n).to.be.true;210 });211});212213// These tests are relevant only when the foreign asset pallet is disabled214describeXCM('[XCM] Integration test: Unique rejects non-native tokens', () => {215 let alice: IKeyringPair;216217 before(async () => {218 await usingPlaygrounds(async (_helper, privateKey) => {219 alice = await privateKey('//Alice');220 });221 });222223 itSub('Unique rejects tokens from the Relay', async ({helper}) => {224 await usingRelayPlaygrounds(relayUrl, async (helper) => {225 const destination = {226 V1: {227 parents: 0,228 interior: {X1: {229 Parachain: UNIQUE_CHAIN,230 },231 },232 }};233234 const beneficiary = {235 V1: {236 parents: 0,237 interior: {X1: {238 AccountId32: {239 network: 'Any',240 id: alice.addressRaw,241 },242 }},243 },244 };245246 const assets = {247 V1: [248 {249 id: {250 Concrete: {251 parents: 0,252 interior: 'Here',253 },254 },255 fun: {256 Fungible: 50_000_000_000_000_000n,257 },258 },259 ],260 };261262 const feeAssetItem = 0;263 const weightLimit = 5_000_000_000;264265 await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, weightLimit);266 });267268 const maxWaitBlocks = 3;269270 const dmpQueueExecutedDownward = await helper.wait.event(maxWaitBlocks, 'dmpQueue', 'ExecutedDownward');271272 expect(273 dmpQueueExecutedDownward != null,274 '[Relay] dmpQueue.ExecutedDownward event is expected',275 ).to.be.true;276277 const event = dmpQueueExecutedDownward!.event;278 const outcome = event.data[1] as XcmV2TraitsOutcome;279280 expect(281 outcome.isIncomplete,282 '[Relay] The outcome of the XCM should be `Incomplete`',283 ).to.be.true;284285 const incomplete = outcome.asIncomplete;286 expect(287 incomplete[1].toString() == 'AssetNotFound',288 '[Relay] The XCM error should be `AssetNotFound`',289 ).to.be.true;290 });291292 itSub('Unique rejects ACA tokens from Acala', async ({helper}) => {293 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {294 const destination = {295 V1: {296 parents: 1,297 interior: {298 X2: [299 {Parachain: UNIQUE_CHAIN},300 {301 AccountId32: {302 network: 'Any',303 id: alice.addressRaw,304 },305 },306 ],307 },308 },309 };310311 const id = {312 Token: 'ACA',313 };314315 const destWeight = 50000000;316317 await helper.xTokens.transfer(alice, id, 100_000_000_000n, destination, destWeight);318 });319320 const maxWaitBlocks = 3;321322 const xcmpQueueFailEvent = await helper.wait.event(maxWaitBlocks, 'xcmpQueue', 'Fail');323324 expect(325 xcmpQueueFailEvent != null,326 '[Acala] xcmpQueue.FailEvent event is expected',327 ).to.be.true;328329 const event = xcmpQueueFailEvent!.event;330 const outcome = event.data[1] as XcmV2TraitsError;331332 expect(333 outcome.isUntrustedReserveLocation,334 '[Acala] The XCM error should be `UntrustedReserveLocation`',335 ).to.be.true;336 });337});338339describeXCM('[XCM] Integration test: Exchanging UNQ with Moonbeam', () => {340 // Unique constants341 let uniqueDonor: IKeyringPair;342 let uniqueAssetLocation;343344 let randomAccountUnique: IKeyringPair;345 let randomAccountMoonbeam: IKeyringPair;346347 // Moonbeam constants348 let assetId: string;349350 const councilVotingThreshold = 2;351 const technicalCommitteeThreshold = 2;352 const votingPeriod = 3;353 const delayPeriod = 0;354355 const uniqueAssetMetadata = {356 name: 'xcUnique',357 symbol: 'xcUNQ',358 decimals: 18,359 isFrozen: false,360 minimalBalance: 1n,361 };362363 let balanceUniqueTokenInit: bigint;364 let balanceUniqueTokenMiddle: bigint;365 let balanceUniqueTokenFinal: bigint;366 let balanceForeignUnqTokenInit: bigint;367 let balanceForeignUnqTokenMiddle: bigint;368 let balanceForeignUnqTokenFinal: bigint;369 let balanceGlmrTokenInit: bigint;370 let balanceGlmrTokenMiddle: bigint;371 let balanceGlmrTokenFinal: bigint;372373 before(async () => {374 await usingPlaygrounds(async (helper, privateKey) => {375 uniqueDonor = await privateKey('//Alice');376 [randomAccountUnique] = await helper.arrange.createAccounts([0n], uniqueDonor);377378 balanceForeignUnqTokenInit = 0n;379 });380381 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {382 const alithAccount = helper.account.alithAccount();383 const baltatharAccount = helper.account.baltatharAccount();384 const dorothyAccount = helper.account.dorothyAccount();385386 randomAccountMoonbeam = helper.account.create();387388 // >>> Sponsoring Dorothy >>>389 console.log('Sponsoring Dorothy.......');390 await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);391 console.log('Sponsoring Dorothy.......DONE');392 // <<< Sponsoring Dorothy <<<393394 uniqueAssetLocation = {395 XCM: {396 parents: 1,397 interior: {X1: {Parachain: UNIQUE_CHAIN}},398 },399 };400 const existentialDeposit = 1n;401 const isSufficient = true;402 const unitsPerSecond = 1n;403 const numAssetsWeightHint = 0;404405 const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({406 location: uniqueAssetLocation,407 metadata: uniqueAssetMetadata,408 existentialDeposit,409 isSufficient,410 unitsPerSecond,411 numAssetsWeightHint,412 });413 const proposalHash = blake2AsHex(encodedProposal);414415 console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);416 console.log('Encoded length %d', encodedProposal.length);417 console.log('Encoded proposal hash for batch utility after schedule is %s', proposalHash);418419 // >>> Note motion preimage >>>420 console.log('Note motion preimage.......');421 await helper.democracy.notePreimage(baltatharAccount, encodedProposal);422 console.log('Note motion preimage.......DONE');423 // <<< Note motion preimage <<<424425 // >>> Propose external motion through council >>>426 console.log('Propose external motion through council.......');427 const externalMotion = helper.democracy.externalProposeMajority(proposalHash);428 const encodedMotion = externalMotion?.method.toHex() || '';429 const motionHash = blake2AsHex(encodedMotion);430 console.log('Motion hash is %s', motionHash);431432 await helper.collective.council.propose(baltatharAccount, councilVotingThreshold, externalMotion, externalMotion.encodedLength);433434 const councilProposalIdx = await helper.collective.council.proposalCount() - 1;435 await helper.collective.council.vote(dorothyAccount, motionHash, councilProposalIdx, true);436 await helper.collective.council.vote(baltatharAccount, motionHash, councilProposalIdx, true);437438 await helper.collective.council.close(dorothyAccount, motionHash, councilProposalIdx, 1_000_000_000, externalMotion.encodedLength);439 console.log('Propose external motion through council.......DONE');440 // <<< Propose external motion through council <<<441442 // >>> Fast track proposal through technical committee >>>443 console.log('Fast track proposal through technical committee.......');444 const fastTrack = helper.democracy.fastTrack(proposalHash, votingPeriod, delayPeriod);445 const encodedFastTrack = fastTrack?.method.toHex() || '';446 const fastTrackHash = blake2AsHex(encodedFastTrack);447 console.log('FastTrack hash is %s', fastTrackHash);448449 await helper.collective.techCommittee.propose(alithAccount, technicalCommitteeThreshold, fastTrack, fastTrack.encodedLength);450451 const techProposalIdx = await helper.collective.techCommittee.proposalCount() - 1;452 await helper.collective.techCommittee.vote(baltatharAccount, fastTrackHash, techProposalIdx, true);453 await helper.collective.techCommittee.vote(alithAccount, fastTrackHash, techProposalIdx, true);454455 await helper.collective.techCommittee.close(baltatharAccount, fastTrackHash, techProposalIdx, 1_000_000_000, fastTrack.encodedLength);456 console.log('Fast track proposal through technical committee.......DONE');457 // <<< Fast track proposal through technical committee <<<458459 // >>> Referendum voting >>>460 console.log('Referendum voting.......');461 await helper.democracy.referendumVote(dorothyAccount, 0, {462 balance: 10_000_000_000_000_000_000n,463 vote: {aye: true, conviction: 1},464 });465 console.log('Referendum voting.......DONE');466 // <<< Referendum voting <<<467468 // >>> Acquire Unique AssetId Info on Moonbeam >>>469 console.log('Acquire Unique AssetId Info on Moonbeam.......');470471 // Wait for the democracy execute472 await helper.wait.newBlocks(5);473474 assetId = (await helper.assetManager.assetTypeId(uniqueAssetLocation)).toString();475476 console.log('UNQ asset ID is %s', assetId);477 console.log('Acquire Unique AssetId Info on Moonbeam.......DONE');478 // >>> Acquire Unique AssetId Info on Moonbeam >>>479480 // >>> Sponsoring random Account >>>481 console.log('Sponsoring random Account.......');482 await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonbeam.address, 11_000_000_000_000_000_000n);483 console.log('Sponsoring random Account.......DONE');484 // <<< Sponsoring random Account <<<485486 balanceGlmrTokenInit = await helper.balance.getEthereum(randomAccountMoonbeam.address);487 });488489 await usingPlaygrounds(async (helper) => {490 await helper.balance.transferToSubstrate(uniqueDonor, randomAccountUnique.address, 10n * TRANSFER_AMOUNT);491 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccountUnique.address);492 });493 });494495 itSub('Should connect and send UNQ to Moonbeam', async ({helper}) => {496 const currencyId = {497 NativeAssetId: 'Here',498 };499 const dest = {500 V1: {501 parents: 1,502 interior: {503 X2: [504 {Parachain: MOONBEAM_CHAIN},505 {AccountKey20: {network: 'Any', key: randomAccountMoonbeam.address}},506 ],507 },508 },509 };510 const amount = TRANSFER_AMOUNT;511 const destWeight = 850000000;512513 await helper.xTokens.transfer(randomAccountUnique, currencyId, amount, dest, destWeight);514515 balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccountUnique.address);516 expect(balanceUniqueTokenMiddle < balanceUniqueTokenInit).to.be.true;517518 const transactionFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;519 console.log('[Unique -> Moonbeam] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(transactionFees));520 expect(transactionFees > 0).to.be.true;521522 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {523 await helper.wait.newBlocks(3);524525 balanceGlmrTokenMiddle = await helper.balance.getEthereum(randomAccountMoonbeam.address);526527 const glmrFees = balanceGlmrTokenInit - balanceGlmrTokenMiddle;528 console.log('[Unique -> Moonbeam] transaction fees on Moonbeam: %s GLMR', helper.util.bigIntToDecimals(glmrFees));529 expect(glmrFees == 0n).to.be.true;530531 balanceForeignUnqTokenMiddle = (await helper.assets.account(assetId, randomAccountMoonbeam.address))!;532533 const unqIncomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenInit;534 console.log('[Unique -> Moonbeam] income %s UNQ', helper.util.bigIntToDecimals(unqIncomeTransfer));535 expect(unqIncomeTransfer == TRANSFER_AMOUNT).to.be.true;536 });537 });538539 itSub('Should connect to Moonbeam and send UNQ back', async ({helper}) => {540 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {541 const asset = {542 V1: {543 id: {544 Concrete: {545 parents: 1,546 interior: {547 X1: {Parachain: UNIQUE_CHAIN},548 },549 },550 },551 fun: {552 Fungible: TRANSFER_AMOUNT,553 },554 },555 };556 const destination = {557 V1: {558 parents: 1,559 interior: {560 X2: [561 {Parachain: UNIQUE_CHAIN},562 {AccountId32: {network: 'Any', id: randomAccountUnique.addressRaw}},563 ],564 },565 },566 };567 const destWeight = 50000000;568569 await helper.xTokens.transferMultiasset(randomAccountMoonbeam, asset, destination, destWeight);570571 balanceGlmrTokenFinal = await helper.balance.getEthereum(randomAccountMoonbeam.address);572573 const glmrFees = balanceGlmrTokenMiddle - balanceGlmrTokenFinal;574 console.log('[Moonbeam -> Unique] transaction fees on Moonbeam: %s GLMR', helper.util.bigIntToDecimals(glmrFees));575 expect(glmrFees > 0).to.be.true;576577 const unqRandomAccountAsset = await helper.assets.account(assetId, randomAccountMoonbeam.address);578579 expect(unqRandomAccountAsset).to.be.null;580 581 balanceForeignUnqTokenFinal = 0n;582583 const unqOutcomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenFinal;584 console.log('[Unique -> Moonbeam] outcome %s UNQ', helper.util.bigIntToDecimals(unqOutcomeTransfer));585 expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;586 });587588 await helper.wait.newBlocks(3);589590 balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccountUnique.address);591 const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;592 expect(actuallyDelivered > 0).to.be.true;593594 console.log('[Moonbeam -> Unique] actually delivered %s UNQ', helper.util.bigIntToDecimals(actuallyDelivered));595596 const unqFees = TRANSFER_AMOUNT - actuallyDelivered;597 console.log('[Moonbeam -> Unique] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));598 expect(unqFees == 0n).to.be.true;599 });600});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 config from '../config';20import {XcmV2TraitsError} from '../interfaces';21import {itSub, expect, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingRelayPlaygrounds, usingMoonbeamPlaygrounds, usingStatemintPlaygrounds} from '../util';2223const UNIQUE_CHAIN = 2037;24const STATEMINT_CHAIN = 1000;25const ACALA_CHAIN = 2000;26const MOONBEAM_CHAIN = 2004;2728const STATEMINT_PALLET_INSTANCE = 50;2930const relayUrl = config.relayUrl;31const statemintUrl = config.statemintUrl;32const acalaUrl = config.acalaUrl;33const moonbeamUrl = config.moonbeamUrl;3435const RELAY_DECIMALS = 12;36const STATEMINT_DECIMALS = 12;37const ACALA_DECIMALS = 12;3839const TRANSFER_AMOUNT = 2000000000000000000000000n;4041const FUNDING_AMOUNT = 3_500_000_0000_000_000n; 4243const TRANSFER_AMOUNT_RELAY = 50_000_000_000_000_000n;4445const USDT_ASSET_ID = 100;46const USDT_ASSET_METADATA_DECIMALS = 18;47const USDT_ASSET_METADATA_NAME = 'USDT';48const USDT_ASSET_METADATA_DESCRIPTION = 'USDT';49const USDT_ASSET_METADATA_MINIMAL_BALANCE = 1n;50const USDT_ASSET_AMOUNT = 10_000_000_000_000_000_000_000_000n;5152describeXCM('[XCM] Integration test: Exchanging USDT with Statemint', () => {53 let alice: IKeyringPair;54 let bob: IKeyringPair;55 56 let balanceStmnBefore: bigint;57 let balanceStmnAfter: bigint;5859 let balanceUniqueBefore: bigint;60 let balanceUniqueAfter: bigint;61 let balanceUniqueFinal: bigint;6263 let balanceBobBefore: bigint;64 let balanceBobAfter: bigint;65 let balanceBobFinal: bigint;6667 let balanceBobRelayTokenBefore: bigint;68 let balanceBobRelayTokenAfter: bigint;697071 before(async () => {72 await usingPlaygrounds(async (_helper, privateKey) => {73 alice = await privateKey('//Alice');74 bob = await privateKey('//Bob'); // sovereign account on Statemint funds donor75 });7677 await usingRelayPlaygrounds(relayUrl, async (helper) => {78 // Fund accounts on Statemint79 await helper.xcm.teleportNativeAsset(alice, STATEMINT_CHAIN, alice.addressRaw, FUNDING_AMOUNT);80 await helper.xcm.teleportNativeAsset(alice, STATEMINT_CHAIN, bob.addressRaw, FUNDING_AMOUNT);81 });8283 await usingStatemintPlaygrounds(statemintUrl, async (helper) => {84 const sovereignFundingAmount = 3_500_000_000n; 8586 await helper.assets.create(87 alice,88 USDT_ASSET_ID,89 alice.address,90 USDT_ASSET_METADATA_MINIMAL_BALANCE,91 );92 await helper.assets.setMetadata(93 alice,94 USDT_ASSET_ID,95 USDT_ASSET_METADATA_NAME,96 USDT_ASSET_METADATA_DESCRIPTION,97 USDT_ASSET_METADATA_DECIMALS,98 );99 await helper.assets.mint(100 alice,101 USDT_ASSET_ID,102 alice.address,103 USDT_ASSET_AMOUNT,104 );105106 // funding parachain sovereing account on Statemint.107 // The sovereign account should be created before any action108 // (the assets pallet on Statemint check if the sovereign account exists)109 const parachainSovereingAccount = helper.address.paraSiblingSovereignAccount(UNIQUE_CHAIN);110 await helper.balance.transferToSubstrate(bob, parachainSovereingAccount, sovereignFundingAmount);111 });112113114 await usingPlaygrounds(async (helper) => {115 const location = {116 V1: {117 parents: 1,118 interior: {X3: [119 {120 Parachain: STATEMINT_CHAIN,121 },122 {123 PalletInstance: STATEMINT_PALLET_INSTANCE,124 },125 {126 GeneralIndex: USDT_ASSET_ID,127 },128 ]},129 },130 };131132 const metadata =133 {134 name: USDT_ASSET_ID,135 symbol: USDT_ASSET_METADATA_NAME,136 decimals: USDT_ASSET_METADATA_DECIMALS,137 minimalBalance: USDT_ASSET_METADATA_MINIMAL_BALANCE,138 };139 await helper.getSudo().foreignAssets.register(alice, alice.address, location, metadata);140 balanceUniqueBefore = await helper.balance.getSubstrate(alice.address);141 });142143144 // Providing the relay currency to the unique sender account145 // (fee for USDT XCM are paid in relay tokens)146 await usingRelayPlaygrounds(relayUrl, async (helper) => {147 const destination = {148 V1: {149 parents: 0,150 interior: {X1: {151 Parachain: UNIQUE_CHAIN,152 },153 },154 }};155156 const beneficiary = {157 V1: {158 parents: 0,159 interior: {X1: {160 AccountId32: {161 network: 'Any',162 id: alice.addressRaw,163 },164 }},165 },166 };167168 const assets = {169 V1: [170 {171 id: {172 Concrete: {173 parents: 0,174 interior: 'Here',175 },176 },177 fun: {178 Fungible: TRANSFER_AMOUNT_RELAY,179 },180 },181 ],182 };183184 const feeAssetItem = 0;185186 await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, {Unlimited: null});187 });188 189 });190191 itSub('Should connect and send USDT from Statemint to Unique', async ({helper}) => {192 await usingStatemintPlaygrounds(statemintUrl, async (helper) => {193 const dest = {194 V1: {195 parents: 1,196 interior: {X1: {197 Parachain: UNIQUE_CHAIN,198 },199 },200 }};201202 const beneficiary = {203 V1: {204 parents: 0,205 interior: {X1: {206 AccountId32: {207 network: 'Any',208 id: alice.addressRaw,209 },210 }},211 },212 };213214 const assets = {215 V1: [216 {217 id: {218 Concrete: {219 parents: 0,220 interior: {221 X2: [222 {223 PalletInstance: STATEMINT_PALLET_INSTANCE,224 },225 {226 GeneralIndex: USDT_ASSET_ID,227 }, 228 ]},229 },230 },231 fun: {232 Fungible: TRANSFER_AMOUNT,233 },234 },235 ],236 };237238 const feeAssetItem = 0;239240 balanceStmnBefore = await helper.balance.getSubstrate(alice.address);241 await helper.xcm.limitedReserveTransferAssets(alice, dest, beneficiary, assets, feeAssetItem, {Unlimited: null});242243 balanceStmnAfter = await helper.balance.getSubstrate(alice.address);244245 // common good parachain take commission in it native token246 console.log(247 '[Statemint -> Unique] transaction fees on Statemint: %s WND',248 helper.util.bigIntToDecimals(balanceStmnBefore - balanceStmnAfter, STATEMINT_DECIMALS),249 );250 expect(balanceStmnBefore > balanceStmnAfter).to.be.true;251252 });253254255 // ensure that asset has been delivered256 await helper.wait.newBlocks(3);257258 // expext collection id will be with id 1259 const free = await helper.ft.getBalance(1, {Substrate: alice.address});260261 balanceUniqueAfter = await helper.balance.getSubstrate(alice.address);262263 console.log(264 '[Statemint -> Unique] transaction fees on Unique: %s USDT',265 helper.util.bigIntToDecimals(TRANSFER_AMOUNT - free, USDT_ASSET_METADATA_DECIMALS),266 );267 console.log(268 '[Statemint -> Unique] transaction fees on Unique: %s UNQ',269 helper.util.bigIntToDecimals(balanceUniqueAfter - balanceUniqueBefore),270 ); 271 // commission has not paid in USDT token272 expect(free).to.be.equal(TRANSFER_AMOUNT);273 // ... and parachain native token274 expect(balanceUniqueAfter == balanceUniqueBefore).to.be.true;275 });276277 itSub('Should connect and send USDT from Unique to Statemint back', async ({helper}) => {278 const destination = {279 V1: {280 parents: 1,281 interior: {X2: [282 {283 Parachain: STATEMINT_CHAIN,284 },285 {286 AccountId32: {287 network: 'Any',288 id: alice.addressRaw,289 },290 },291 ]},292 },293 };294295 const relayFee = 400_000_000_000_000n;296 const currencies: [any, bigint][] = [297 [298 {299 ForeignAssetId: 0,300 },301 TRANSFER_AMOUNT,302 ], 303 [304 {305 NativeAssetId: 'Parent',306 },307 relayFee,308 ],309 ];310311 const feeItem = 1;312313 await helper.xTokens.transferMulticurrencies(alice, currencies, feeItem, destination, {Unlimited: null});314 315 // the commission has been paid in parachain native token316 balanceUniqueFinal = await helper.balance.getSubstrate(alice.address);317 console.log('[Unique -> Statemint] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(balanceUniqueFinal - balanceUniqueAfter));318 expect(balanceUniqueAfter > balanceUniqueFinal).to.be.true;319320 await usingStatemintPlaygrounds(statemintUrl, async (helper) => {321 await helper.wait.newBlocks(3);322 323 // The USDT token never paid fees. Its amount not changed from begin value.324 // Also check that xcm transfer has been succeeded 325 expect((await helper.assets.account(USDT_ASSET_ID, alice.address))! == USDT_ASSET_AMOUNT).to.be.true;326 });327 });328329 itSub('Should connect and send Relay token to Unique', async ({helper}) => {330 balanceBobBefore = await helper.balance.getSubstrate(bob.address);331 balanceBobRelayTokenBefore = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});332333 await usingRelayPlaygrounds(relayUrl, async (helper) => {334 const destination = {335 V1: {336 parents: 0,337 interior: {X1: {338 Parachain: UNIQUE_CHAIN,339 },340 },341 }};342343 const beneficiary = {344 V1: {345 parents: 0,346 interior: {X1: {347 AccountId32: {348 network: 'Any',349 id: bob.addressRaw,350 },351 }},352 },353 };354355 const assets = {356 V1: [357 {358 id: {359 Concrete: {360 parents: 0,361 interior: 'Here',362 },363 },364 fun: {365 Fungible: TRANSFER_AMOUNT_RELAY,366 },367 },368 ],369 };370371 const feeAssetItem = 0;372373 await helper.xcm.limitedReserveTransferAssets(bob, destination, beneficiary, assets, feeAssetItem, {Unlimited: null});374 });375 376 await helper.wait.newBlocks(3);377378 balanceBobAfter = await helper.balance.getSubstrate(bob.address); 379 balanceBobRelayTokenAfter = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});380381 const wndFeeOnUnique = balanceBobRelayTokenAfter - TRANSFER_AMOUNT_RELAY - balanceBobRelayTokenBefore;382 const wndDiffOnUnique = balanceBobRelayTokenAfter - balanceBobRelayTokenBefore;383 console.log(384 '[Relay (Westend) -> Unique] transaction fees: %s UNQ',385 helper.util.bigIntToDecimals(balanceBobAfter - balanceBobBefore),386 );387 console.log(388 '[Relay (Westend) -> Unique] transaction fees: %s WND',389 helper.util.bigIntToDecimals(wndFeeOnUnique, STATEMINT_DECIMALS),390 );391 console.log('[Relay (Westend) -> Unique] actually delivered: %s WND', wndDiffOnUnique);392 expect(wndFeeOnUnique == 0n, 'No incoming WND fees should be taken').to.be.true;393 expect(balanceBobBefore == balanceBobAfter, 'No incoming UNQ fees should be taken').to.be.true;394 });395396 itSub('Should connect and send Relay token back', async ({helper}) => {397 let relayTokenBalanceBefore: bigint;398 let relayTokenBalanceAfter: bigint;399 await usingRelayPlaygrounds(relayUrl, async (helper) => {400 relayTokenBalanceBefore = await helper.balance.getSubstrate(bob.address);401 });402403 const destination = {404 V1: {405 parents: 1,406 interior: {407 X1:{408 AccountId32: {409 network: 'Any',410 id: bob.addressRaw,411 },412 },413 },414 },415 };416417 const currencies: any = [418 [419 {420 NativeAssetId: 'Parent',421 },422 TRANSFER_AMOUNT_RELAY,423 ],424 ];425426 const feeItem = 0;427428 await helper.xTokens.transferMulticurrencies(bob, currencies, feeItem, destination, {Unlimited: null});429430 balanceBobFinal = await helper.balance.getSubstrate(bob.address);431 console.log('[Unique -> Relay (Westend)] transaction fees: %s UNQ', helper.util.bigIntToDecimals(balanceBobAfter - balanceBobFinal));432433 await usingRelayPlaygrounds(relayUrl, async (helper) => {434 await helper.wait.newBlocks(10);435 relayTokenBalanceAfter = await helper.balance.getSubstrate(bob.address);436437 const diff = relayTokenBalanceAfter - relayTokenBalanceBefore;438 console.log('[Unique -> Relay (Westend)] actually delivered: %s WND', helper.util.bigIntToDecimals(diff, RELAY_DECIMALS));439 expect(diff > 0, 'Relay tokens was not delivered back').to.be.true;440 });441 });442});443444describeXCM('[XCM] Integration test: Exchanging tokens with Acala', () => {445 let alice: IKeyringPair;446 let randomAccount: IKeyringPair;447448 let balanceUniqueTokenInit: bigint;449 let balanceUniqueTokenMiddle: bigint;450 let balanceUniqueTokenFinal: bigint;451 let balanceAcalaTokenInit: bigint;452 let balanceAcalaTokenMiddle: bigint;453 let balanceAcalaTokenFinal: bigint;454 let balanceUniqueForeignTokenInit: bigint;455 let balanceUniqueForeignTokenMiddle: bigint;456 let balanceUniqueForeignTokenFinal: bigint;457458 before(async () => {459 await usingPlaygrounds(async (helper, privateKey) => {460 alice = await privateKey('//Alice');461 [randomAccount] = await helper.arrange.createAccounts([0n], alice);462 });463464 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {465 const destination = {466 V0: {467 X2: [468 'Parent',469 {470 Parachain: UNIQUE_CHAIN,471 },472 ],473 },474 };475476 const metadata = {477 name: 'UNQ',478 symbol: 'UNQ',479 decimals: 18,480 minimalBalance: 1n,481 };482483 await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);484 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);485 balanceAcalaTokenInit = await helper.balance.getSubstrate(randomAccount.address);486 balanceUniqueForeignTokenInit = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});487 });488489 await usingPlaygrounds(async (helper) => {490 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10n * TRANSFER_AMOUNT);491 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);492 });493 });494495 itSub('Should connect and send UNQ to Acala', async ({helper}) => {496497 const destination = {498 V0: {499 X2: [500 'Parent',501 {502 Parachain: ACALA_CHAIN,503 },504 ],505 },506 };507508 const beneficiary = {509 V0: {510 X1: {511 AccountId32: {512 network: 'Any',513 id: randomAccount.addressRaw,514 },515 },516 },517 };518519 const assets = {520 V1: [521 {522 id: {523 Concrete: {524 parents: 0,525 interior: 'Here',526 },527 },528 fun: {529 Fungible: TRANSFER_AMOUNT,530 },531 },532 ],533 };534535 const feeAssetItem = 0;536537 await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, {Unlimited: null});538 balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);539540 const unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;541 console.log('[Unique -> Acala] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));542 expect(unqFees > 0n, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;543544 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {545 await helper.wait.newBlocks(3);546547 balanceUniqueForeignTokenMiddle = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});548 balanceAcalaTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);549550 const acaFees = balanceAcalaTokenInit - balanceAcalaTokenMiddle;551 const unqIncomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenInit;552553 console.log(554 '[Unique -> Acala] transaction fees on Acala: %s ACA',555 helper.util.bigIntToDecimals(acaFees, ACALA_DECIMALS),556 );557 console.log('[Unique -> Acala] income %s UNQ', helper.util.bigIntToDecimals(unqIncomeTransfer));558 expect(acaFees == 0n).to.be.true;559 expect(unqIncomeTransfer == TRANSFER_AMOUNT).to.be.true;560 });561 });562563 itSub('Should connect to Acala and send UNQ back', async ({helper}) => {564 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {565 const destination = {566 V1: {567 parents: 1,568 interior: {569 X2: [570 {Parachain: UNIQUE_CHAIN},571 {572 AccountId32: {573 network: 'Any',574 id: randomAccount.addressRaw,575 },576 },577 ],578 },579 },580 };581582 const id = {583 ForeignAsset: 0,584 };585586 await helper.xTokens.transfer(randomAccount, id, TRANSFER_AMOUNT, destination, {Unlimited: null});587 balanceAcalaTokenFinal = await helper.balance.getSubstrate(randomAccount.address);588 balanceUniqueForeignTokenFinal = await helper.tokens.accounts(randomAccount.address, id);589590 const acaFees = balanceAcalaTokenMiddle - balanceAcalaTokenFinal;591 const unqOutcomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenFinal;592593 console.log(594 '[Acala -> Unique] transaction fees on Acala: %s ACA',595 helper.util.bigIntToDecimals(acaFees, ACALA_DECIMALS),596 );597 console.log('[Acala -> Unique] outcome %s UNQ', helper.util.bigIntToDecimals(unqOutcomeTransfer));598599 expect(acaFees > 0, 'Negative fees ACA, looks like nothing was transferred').to.be.true;600 expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;601 });602603 await helper.wait.newBlocks(3);604605 balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccount.address);606 const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;607 expect(actuallyDelivered > 0).to.be.true;608609 console.log('[Acala -> Unique] actually delivered %s UNQ', helper.util.bigIntToDecimals(actuallyDelivered));610611 const unqFees = TRANSFER_AMOUNT - actuallyDelivered;612 console.log('[Acala -> Unique] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));613 expect(unqFees == 0n).to.be.true;614 });615});616617// These tests are relevant only when the foreign asset pallet is disabled618describeXCM('[XCM] Integration test: Unique rejects non-native tokens', () => {619 let alice: IKeyringPair;620621 before(async () => {622 await usingPlaygrounds(async (_helper, privateKey) => {623 alice = await privateKey('//Alice');624 });625 });626627 itSub('Unique rejects ACA tokens from Acala', async ({helper}) => {628 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {629 const destination = {630 V1: {631 parents: 1,632 interior: {633 X2: [634 {Parachain: UNIQUE_CHAIN},635 {636 AccountId32: {637 network: 'Any',638 id: alice.addressRaw,639 },640 },641 ],642 },643 },644 };645646 const id = {647 Token: 'ACA',648 };649650 await helper.xTokens.transfer(alice, id, 100_000_000_000n, destination, {Unlimited: null});651 });652653 const maxWaitBlocks = 3;654655 const xcmpQueueFailEvent = await helper.wait.event(maxWaitBlocks, 'xcmpQueue', 'Fail');656657 expect(658 xcmpQueueFailEvent != null,659 '[Acala] xcmpQueue.FailEvent event is expected',660 ).to.be.true;661662 const event = xcmpQueueFailEvent!.event;663 const outcome = event.data[1] as XcmV2TraitsError;664665 expect(666 outcome.isFailedToTransactAsset,667 '[Acala] The XCM error should be `FailedToTransactAsset`',668 ).to.be.true;669 });670});671672describeXCM('[XCM] Integration test: Exchanging UNQ with Moonbeam', () => {673 // Unique constants674 let uniqueDonor: IKeyringPair;675 let uniqueAssetLocation;676677 let randomAccountUnique: IKeyringPair;678 let randomAccountMoonbeam: IKeyringPair;679680 // Moonbeam constants681 let assetId: string;682683 const councilVotingThreshold = 2;684 const technicalCommitteeThreshold = 2;685 const votingPeriod = 3;686 const delayPeriod = 0;687688 const uniqueAssetMetadata = {689 name: 'xcUnique',690 symbol: 'xcUNQ',691 decimals: 18,692 isFrozen: false,693 minimalBalance: 1n,694 };695696 let balanceUniqueTokenInit: bigint;697 let balanceUniqueTokenMiddle: bigint;698 let balanceUniqueTokenFinal: bigint;699 let balanceForeignUnqTokenInit: bigint;700 let balanceForeignUnqTokenMiddle: bigint;701 let balanceForeignUnqTokenFinal: bigint;702 let balanceGlmrTokenInit: bigint;703 let balanceGlmrTokenMiddle: bigint;704 let balanceGlmrTokenFinal: bigint;705706 before(async () => {707 await usingPlaygrounds(async (helper, privateKey) => {708 uniqueDonor = await privateKey('//Alice');709 [randomAccountUnique] = await helper.arrange.createAccounts([0n], uniqueDonor);710711 balanceForeignUnqTokenInit = 0n;712 });713714 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {715 const alithAccount = helper.account.alithAccount();716 const baltatharAccount = helper.account.baltatharAccount();717 const dorothyAccount = helper.account.dorothyAccount();718719 randomAccountMoonbeam = helper.account.create();720721 // >>> Sponsoring Dorothy >>>722 console.log('Sponsoring Dorothy.......');723 await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);724 console.log('Sponsoring Dorothy.......DONE');725 // <<< Sponsoring Dorothy <<<726727 uniqueAssetLocation = {728 XCM: {729 parents: 1,730 interior: {X1: {Parachain: UNIQUE_CHAIN}},731 },732 };733 const existentialDeposit = 1n;734 const isSufficient = true;735 const unitsPerSecond = 1n;736 const numAssetsWeightHint = 0;737738 const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({739 location: uniqueAssetLocation,740 metadata: uniqueAssetMetadata,741 existentialDeposit,742 isSufficient,743 unitsPerSecond,744 numAssetsWeightHint,745 });746 const proposalHash = blake2AsHex(encodedProposal);747748 console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);749 console.log('Encoded length %d', encodedProposal.length);750 console.log('Encoded proposal hash for batch utility after schedule is %s', proposalHash);751752 // >>> Note motion preimage >>>753 console.log('Note motion preimage.......');754 await helper.democracy.notePreimage(baltatharAccount, encodedProposal);755 console.log('Note motion preimage.......DONE');756 // <<< Note motion preimage <<<757758 // >>> Propose external motion through council >>>759 console.log('Propose external motion through council.......');760 const externalMotion = helper.democracy.externalProposeMajority(proposalHash);761 const encodedMotion = externalMotion?.method.toHex() || '';762 const motionHash = blake2AsHex(encodedMotion);763 console.log('Motion hash is %s', motionHash);764765 await helper.collective.council.propose(baltatharAccount, councilVotingThreshold, externalMotion, externalMotion.encodedLength);766767 const councilProposalIdx = await helper.collective.council.proposalCount() - 1;768 await helper.collective.council.vote(dorothyAccount, motionHash, councilProposalIdx, true);769 await helper.collective.council.vote(baltatharAccount, motionHash, councilProposalIdx, true);770771 await helper.collective.council.close(dorothyAccount, motionHash, councilProposalIdx, 1_000_000_000, externalMotion.encodedLength);772 console.log('Propose external motion through council.......DONE');773 // <<< Propose external motion through council <<<774775 // >>> Fast track proposal through technical committee >>>776 console.log('Fast track proposal through technical committee.......');777 const fastTrack = helper.democracy.fastTrack(proposalHash, votingPeriod, delayPeriod);778 const encodedFastTrack = fastTrack?.method.toHex() || '';779 const fastTrackHash = blake2AsHex(encodedFastTrack);780 console.log('FastTrack hash is %s', fastTrackHash);781782 await helper.collective.techCommittee.propose(alithAccount, technicalCommitteeThreshold, fastTrack, fastTrack.encodedLength);783784 const techProposalIdx = await helper.collective.techCommittee.proposalCount() - 1;785 await helper.collective.techCommittee.vote(baltatharAccount, fastTrackHash, techProposalIdx, true);786 await helper.collective.techCommittee.vote(alithAccount, fastTrackHash, techProposalIdx, true);787788 await helper.collective.techCommittee.close(baltatharAccount, fastTrackHash, techProposalIdx, 1_000_000_000, fastTrack.encodedLength);789 console.log('Fast track proposal through technical committee.......DONE');790 // <<< Fast track proposal through technical committee <<<791792 // >>> Referendum voting >>>793 console.log('Referendum voting.......');794 await helper.democracy.referendumVote(dorothyAccount, 0, {795 balance: 10_000_000_000_000_000_000n,796 vote: {aye: true, conviction: 1},797 });798 console.log('Referendum voting.......DONE');799 // <<< Referendum voting <<<800801 // >>> Acquire Unique AssetId Info on Moonbeam >>>802 console.log('Acquire Unique AssetId Info on Moonbeam.......');803804 // Wait for the democracy execute805 await helper.wait.newBlocks(5);806807 assetId = (await helper.assetManager.assetTypeId(uniqueAssetLocation)).toString();808809 console.log('UNQ asset ID is %s', assetId);810 console.log('Acquire Unique AssetId Info on Moonbeam.......DONE');811 // >>> Acquire Unique AssetId Info on Moonbeam >>>812813 // >>> Sponsoring random Account >>>814 console.log('Sponsoring random Account.......');815 await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonbeam.address, 11_000_000_000_000_000_000n);816 console.log('Sponsoring random Account.......DONE');817 // <<< Sponsoring random Account <<<818819 balanceGlmrTokenInit = await helper.balance.getEthereum(randomAccountMoonbeam.address);820 });821822 await usingPlaygrounds(async (helper) => {823 await helper.balance.transferToSubstrate(uniqueDonor, randomAccountUnique.address, 10n * TRANSFER_AMOUNT);824 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccountUnique.address);825 });826 });827828 itSub('Should connect and send UNQ to Moonbeam', async ({helper}) => {829 const currencyId = {830 NativeAssetId: 'Here',831 };832 const dest = {833 V1: {834 parents: 1,835 interior: {836 X2: [837 {Parachain: MOONBEAM_CHAIN},838 {AccountKey20: {network: 'Any', key: randomAccountMoonbeam.address}},839 ],840 },841 },842 };843 const amount = TRANSFER_AMOUNT;844845 await helper.xTokens.transfer(randomAccountUnique, currencyId, amount, dest, {Unlimited: null});846847 balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccountUnique.address);848 expect(balanceUniqueTokenMiddle < balanceUniqueTokenInit).to.be.true;849850 const transactionFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;851 console.log('[Unique -> Moonbeam] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(transactionFees));852 expect(transactionFees > 0, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;853854 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {855 await helper.wait.newBlocks(3);856857 balanceGlmrTokenMiddle = await helper.balance.getEthereum(randomAccountMoonbeam.address);858859 const glmrFees = balanceGlmrTokenInit - balanceGlmrTokenMiddle;860 console.log('[Unique -> Moonbeam] transaction fees on Moonbeam: %s GLMR', helper.util.bigIntToDecimals(glmrFees));861 expect(glmrFees == 0n).to.be.true;862863 balanceForeignUnqTokenMiddle = (await helper.assets.account(assetId, randomAccountMoonbeam.address))!;864865 const unqIncomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenInit;866 console.log('[Unique -> Moonbeam] income %s UNQ', helper.util.bigIntToDecimals(unqIncomeTransfer));867 expect(unqIncomeTransfer == TRANSFER_AMOUNT).to.be.true;868 });869 });870871 itSub('Should connect to Moonbeam and send UNQ back', async ({helper}) => {872 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {873 const asset = {874 V1: {875 id: {876 Concrete: {877 parents: 1,878 interior: {879 X1: {Parachain: UNIQUE_CHAIN},880 },881 },882 },883 fun: {884 Fungible: TRANSFER_AMOUNT,885 },886 },887 };888 const destination = {889 V1: {890 parents: 1,891 interior: {892 X2: [893 {Parachain: UNIQUE_CHAIN},894 {AccountId32: {network: 'Any', id: randomAccountUnique.addressRaw}},895 ],896 },897 },898 };899 const destWeight = 50000000;900901 await helper.xTokens.transferMultiasset(randomAccountMoonbeam, asset, destination, destWeight);902903 balanceGlmrTokenFinal = await helper.balance.getEthereum(randomAccountMoonbeam.address);904905 const glmrFees = balanceGlmrTokenMiddle - balanceGlmrTokenFinal;906 console.log('[Moonbeam -> Unique] transaction fees on Moonbeam: %s GLMR', helper.util.bigIntToDecimals(glmrFees));907 expect(glmrFees > 0, 'Negative fees GLMR, looks like nothing was transferred').to.be.true;908909 const unqRandomAccountAsset = await helper.assets.account(assetId, randomAccountMoonbeam.address);910911 expect(unqRandomAccountAsset).to.be.null;912 913 balanceForeignUnqTokenFinal = 0n;914915 const unqOutcomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenFinal;916 console.log('[Unique -> Moonbeam] outcome %s UNQ', helper.util.bigIntToDecimals(unqOutcomeTransfer));917 expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;918 });919920 await helper.wait.newBlocks(3);921922 balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccountUnique.address);923 const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;924 expect(actuallyDelivered > 0).to.be.true;925926 console.log('[Moonbeam -> Unique] actually delivered %s UNQ', helper.util.bigIntToDecimals(actuallyDelivered));927928 const unqFees = TRANSFER_AMOUNT - actuallyDelivered;929 console.log('[Moonbeam -> Unique] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));930 expect(unqFees == 0n).to.be.true;931 });932});