difftreelog
fix tx fees check in MB tests, run XCM tests only when env var set
in: master
3 files changed
tests/package.jsondiffbeforeafterboth--- a/tests/package.json
+++ b/tests/package.json
@@ -74,11 +74,11 @@
"testInflation": "mocha --timeout 9999999 -r ts-node/register ./**/inflation.test.ts",
"testScheduler": "mocha --timeout 9999999 -r ts-node/register ./**/scheduler.test.ts",
"testSchedulingEVM": "mocha --timeout 9999999 -r ts-node/register ./**/eth/scheduling.test.ts",
- "testXcmUnique": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmUnique.test.ts",
+ "testXcmUnique": "RUN_XCM_TESTS=1 mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmUnique.test.ts",
"testXcmOpal": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmOpal.test.ts",
"testXcmTransferAcala": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferAcala.test.ts acalaId=2000 uniqueId=5000",
"testXcmTransferStatemine": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferStatemine.test.ts statemineId=1000 uniqueId=5000",
- "testXcmTransferMoonbeam": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferMoonbeam.test.ts moonbeamId=2000 uniqueId=5000",
+ "testXcmTransferMoonbeam": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferMoonbeam.test.ts",
"testPalletPresence": "mocha --timeout 9999999 -r ts-node/register ./**/pallet-presence.test.ts",
"testBlockProduction": "mocha --timeout 9999999 -r ts-node/register ./**/block-production.test.ts",
"testEnableDisableTransfers": "mocha --timeout 9999999 -r ts-node/register ./**/enableDisableTransfer.test.ts",
tests/src/util/helpers.tsdiffbeforeafterboth--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -1746,6 +1746,12 @@
return (await api.rpc.unique.collectionById(collectionId)).unwrap();
}
+export const describe_xcm = (
+ process.env.RUN_XCM_TESTS
+ ? describe
+ : describe.skip
+);
+
export async function waitNewBlocks(blocksCount = 1): Promise<void> {
await usingApi(async (api) => {
const promise = new Promise<void>(async (resolve) => {
@@ -1762,6 +1768,35 @@
});
}
+export async function waitEvent(
+ api: ApiPromise,
+ maxBlocksToWait: number,
+ eventSection: string,
+ eventMethod: string,
+): Promise<EventRecord | null> {
+
+ const promise = new Promise<EventRecord | null>(async (resolve) => {
+ const unsubscribe = await api.query.system.events(eventRecords => {
+ const neededEvent = eventRecords.find(r => {
+ return r.event.section == eventSection && r.event.method == eventMethod;
+ });
+
+ if (neededEvent) {
+ unsubscribe();
+ resolve(neededEvent);
+ }
+
+ if (maxBlocksToWait > 0) {
+ maxBlocksToWait--;
+ } else {
+ unsubscribe();
+ resolve(null);
+ }
+ });
+ });
+ return promise;
+}
+
export async function repartitionRFT(
api: ApiPromise,
collectionId: number,
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 chai from 'chai';18import chaiAsPromised from 'chai-as-promised';1920import {WsProvider, Keyring} from '@polkadot/api';21import {ApiOptions} from '@polkadot/api/types';22import {IKeyringPair} from '@polkadot/types/types';23import usingApi, {submitTransactionAsync} from '../substrate/substrate-api';24import {getGenericResult, generateKeyringPair} from '../util/helpers';25import {MultiLocation} from '@polkadot/types/interfaces';26import {blake2AsHex} from '@polkadot/util-crypto';27import waitNewBlocks from '../substrate/wait-new-blocks';28import getBalance from '../substrate/get-balance';2930chai.use(chaiAsPromised);31const expect = chai.expect;3233const UNIQUE_CHAIN = 2037;34const ACALA_CHAIN = 2000;35const MOONBEAM_CHAIN = 2004;3637const ACALA_PORT = 9946;38const MOONBEAM_PORT = 9947;3940const TRANSFER_AMOUNT = 2000000000000000000000000n;4142function parachainApiOptions(port: number): ApiOptions {43 return {44 provider: new WsProvider('ws://127.0.0.1:' + port.toString()),45 };46}4748function acalaOptions(): ApiOptions {49 return parachainApiOptions(ACALA_PORT);50}5152function moonbeamOptions(): ApiOptions {53 return parachainApiOptions(MOONBEAM_PORT);54}5556describe('Integration test: Exchanging UNQ with Acala', () => {57 let alice: IKeyringPair;58 let randomAccount: IKeyringPair;59 60 let balanceUniqueTokenInit: bigint;61 let balanceUniqueTokenMiddle: bigint;62 let balanceUniqueTokenFinal: bigint;63 let balanceAcalaTokenInit: bigint;64 let balanceAcalaTokenMiddle: bigint;65 let balanceAcalaTokenFinal: bigint;66 let balanceUniqueForeignTokenInit: bigint;67 let balanceUniqueForeignTokenMiddle: bigint;68 let balanceUniqueForeignTokenFinal: bigint;69 70 before(async () => {71 await usingApi(async (api, privateKeyWrapper) => {72 alice = privateKeyWrapper('//Alice');73 randomAccount = generateKeyringPair();74 });7576 // Acala side77 await usingApi(78 async (api) => {79 const destination = {80 V0: {81 X2: [82 'Parent',83 {84 Parachain: UNIQUE_CHAIN,85 },86 ],87 },88 };89 90 const metadata = {91 name: 'UNQ',92 symbol: 'UNQ',93 decimals: 18,94 minimalBalance: 1,95 };96 97 const tx = api.tx.assetRegistry.registerForeignAsset(destination, metadata);98 const sudoTx = api.tx.sudo.sudo(tx as any);99 const events = await submitTransactionAsync(alice, sudoTx);100 const result = getGenericResult(events);101 expect(result.success).to.be.true;102 103 const tx1 = api.tx.balances.transfer(randomAccount.address, 10000000000000n);104 const events1 = await submitTransactionAsync(alice, tx1);105 const result1 = getGenericResult(events1);106 expect(result1.success).to.be.true;107 108 [balanceAcalaTokenInit] = await getBalance(api, [randomAccount.address]);109 {110 const {free} = (await api.query.tokens.accounts(randomAccount.addressRaw, {ForeignAsset: 0})).toJSON() as any;111 balanceUniqueForeignTokenInit = BigInt(free);112 }113 },114 acalaOptions(),115 );116 117 // Unique side118 await usingApi(async (api) => {119 const tx0 = api.tx.balances.transfer(randomAccount.address, 10n * TRANSFER_AMOUNT);120 const events0 = await submitTransactionAsync(alice, tx0);121 const result0 = getGenericResult(events0);122 expect(result0.success).to.be.true;123 124 [balanceUniqueTokenInit] = await getBalance(api, [randomAccount.address]);125 });126 });127 128 it('Should connect and send UNQ to Acala', async () => {129 130 // Unique side131 await usingApi(async (api) => {132 133 const destination = {134 V0: {135 X2: [136 'Parent',137 {138 Parachain: ACALA_CHAIN,139 },140 ],141 },142 };143 144 const beneficiary = {145 V0: {146 X1: {147 AccountId32: {148 network: 'Any',149 id: randomAccount.addressRaw,150 },151 },152 },153 };154 155 const assets = {156 V1: [157 {158 id: {159 Concrete: {160 parents: 0,161 interior: 'Here',162 },163 },164 fun: {165 Fungible: TRANSFER_AMOUNT,166 },167 },168 ],169 };170 171 const feeAssetItem = 0;172 173 const weightLimit = {174 Limited: 5000000000,175 };176 177 const tx = api.tx.polkadotXcm.limitedReserveTransferAssets(destination, beneficiary, assets, feeAssetItem, weightLimit);178 const events = await submitTransactionAsync(randomAccount, tx);179 const result = getGenericResult(events);180 expect(result.success).to.be.true;181 182 [balanceUniqueTokenMiddle] = await getBalance(api, [randomAccount.address]);183 184 const unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle + TRANSFER_AMOUNT;185 console.log('[Unique -> Acala] transaction fees on Unique: %s UNQ', unqFees);186 expect(unqFees > 0n).to.be.true;187 });188 189 // Acala side190 await usingApi(191 async (api) => {192 await waitNewBlocks(api, 3);193 const {free} = (await api.query.tokens.accounts(randomAccount.addressRaw, {ForeignAsset: 0})).toJSON() as any;194 balanceUniqueForeignTokenMiddle = BigInt(free);195 196 [balanceAcalaTokenMiddle] = await getBalance(api, [randomAccount.address]);197198 const acaFees = balanceAcalaTokenInit - balanceAcalaTokenMiddle;199 const unqIncomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenInit;200201 console.log('[Unique -> Acala] transaction fees on Acala: %s ACA', acaFees);202 console.log('[Unique -> Acala] income %s UNQ', unqIncomeTransfer);203 expect(acaFees == 0n).to.be.true;204 expect(unqIncomeTransfer == TRANSFER_AMOUNT).to.be.true;205 },206 acalaOptions(),207 );208 });209 210 it('Should connect to Acala and send UNQ back', async () => {211 212 // Acala side213 await usingApi(214 async (api) => {215 const destination = {216 V1: {217 parents: 1,218 interior: {219 X2: [220 {Parachain: UNIQUE_CHAIN},221 {222 AccountId32: {223 network: 'Any',224 id: randomAccount.addressRaw,225 },226 },227 ],228 },229 },230 };231 232 const id = {233 ForeignAsset: 0,234 };235236 const destWeight = 50000000;237 238 const tx = api.tx.xTokens.transfer(id, TRANSFER_AMOUNT, destination, destWeight);239 const events = await submitTransactionAsync(randomAccount, tx);240 const result = getGenericResult(events);241 expect(result.success).to.be.true;242 243 [balanceAcalaTokenFinal] = await getBalance(api, [randomAccount.address]);244 {245 const {free} = (await api.query.tokens.accounts(randomAccount.addressRaw, {ForeignAsset: 0})).toJSON() as any;246 balanceUniqueForeignTokenFinal = BigInt(free);247 }248 249 const acaFees = balanceAcalaTokenMiddle - balanceAcalaTokenFinal;250 const unqOutcomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenFinal;251252 console.log('[Acala -> Unique] transaction fees on Acala: %s ACA', acaFees);253 console.log('[Acala -> Unique] outcome %s UNQ', unqOutcomeTransfer);254255 expect(acaFees > 0).to.be.true;256 expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;257 },258 acalaOptions(),259 );260261 // Unique side262 await usingApi(async (api) => {263 await waitNewBlocks(api, 3);264 265 [balanceUniqueTokenFinal] = await getBalance(api, [randomAccount.address]);266 const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;267 expect(actuallyDelivered > 0).to.be.true;268269 console.log('[Acala -> Unique] actually delivered %s UNQ', actuallyDelivered);270 271 const unqFees = TRANSFER_AMOUNT - actuallyDelivered;272 console.log('[Acala -> Unique] transaction fees on Unique: %s UNQ', unqFees);273 expect(unqFees == 0n).to.be.true;274 });275 });276});277278describe('Integration test: Exchanging UNQ with Moonbeam', () => {279280 // Unique constants281 let uniqueAlice: IKeyringPair;282 let uniqueAssetLocation;283284 let randomAccountUnique: IKeyringPair;285 let randomAccountMoonbeam: IKeyringPair;286287 // Moonbeam constants288 let assetId: string;289290 const moonbeamKeyring = new Keyring({type: 'ethereum'});291 const alithPrivateKey = '0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133';292 const baltatharPrivateKey = '0x8075991ce870b93a8870eca0c0f91913d12f47948ca0fd25b49c6fa7cdbeee8b';293 const dorothyPrivateKey = '0x39539ab1876910bbf3a223d84a29e28f1cb4e2e456503e7e91ed39b2e7223d68';294295 const alithAccount = moonbeamKeyring.addFromUri(alithPrivateKey, undefined, 'ethereum');296 const baltatharAccount = moonbeamKeyring.addFromUri(baltatharPrivateKey, undefined, 'ethereum');297 const dorothyAccount = moonbeamKeyring.addFromUri(dorothyPrivateKey, undefined, 'ethereum');298299 const councilVotingThreshold = 2;300 const technicalCommitteeThreshold = 2;301 const votingPeriod = 3;302 const delayPeriod = 0;303304 const uniqueAssetMetadata = {305 name: 'xcUnique',306 symbol: 'xcUNQ',307 decimals: 18,308 isFrozen: false,309 minimalBalance: 1,310 };311312 let balanceUniqueTokenInit: bigint;313 let balanceUniqueTokenMiddle: bigint;314 let balanceUniqueTokenFinal: bigint;315 let balanceForeignUnqTokenInit: bigint;316 let balanceForeignUnqTokenMiddle: bigint;317 let balanceForeignUnqTokenFinal: bigint;318 let balanceGlmrTokenInit: bigint;319 let balanceGlmrTokenMiddle: bigint;320 let balanceGlmrTokenFinal: bigint;321322 before(async () => {323 await usingApi(async (api, privateKeyWrapper) => {324 uniqueAlice = privateKeyWrapper('//Alice');325 randomAccountUnique = generateKeyringPair();326 randomAccountMoonbeam = generateKeyringPair('ethereum');327328 balanceForeignUnqTokenInit = 0n;329 });330331 await usingApi(332 async (api) => {333334 // >>> Sponsoring Dorothy >>>335 console.log('Sponsoring Dorothy.......');336 const tx0 = api.tx.balances.transfer(dorothyAccount.address, 11_000_000_000_000_000_000n);337 const events0 = await submitTransactionAsync(alithAccount, tx0);338 const result0 = getGenericResult(events0);339 expect(result0.success).to.be.true;340 console.log('Sponsoring Dorothy.......DONE');341 // <<< Sponsoring Dorothy <<<342343 const sourceLocation: MultiLocation = api.createType(344 'MultiLocation',345 {346 parents: 1,347 interior: {X1: {Parachain: UNIQUE_CHAIN}},348 },349 );350351 uniqueAssetLocation = {XCM: sourceLocation};352 const existentialDeposit = 1;353 const isSufficient = true;354 const unitsPerSecond = '1';355 const numAssetsWeightHint = 0;356357 const registerTx = api.tx.assetManager.registerForeignAsset(358 uniqueAssetLocation,359 uniqueAssetMetadata,360 existentialDeposit,361 isSufficient,362 );363 console.log('Encoded proposal for registerAsset is %s', registerTx.method.toHex() || '');364365 const setUnitsTx = api.tx.assetManager.setAssetUnitsPerSecond(366 uniqueAssetLocation,367 unitsPerSecond,368 numAssetsWeightHint,369 );370 console.log('Encoded proposal for setAssetUnitsPerSecond is %s', setUnitsTx.method.toHex() || '');371372 const batchCall = api.tx.utility.batchAll([registerTx, setUnitsTx]);373 console.log('Encoded proposal for batchCall is %s', batchCall.method.toHex() || '');374375 // >>> Note motion preimage >>>376 console.log('Note motion preimage.......');377 const encodedProposal = batchCall?.method.toHex() || '';378 const proposalHash = blake2AsHex(encodedProposal);379 console.log('Encoded proposal for batch utility after schedule is %s', encodedProposal);380 console.log('Encoded proposal hash for batch utility after schedule is %s', proposalHash);381 console.log('Encoded length %d', encodedProposal.length);382383 const tx1 = api.tx.democracy.notePreimage(encodedProposal);384 const events1 = await submitTransactionAsync(baltatharAccount, tx1);385 const result1 = getGenericResult(events1);386 expect(result1.success).to.be.true;387 console.log('Note motion preimage.......DONE');388 // <<< Note motion preimage <<<389390 // >>> Propose external motion through council >>>391 console.log('Propose external motion through council.......');392 const externalMotion = api.tx.democracy.externalProposeMajority(proposalHash);393 const tx2 = api.tx.councilCollective.propose(394 councilVotingThreshold,395 externalMotion,396 externalMotion.encodedLength,397 );398 const events2 = await submitTransactionAsync(baltatharAccount, tx2);399 const result2 = getGenericResult(events2);400 expect(result2.success).to.be.true;401402 const encodedMotion = externalMotion?.method.toHex() || '';403 const motionHash = blake2AsHex(encodedMotion);404 console.log('Motion hash is %s', motionHash);405406 const tx3 = api.tx.councilCollective.vote(motionHash, 0, true);407 {408 const events3 = await submitTransactionAsync(dorothyAccount, tx3);409 const result3 = getGenericResult(events3);410 expect(result3.success).to.be.true;411 }412 {413 const events3 = await submitTransactionAsync(baltatharAccount, tx3);414 const result3 = getGenericResult(events3);415 expect(result3.success).to.be.true;416 }417418 const tx4 = api.tx.councilCollective.close(motionHash, 0, 1_000_000_000, externalMotion.encodedLength);419 const events4 = await submitTransactionAsync(dorothyAccount, tx4);420 const result4 = getGenericResult(events4);421 expect(result4.success).to.be.true;422 console.log('Propose external motion through council.......DONE');423 // <<< Propose external motion through council <<<424425 // >>> Fast track proposal through technical committee >>>426 console.log('Fast track proposal through technical committee.......');427 const fastTrack = api.tx.democracy.fastTrack(proposalHash, votingPeriod, delayPeriod);428 const tx5 = api.tx.techCommitteeCollective.propose(429 technicalCommitteeThreshold,430 fastTrack,431 fastTrack.encodedLength,432 );433 const events5 = await submitTransactionAsync(alithAccount, tx5);434 const result5 = getGenericResult(events5);435 expect(result5.success).to.be.true;436437 const encodedFastTrack = fastTrack?.method.toHex() || '';438 const fastTrackHash = blake2AsHex(encodedFastTrack);439 console.log('FastTrack hash is %s', fastTrackHash);440441 const proposalIdx = Number(await api.query.techCommitteeCollective.proposalCount()) - 1;442 const tx6 = api.tx.techCommitteeCollective.vote(fastTrackHash, proposalIdx, true);443 {444 const events6 = await submitTransactionAsync(baltatharAccount, tx6);445 const result6 = getGenericResult(events6);446 expect(result6.success).to.be.true;447 }448 {449 const events6 = await submitTransactionAsync(alithAccount, tx6);450 const result6 = getGenericResult(events6);451 expect(result6.success).to.be.true;452 }453454 const tx7 = api.tx.techCommitteeCollective455 .close(fastTrackHash, proposalIdx, 1_000_000_000, fastTrack.encodedLength);456 const events7 = await submitTransactionAsync(baltatharAccount, tx7);457 const result7 = getGenericResult(events7);458 expect(result7.success).to.be.true;459 console.log('Fast track proposal through technical committee.......DONE');460 // <<< Fast track proposal through technical committee <<<461462 // >>> Referendum voting >>>463 console.log('Referendum voting.......');464 const tx8 = api.tx.democracy.vote(465 0,466 {Standard: {balance: 10_000_000_000_000_000_000n, vote: {aye: true, conviction: 1}}},467 );468 const events8 = await submitTransactionAsync(dorothyAccount, tx8);469 const result8 = getGenericResult(events8);470 expect(result8.success).to.be.true;471 console.log('Referendum voting.......DONE');472 // <<< Referendum voting <<<473474 // >>> Acquire Unique AssetId Info on Moonbeam >>>475 console.log('Acquire Unique AssetId Info on Moonbeam.......');476477 // Wait for the democracy execute478 await waitNewBlocks(api, 5);479480 assetId = (await api.query.assetManager.assetTypeId({481 XCM: sourceLocation,482 })).toString();483484 console.log('UNQ asset ID is %s', assetId);485 console.log('Acquire Unique AssetId Info on Moonbeam.......DONE');486 // >>> Acquire Unique AssetId Info on Moonbeam >>>487488 // >>> Sponsoring random Account >>>489 console.log('Sponsoring random Account.......');490 const tx10 = api.tx.balances.transfer(randomAccountMoonbeam.address, 11_000_000_000_000_000_000n);491 const events10 = await submitTransactionAsync(baltatharAccount, tx10);492 const result10 = getGenericResult(events10);493 expect(result10.success).to.be.true;494 console.log('Sponsoring random Account.......DONE');495 // <<< Sponsoring random Account <<<496497 [balanceGlmrTokenInit] = await getBalance(api, [randomAccountMoonbeam.address]);498 },499 moonbeamOptions(),500 );501502 await usingApi(async (api) => {503 const tx0 = api.tx.balances.transfer(randomAccountUnique.address, 10n * TRANSFER_AMOUNT);504 const events0 = await submitTransactionAsync(uniqueAlice, tx0);505 const result0 = getGenericResult(events0);506 expect(result0.success).to.be.true;507508 [balanceUniqueTokenInit] = await getBalance(api, [randomAccountUnique.address]);509 });510 });511512 it('Should connect and send UNQ to Moonbeam', async () => {513 await usingApi(async (api) => {514 const currencyId = {515 NativeAssetId: 'Here',516 };517 const dest = {518 V1: {519 parents: 1,520 interior: {521 X2: [522 {Parachain: MOONBEAM_CHAIN},523 {AccountKey20: {network: 'Any', key: randomAccountMoonbeam.address}},524 ],525 },526 },527 };528 const amount = TRANSFER_AMOUNT;529 const destWeight = 850000000;530531 const tx = api.tx.xTokens.transfer(currencyId, amount, dest, destWeight);532 const events = await submitTransactionAsync(randomAccountUnique, tx);533 const result = getGenericResult(events);534 expect(result.success).to.be.true;535536 [balanceUniqueTokenMiddle] = await getBalance(api, [randomAccountUnique.address]);537 expect(balanceUniqueTokenMiddle < balanceUniqueTokenInit).to.be.true;538539 const transactionFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle + TRANSFER_AMOUNT;540 console.log('[Unique -> Moonbeam] transaction fees on Unique: %s UNQ', transactionFees);541 expect(transactionFees > 0).to.be.true;542 });543544 await usingApi(545 async (api) => {546 await waitNewBlocks(api, 3);547548 [balanceGlmrTokenMiddle] = await getBalance(api, [randomAccountMoonbeam.address]);549550 const glmrFees = balanceGlmrTokenInit - balanceGlmrTokenMiddle;551 console.log('[Unique -> Moonbeam] transaction fees on Moonbeam: %s GLMR', glmrFees);552 expect(glmrFees == 0n).to.be.true;553554 const unqRandomAccountAsset = (555 await api.query.assets.account(assetId, randomAccountMoonbeam.address)556 ).toJSON()! as any;557558 balanceForeignUnqTokenMiddle = BigInt(unqRandomAccountAsset['balance']);559 const unqIncomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenInit;560 console.log('[Unique -> Moonbeam] income %s UNQ', unqIncomeTransfer);561 expect(unqIncomeTransfer == TRANSFER_AMOUNT).to.be.true;562 },563 moonbeamOptions(),564 );565 });566567 it('Should connect to Moonbeam and send UNQ back', async () => {568 await usingApi(569 async (api) => {570 const asset = {571 V1: {572 id: {573 Concrete: {574 parents: 1,575 interior: {576 X1: {Parachain: UNIQUE_CHAIN},577 },578 },579 },580 fun: {581 Fungible: TRANSFER_AMOUNT,582 },583 },584 };585 const destination = {586 V1: {587 parents: 1,588 interior: {589 X2: [590 {Parachain: UNIQUE_CHAIN},591 {AccountId32: {network: 'Any', id: randomAccountUnique.addressRaw}},592 ],593 },594 },595 };596 const destWeight = 50000000;597598 const tx = api.tx.xTokens.transferMultiasset(asset, destination, destWeight);599 const events = await submitTransactionAsync(randomAccountMoonbeam, tx);600 const result = getGenericResult(events);601 expect(result.success).to.be.true;602603 [balanceGlmrTokenFinal] = await getBalance(api, [randomAccountMoonbeam.address]);604605 const glmrFees = balanceGlmrTokenMiddle - balanceGlmrTokenFinal;606 console.log('[Moonbeam -> Unique] transaction fees on Moonbeam: %s GLMR', glmrFees);607 expect(glmrFees > 0).to.be.true;608609 const unqRandomAccountAsset = (610 await api.query.assets.account(assetId, randomAccountMoonbeam.address)611 ).toJSON()! as any;612613 expect(unqRandomAccountAsset).to.be.null;614615 balanceForeignUnqTokenFinal = 0n;616617 const unqOutcomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenFinal;618 console.log('[Unique -> Moonbeam] outcome %s UNQ', unqOutcomeTransfer);619 expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;620 },621 moonbeamOptions(),622 );623624 await usingApi(async (api) => {625 await waitNewBlocks(api, 3);626627 [balanceUniqueTokenFinal] = await getBalance(api, [randomAccountUnique.address]);628 const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;629 expect(actuallyDelivered > 0).to.be.true;630631 console.log('[Moonbeam -> Unique] actually delivered %s UNQ', actuallyDelivered);632633 const unqFees = TRANSFER_AMOUNT - actuallyDelivered;634 console.log('[Moonbeam -> Unique] transaction fees on Unique: %s UNQ', unqFees);635 expect(unqFees == 0n).to.be.true;636 });637 });638});