git.delta.rocks / unique-network / refs/commits / 7b07931fc69a

difftreelog

test(xcm) unique <-> moonbeam

Daniel Shiposha2022-09-02parent: #2286f73.patch.diff
in: master

1 file changed

modifiedtests/src/xcm/xcmUnique.test.tsdiffbeforeafterboth
17import chai from 'chai';17import chai from 'chai';
18import chaiAsPromised from 'chai-as-promised';18import chaiAsPromised from 'chai-as-promised';
1919
20import {WsProvider} from '@polkadot/api';20import {WsProvider, Keyring} from '@polkadot/api';
21import {ApiOptions} from '@polkadot/api/types';21import {ApiOptions} from '@polkadot/api/types';
22import {IKeyringPair} from '@polkadot/types/types';22import {IKeyringPair} from '@polkadot/types/types';
23import usingApi, {submitTransactionAsync} from '../substrate/substrate-api';23import usingApi, {submitTransactionAsync} from '../substrate/substrate-api';
24import {getGenericResult, generateKeyringPair} from '../util/helpers';24import {getGenericResult, generateKeyringPair} from '../util/helpers';
25import {MultiLocation} from '@polkadot/types/interfaces';
26import {blake2AsHex} from '@polkadot/util-crypto';
25import waitNewBlocks from '../substrate/wait-new-blocks';27import waitNewBlocks from '../substrate/wait-new-blocks';
26import getBalance from '../substrate/get-balance';28import getBalance from '../substrate/get-balance';
2729
3032
31const UNIQUE_CHAIN = 2037;33const UNIQUE_CHAIN = 2037;
32const ACALA_CHAIN = 2000;34const ACALA_CHAIN = 2000;
35const MOONBEAM_CHAIN = 2004;
3336
34const ACALA_PORT = '9946';37const ACALA_PORT = 9946;
38const MOONBEAM_PORT = 9947;
3539
36const TRANSFER_AMOUNT = 2000000000000000000000000n;40const TRANSFER_AMOUNT = 2000000000000000000000000n;
3741
42function parachainApiOptions(port: number): ApiOptions {
43 return {
44 provider: new WsProvider('ws://127.0.0.1:' + port.toString()),
45 };
46}
47
48function acalaOptions(): ApiOptions {
49 return parachainApiOptions(ACALA_PORT);
50}
51
52function moonbeamOptions(): ApiOptions {
53 return parachainApiOptions(MOONBEAM_PORT);
54}
55
38describe('Integration test: Exchanging UNQ with Acala', () => {56describe('Integration test: Exchanging UNQ with Acala', () => {
39 let alice: IKeyringPair;57 let alice: IKeyringPair;
40 let randomAccount: IKeyringPair;58 let randomAccount: IKeyringPair;
41 59
42 let balanceUniqueTokenBefore: bigint;60 let balanceUniqueTokenInit: bigint;
43 let balanceUniqueTokenAfter: bigint;61 let balanceUniqueTokenMiddle: bigint;
44 let balanceUniqueTokenFinal: bigint;62 let balanceUniqueTokenFinal: bigint;
45 let balanceAcalaTokenBefore: bigint;63 let balanceAcalaTokenInit: bigint;
46 let balanceAcalaTokenAfter: bigint;64 let balanceAcalaTokenMiddle: bigint;
47 let balanceAcalaTokenFinal: bigint;65 let balanceAcalaTokenFinal: bigint;
48 let balanceUniqueForeignTokenAfter: bigint;66 let balanceUniqueForeignTokenInit: bigint;
49 let balanceUniqueForeignTokenBefore: bigint;67 let balanceUniqueForeignTokenMiddle: bigint;
50 let balanceUniqueForeignTokenFinal: bigint;68 let balanceUniqueForeignTokenFinal: bigint;
51 69
52 before(async () => {70 before(async () => {
53 await usingApi(async (api, privateKeyWrapper) => {71 await usingApi(async (api, privateKeyWrapper) => {
54 alice = privateKeyWrapper('//Alice');72 alice = privateKeyWrapper('//Alice');
55 randomAccount = generateKeyringPair();73 randomAccount = generateKeyringPair();
56 });74 });
57 75
58 const acalaApiOptions: ApiOptions = {
59 provider: new WsProvider('ws://127.0.0.1:' + ACALA_PORT),
60 };
61
62 // Acala side76 // Acala side
63 await usingApi(77 await usingApi(
64 async (api) => {78 async (api) => {
91 const result1 = getGenericResult(events1);105 const result1 = getGenericResult(events1);
92 expect(result1.success).to.be.true;106 expect(result1.success).to.be.true;
93 107
94 [balanceAcalaTokenBefore] = await getBalance(api, [randomAccount.address]);108 [balanceAcalaTokenInit] = await getBalance(api, [randomAccount.address]);
95 {109 {
96 const {free} = (await api.query.tokens.accounts(randomAccount.addressRaw, {ForeignAsset: 0})).toJSON() as any;110 const {free} = (await api.query.tokens.accounts(randomAccount.addressRaw, {ForeignAsset: 0})).toJSON() as any;
97 balanceUniqueForeignTokenBefore = BigInt(free);111 balanceUniqueForeignTokenInit = BigInt(free);
98 }112 }
99 },113 },
100 acalaApiOptions,114 acalaOptions(),
101 );115 );
102 116
103 // Unique side117 // Unique side
107 const result0 = getGenericResult(events0);121 const result0 = getGenericResult(events0);
108 expect(result0.success).to.be.true;122 expect(result0.success).to.be.true;
109 123
110 [balanceUniqueTokenBefore] = await getBalance(api, [randomAccount.address]);124 [balanceUniqueTokenInit] = await getBalance(api, [randomAccount.address]);
111 });125 });
112 });126 });
113 127
165 const result = getGenericResult(events);179 const result = getGenericResult(events);
166 expect(result.success).to.be.true;180 expect(result.success).to.be.true;
167 181
168 [balanceUniqueTokenAfter] = await getBalance(api, [randomAccount.address]);182 [balanceUniqueTokenMiddle] = await getBalance(api, [randomAccount.address]);
169 183
170 const unqFees = balanceUniqueTokenBefore - balanceUniqueTokenAfter;184 const unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle + TRANSFER_AMOUNT;
171 console.log('[Unique -> Acala] transaction fees on Unique: %s UNQ', unqFees);185 console.log('[Unique -> Acala] transaction fees on Unique: %s UNQ', unqFees);
172 expect(unqFees > 0n).to.be.true;186 expect(unqFees > 0n).to.be.true;
173 });187 });
174 188
175 // Acala side189 // Acala side
176 await usingApi(190 await usingApi(
177 async (api) => {191 async (api) => {
178 // todo do something about instant sealing, where there might not be any new blocks
179 await waitNewBlocks(api, 3);192 await waitNewBlocks(api, 3);
180 const {free} = (await api.query.tokens.accounts(randomAccount.addressRaw, {ForeignAsset: 0})).toJSON() as any;193 const {free} = (await api.query.tokens.accounts(randomAccount.addressRaw, {ForeignAsset: 0})).toJSON() as any;
181 balanceUniqueForeignTokenAfter = BigInt(free);194 balanceUniqueForeignTokenMiddle = BigInt(free);
182 195
183 [balanceAcalaTokenAfter] = await getBalance(api, [randomAccount.address]);196 [balanceAcalaTokenMiddle] = await getBalance(api, [randomAccount.address]);
184197
185 const acaFees = balanceAcalaTokenBefore - balanceAcalaTokenAfter;198 const acaFees = balanceAcalaTokenInit - balanceAcalaTokenMiddle;
186 const unqDiffAfterIncomeTransfer = balanceUniqueForeignTokenAfter - balanceUniqueForeignTokenBefore;199 const unqIncomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenInit;
187200
188 const unqFees = unqDiffAfterIncomeTransfer - TRANSFER_AMOUNT;
189
190 console.log('[Unique -> Acala] transaction fees on Acala: %s ACA', acaFees);201 console.log('[Unique -> Acala] transaction fees on Acala: %s ACA', acaFees);
191 console.log('[Unique -> Acala] transaction fees on Acala: %s UNQ', unqFees);202 console.log('[Unique -> Acala] income %s UNQ', unqIncomeTransfer);
192 expect(acaFees == 0n).to.be.true;203 expect(acaFees == 0n).to.be.true;
193 expect(unqFees == 0n).to.be.true;204 expect(unqIncomeTransfer == TRANSFER_AMOUNT).to.be.true;
194 },205 },
195 {provider: new WsProvider('ws://127.0.0.1:' + ACALA_PORT)},206 acalaOptions(),
196 );207 );
197 });208 });
198 209
221 const id = {232 const id = {
222 ForeignAsset: 0,233 ForeignAsset: 0,
223 };234 };
224 235
225 const amount = TRANSFER_AMOUNT;
226 const destWeight = 50000000;236 const destWeight = 50000000;
227 237
228 const tx = api.tx.xTokens.transfer(id, amount, destination, destWeight);238 const tx = api.tx.xTokens.transfer(id, TRANSFER_AMOUNT, destination, destWeight);
229 const events = await submitTransactionAsync(randomAccount, tx);239 const events = await submitTransactionAsync(randomAccount, tx);
230 const result = getGenericResult(events);240 const result = getGenericResult(events);
231 expect(result.success).to.be.true;241 expect(result.success).to.be.true;
236 balanceUniqueForeignTokenFinal = BigInt(free);246 balanceUniqueForeignTokenFinal = BigInt(free);
237 }247 }
238 248
239 const acaFees = balanceAcalaTokenAfter - balanceAcalaTokenFinal;249 const acaFees = balanceAcalaTokenMiddle - balanceAcalaTokenFinal;
240 const unqDiffAfterOutcomeTransfer = balanceUniqueForeignTokenAfter - TRANSFER_AMOUNT;250 const unqOutcomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenFinal;
241251
242 const unqFees = unqDiffAfterOutcomeTransfer - balanceUniqueForeignTokenFinal;
243
244 console.log('[Acala -> Unique] transaction fees on Acala: %s ACA', acaFees);252 console.log('[Acala -> Unique] transaction fees on Acala: %s ACA', acaFees);
245 console.log('[Acala -> Unique] transaction fees on Acala: %s UNQ', unqFees);253 console.log('[Acala -> Unique] outcome %s UNQ', unqOutcomeTransfer);
246254
247 expect(acaFees > 0).to.be.true;255 expect(acaFees > 0).to.be.true;
248 expect(unqFees == 0n).to.be.true;256 expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;
249 },257 },
250 {provider: new WsProvider('ws://127.0.0.1:' + ACALA_PORT)},258 acalaOptions(),
251 );259 );
252260
253 // Unique side261 // Unique side
254 await usingApi(async (api) => {262 await usingApi(async (api) => {
255 // todo do something about instant sealing, where there might not be any new blocks
256 await waitNewBlocks(api, 3);263 await waitNewBlocks(api, 3);
257 264
258 [balanceUniqueTokenFinal] = await getBalance(api, [randomAccount.address]);265 [balanceUniqueTokenFinal] = await getBalance(api, [randomAccount.address]);
259 const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenAfter;266 const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;
260 expect(actuallyDelivered > 0).to.be.true;267 expect(actuallyDelivered > 0).to.be.true;
268
269 console.log('[Acala -> Unique] actually delivered %s UNQ', actuallyDelivered);
261 270
262 const unqFees = TRANSFER_AMOUNT - actuallyDelivered;271 const unqFees = TRANSFER_AMOUNT - actuallyDelivered;
263 console.log('[Acala -> Unique] transaction fees on Unique: %s UNQ', unqFees);272 console.log('[Acala -> Unique] transaction fees on Unique: %s UNQ', unqFees);
273 expect(unqFees == 0n).to.be.true;
274 });
275 });
276});
277
278describe('Integration test: Exchanging UNQ with Moonbeam', () => {
279
280 // Unique constants
281 let uniqueAlice: IKeyringPair;
282 let uniqueAssetLocation;
283
284 let randomAccountUnique: IKeyringPair;
285 let randomAccountMoonbeam: IKeyringPair;
286
287 // Moonbeam constants
288 let assetId: string;
289
290 const moonbeamKeyring = new Keyring({type: 'ethereum'});
291 const alithPrivateKey = '0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133';
292 const baltatharPrivateKey = '0x8075991ce870b93a8870eca0c0f91913d12f47948ca0fd25b49c6fa7cdbeee8b';
293 const dorothyPrivateKey = '0x39539ab1876910bbf3a223d84a29e28f1cb4e2e456503e7e91ed39b2e7223d68';
294
295 const alithAccount = moonbeamKeyring.addFromUri(alithPrivateKey, undefined, 'ethereum');
296 const baltatharAccount = moonbeamKeyring.addFromUri(baltatharPrivateKey, undefined, 'ethereum');
297 const dorothyAccount = moonbeamKeyring.addFromUri(dorothyPrivateKey, undefined, 'ethereum');
298
299 const councilVotingThreshold = 2;
300 const technicalCommitteeThreshold = 2;
301 const votingPeriod = 3;
302 const delayPeriod = 0;
303
304 const uniqueAssetMetadata = {
305 name: 'xcUnique',
306 symbol: 'xcUNQ',
307 decimals: 18,
308 isFrozen: false,
309 minimalBalance: 1,
310 };
311
312 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;
321
322 before(async () => {
323 await usingApi(async (api, privateKeyWrapper) => {
324 uniqueAlice = privateKeyWrapper('//Alice');
325 randomAccountUnique = generateKeyringPair();
326 randomAccountMoonbeam = generateKeyringPair('ethereum');
327
328 balanceForeignUnqTokenInit = 0n;
329 });
330
331 await usingApi(
332 async (api) => {
333
334 // >>> 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 <<<
342
343 const sourceLocation: MultiLocation = api.createType(
344 'MultiLocation',
345 {
346 parents: 1,
347 interior: {X1: {Parachain: UNIQUE_CHAIN}},
348 },
349 );
350
351 uniqueAssetLocation = {XCM: sourceLocation};
352 const existentialDeposit = 1;
353 const isSufficient = true;
354 const unitsPerSecond = '1';
355 const numAssetsWeightHint = 0;
356
357 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() || '');
364
365 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() || '');
371
372 const batchCall = api.tx.utility.batchAll([registerTx, setUnitsTx]);
373 console.log('Encoded proposal for batchCall is %s', batchCall.method.toHex() || '');
374
375 // >>> 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);
382
383 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 <<<
389
390 // >>> 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;
401
402 const encodedMotion = externalMotion?.method.toHex() || '';
403 const motionHash = blake2AsHex(encodedMotion);
404 console.log('Motion hash is %s', motionHash);
405
406 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 }
417
418 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 <<<
424
425 // >>> 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;
436
437 const encodedFastTrack = fastTrack?.method.toHex() || '';
438 const fastTrackHash = blake2AsHex(encodedFastTrack);
439 console.log('FastTrack hash is %s', fastTrackHash);
440
441 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 }
453
454 const tx7 = api.tx.techCommitteeCollective
455 .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 <<<
461
462 // >>> 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 <<<
473
474 // >>> Acquire Unique AssetId Info on Moonbeam >>>
475 console.log('Acquire Unique AssetId Info on Moonbeam.......');
476
477 // Wait for the democracy execute
478 await waitNewBlocks(api, 5);
479
480 assetId = (await api.query.assetManager.assetTypeId({
481 XCM: sourceLocation,
482 })).toString();
483
484 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 >>>
487
488 // >>> 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 <<<
496
497 [balanceGlmrTokenInit] = await getBalance(api, [randomAccountMoonbeam.address]);
498 },
499 moonbeamOptions(),
500 );
501
502 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;
507
508 [balanceUniqueTokenInit] = await getBalance(api, [randomAccountUnique.address]);
509 });
510 });
511
512 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;
530
531 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;
535
536 [balanceUniqueTokenMiddle] = await getBalance(api, [randomAccountUnique.address]);
537 expect(balanceUniqueTokenMiddle < balanceUniqueTokenInit).to.be.true;
538
539 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 });
543
544 await usingApi(
545 async (api) => {
546 await waitNewBlocks(api, 3);
547
548 [balanceGlmrTokenMiddle] = await getBalance(api, [randomAccountMoonbeam.address]);
549
550 const glmrFees = balanceGlmrTokenInit - balanceGlmrTokenMiddle;
551 console.log('[Unique -> Moonbeam] transaction fees on Moonbeam: %s GLMR', glmrFees);
552 expect(glmrFees == 0n).to.be.true;
553
554 const unqRandomAccountAsset = (
555 await api.query.assets.account(assetId, randomAccountMoonbeam.address)
556 ).toJSON()! as any;
557
558 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 });
566
567 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;
597
598 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;
602
603 [balanceGlmrTokenFinal] = await getBalance(api, [randomAccountMoonbeam.address]);
604
605 const glmrFees = balanceGlmrTokenMiddle - balanceGlmrTokenFinal;
606 console.log('[Moonbeam -> Unique] transaction fees on Moonbeam: %s GLMR', glmrFees);
607 expect(glmrFees > 0).to.be.true;
608
609 const unqRandomAccountAsset = (
610 await api.query.assets.account(assetId, randomAccountMoonbeam.address)
611 ).toJSON()! as any;
612
613 expect(unqRandomAccountAsset).to.be.null;
614
615 balanceForeignUnqTokenFinal = 0n;
616
617 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 );
623
624 await usingApi(async (api) => {
625 await waitNewBlocks(api, 3);
626
627 [balanceUniqueTokenFinal] = await getBalance(api, [randomAccountUnique.address]);
628 const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;
629 expect(actuallyDelivered > 0).to.be.true;
630
631 console.log('[Moonbeam -> Unique] actually delivered %s UNQ', actuallyDelivered);
632
633 const unqFees = TRANSFER_AMOUNT - actuallyDelivered;
634 console.log('[Moonbeam -> Unique] transaction fees on Unique: %s UNQ', unqFees);
264 expect(unqFees == 0n).to.be.true;635 expect(unqFees == 0n).to.be.true;
265 });636 });
266 });637 });