difftreelog
fix(xcm-tests) use executeTransaction
in: master
3 files changed
tests/src/xcm/xcmOpal.test.tsdiffbeforeafterboth--- a/tests/src/xcm/xcmOpal.test.ts
+++ b/tests/src/xcm/xcmOpal.test.ts
@@ -20,7 +20,7 @@
import {WsProvider} from '@polkadot/api';
import {ApiOptions} from '@polkadot/api/types';
import {IKeyringPair} from '@polkadot/types/types';
-import usingApi, {submitTransactionAsync} from './../substrate/substrate-api';
+import usingApi, {executeTransaction} from './../substrate/substrate-api';
import {bigIntToDecimals, describe_xcm, getGenericResult, paraSiblingSovereignAccount} from './../util/helpers';
import waitNewBlocks from './../substrate/wait-new-blocks';
import {normalizeAccountId} from './../util/helpers';
@@ -93,26 +93,26 @@
const fundingAmount = 3_500_000_000_000;
const tx = api.tx.assets.create(ASSET_ID, alice.addressRaw, ASSET_METADATA_MINIMAL_BALANCE);
- const events = await submitTransactionAsync(alice, tx);
+ const events = await executeTransaction(api, alice, tx);
const result = getGenericResult(events);
expect(result.success).to.be.true;
// set metadata
const tx2 = api.tx.assets.setMetadata(ASSET_ID, ASSET_METADATA_NAME, ASSET_METADATA_DESCRIPTION, ASSET_METADATA_DECIMALS);
- const events2 = await submitTransactionAsync(alice, tx2);
+ const events2 = await executeTransaction(api, alice, tx2);
const result2 = getGenericResult(events2);
expect(result2.success).to.be.true;
// mint some amount of asset
const tx3 = api.tx.assets.mint(ASSET_ID, alice.addressRaw, ASSET_AMOUNT);
- const events3 = await submitTransactionAsync(alice, tx3);
+ const events3 = await executeTransaction(api, alice, tx3);
const result3 = getGenericResult(events3);
expect(result3.success).to.be.true;
// funding parachain sovereing account (Parachain: 2095)
const parachainSovereingAccount = await paraSiblingSovereignAccount(UNIQUE_CHAIN);
const tx4 = api.tx.balances.transfer(parachainSovereingAccount, fundingAmount);
- const events4 = await submitTransactionAsync(bob, tx4);
+ const events4 = await executeTransaction(api, bob, tx4);
const result4 = getGenericResult(events4);
expect(result4.success).to.be.true;
@@ -148,7 +148,7 @@
//registerForeignAsset(owner, location, metadata)
const tx = api.tx.foreignAssets.registerForeignAsset(alice.addressRaw, location, metadata);
const sudoTx = api.tx.sudo.sudo(tx as any);
- const events = await submitTransactionAsync(alice, sudoTx);
+ const events = await executeTransaction(api, alice, sudoTx);
const result = getGenericResult(events);
expect(result.success).to.be.true;
@@ -203,7 +203,7 @@
};
const tx = api.tx.xcmPallet.limitedReserveTransferAssets(destination, beneficiary, assets, feeAssetItem, weightLimit);
- const events = await submitTransactionAsync(alice, tx);
+ const events = await executeTransaction(api, alice, tx);
const result = getGenericResult(events);
expect(result.success).to.be.true;
}, relayApiOptions);
@@ -276,7 +276,7 @@
[balanceStmnBefore] = await getBalance(api, [alice.address]);
const tx = api.tx.polkadotXcm.limitedReserveTransferAssets(dest, beneficiary, assets, feeAssetItem, weightLimit);
- const events = await submitTransactionAsync(alice, tx);
+ const events = await executeTransaction(api, alice, tx);
const result = getGenericResult(events);
expect(result.success).to.be.true;
@@ -365,7 +365,7 @@
const destWeight = 500000000000;
const tx = api.tx.xTokens.transferMulticurrencies(currencies, feeItem, destination, destWeight);
- const events = await submitTransactionAsync(alice, tx);
+ const events = await executeTransaction(api, alice, tx);
const result = getGenericResult(events);
expect(result.success).to.be.true;
@@ -452,7 +452,7 @@
};
const tx = api.tx.xcmPallet.limitedReserveTransferAssets(destination, beneficiary, assets, feeAssetItem, weightLimit);
- const events = await submitTransactionAsync(bob, tx);
+ const events = await executeTransaction(api, bob, tx);
const result = getGenericResult(events);
expect(result.success).to.be.true;
}, relayApiOptions);
@@ -514,7 +514,7 @@
const destWeight = 500000000000;
const tx = api.tx.xTokens.transferMulticurrencies(currencies, feeItem, destination, destWeight);
- const events = await submitTransactionAsync(bob, tx);
+ const events = await executeTransaction(api, bob, tx);
const result = getGenericResult(events);
expect(result.success).to.be.true;
tests/src/xcm/xcmQuartz.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, waitEvent, describe_xcm, bigIntToDecimals} 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';29import {XcmV2TraitsOutcome, XcmV2TraitsError} from '../interfaces';3031chai.use(chaiAsPromised);32const expect = chai.expect;3334const QUARTZ_CHAIN = 2095;35const KARURA_CHAIN = 2000;36const MOONRIVER_CHAIN = 2023;3738const RELAY_PORT = 9844;39const KARURA_PORT = 9946;40const MOONRIVER_PORT = 9947;4142const KARURA_DECIMALS = 12;4344const TRANSFER_AMOUNT = 2000000000000000000000000n;4546function parachainApiOptions(port: number): ApiOptions {47 return {48 provider: new WsProvider('ws://127.0.0.1:' + port.toString()),49 };50}5152function karuraOptions(): ApiOptions {53 return parachainApiOptions(KARURA_PORT);54}5556function moonriverOptions(): ApiOptions {57 return parachainApiOptions(MOONRIVER_PORT);58}5960function relayOptions(): ApiOptions {61 return parachainApiOptions(RELAY_PORT);62}6364describe_xcm('[XCM] Integration test: Exchanging tokens with Karura', () => {65 let alice: IKeyringPair;66 let randomAccount: IKeyringPair;67 68 let balanceQuartzTokenInit: bigint;69 let balanceQuartzTokenMiddle: bigint;70 let balanceQuartzTokenFinal: bigint;71 let balanceKaruraTokenInit: bigint;72 let balanceKaruraTokenMiddle: bigint;73 let balanceKaruraTokenFinal: bigint;74 let balanceQuartzForeignTokenInit: bigint;75 let balanceQuartzForeignTokenMiddle: bigint;76 let balanceQuartzForeignTokenFinal: bigint;77 78 before(async () => {79 await usingApi(async (api, privateKeyWrapper) => {80 alice = privateKeyWrapper('//Alice');81 randomAccount = generateKeyringPair();82 });8384 // Karura side85 await usingApi(86 async (api) => {87 const destination = {88 V0: {89 X2: [90 'Parent',91 {92 Parachain: QUARTZ_CHAIN,93 },94 ],95 },96 };97 98 const metadata = {99 name: 'QTZ',100 symbol: 'QTZ',101 decimals: 18,102 minimalBalance: 1,103 };104 105 const tx = api.tx.assetRegistry.registerForeignAsset(destination, metadata);106 const sudoTx = api.tx.sudo.sudo(tx as any);107 const events = await submitTransactionAsync(alice, sudoTx);108 const result = getGenericResult(events);109 expect(result.success).to.be.true;110 111 const tx1 = api.tx.balances.transfer(randomAccount.address, 10000000000000n);112 const events1 = await submitTransactionAsync(alice, tx1);113 const result1 = getGenericResult(events1);114 expect(result1.success).to.be.true;115 116 [balanceKaruraTokenInit] = await getBalance(api, [randomAccount.address]);117 {118 const {free} = (await api.query.tokens.accounts(randomAccount.addressRaw, {ForeignAsset: 0})).toJSON() as any;119 balanceQuartzForeignTokenInit = BigInt(free);120 }121 },122 karuraOptions(),123 );124 125 // Quartz side126 await usingApi(async (api) => {127 const tx0 = api.tx.balances.transfer(randomAccount.address, 10n * TRANSFER_AMOUNT);128 const events0 = await submitTransactionAsync(alice, tx0);129 const result0 = getGenericResult(events0);130 expect(result0.success).to.be.true;131 132 [balanceQuartzTokenInit] = await getBalance(api, [randomAccount.address]);133 });134 });135 136 it('Should connect and send QTZ to Karura', async () => {137 138 // Quartz side139 await usingApi(async (api) => {140 141 const destination = {142 V0: {143 X2: [144 'Parent',145 {146 Parachain: KARURA_CHAIN,147 },148 ],149 },150 };151 152 const beneficiary = {153 V0: {154 X1: {155 AccountId32: {156 network: 'Any',157 id: randomAccount.addressRaw,158 },159 },160 },161 };162 163 const assets = {164 V1: [165 {166 id: {167 Concrete: {168 parents: 0,169 interior: 'Here',170 },171 },172 fun: {173 Fungible: TRANSFER_AMOUNT,174 },175 },176 ],177 };178 179 const feeAssetItem = 0;180 181 const weightLimit = {182 Limited: 5000000000,183 };184 185 const tx = api.tx.polkadotXcm.limitedReserveTransferAssets(destination, beneficiary, assets, feeAssetItem, weightLimit);186 const events = await submitTransactionAsync(randomAccount, tx);187 const result = getGenericResult(events);188 expect(result.success).to.be.true;189 190 [balanceQuartzTokenMiddle] = await getBalance(api, [randomAccount.address]);191 192 const qtzFees = balanceQuartzTokenInit - balanceQuartzTokenMiddle - TRANSFER_AMOUNT;193 console.log('[Quartz -> Karura] transaction fees on Quartz: %s QTZ', bigIntToDecimals(qtzFees));194 expect(qtzFees > 0n).to.be.true;195 });196 197 // Karura side198 await usingApi(199 async (api) => {200 await waitNewBlocks(api, 3);201 const {free} = (await api.query.tokens.accounts(randomAccount.addressRaw, {ForeignAsset: 0})).toJSON() as any;202 balanceQuartzForeignTokenMiddle = BigInt(free);203 204 [balanceKaruraTokenMiddle] = await getBalance(api, [randomAccount.address]);205206 const karFees = balanceKaruraTokenInit - balanceKaruraTokenMiddle;207 const qtzIncomeTransfer = balanceQuartzForeignTokenMiddle - balanceQuartzForeignTokenInit;208209 console.log(210 '[Quartz -> Karura] transaction fees on Karura: %s KAR',211 bigIntToDecimals(karFees, KARURA_DECIMALS),212 );213 console.log('[Quartz -> Karura] income %s QTZ', bigIntToDecimals(qtzIncomeTransfer));214 expect(karFees == 0n).to.be.true;215 expect(qtzIncomeTransfer == TRANSFER_AMOUNT).to.be.true;216 },217 karuraOptions(),218 );219 });220 221 it('Should connect to Karura and send QTZ back', async () => {222 223 // Karura side224 await usingApi(225 async (api) => {226 const destination = {227 V1: {228 parents: 1,229 interior: {230 X2: [231 {Parachain: QUARTZ_CHAIN},232 {233 AccountId32: {234 network: 'Any',235 id: randomAccount.addressRaw,236 },237 },238 ],239 },240 },241 };242 243 const id = {244 ForeignAsset: 0,245 };246247 const destWeight = 50000000;248 249 const tx = api.tx.xTokens.transfer(id as any, TRANSFER_AMOUNT, destination, destWeight);250 const events = await submitTransactionAsync(randomAccount, tx);251 const result = getGenericResult(events);252 expect(result.success).to.be.true;253 254 [balanceKaruraTokenFinal] = await getBalance(api, [randomAccount.address]);255 {256 const {free} = (await api.query.tokens.accounts(randomAccount.addressRaw, {ForeignAsset: 0})).toJSON() as any;257 balanceQuartzForeignTokenFinal = BigInt(free);258 }259 260 const karFees = balanceKaruraTokenMiddle - balanceKaruraTokenFinal;261 const qtzOutcomeTransfer = balanceQuartzForeignTokenMiddle - balanceQuartzForeignTokenFinal;262263 console.log(264 '[Karura -> Quartz] transaction fees on Karura: %s KAR',265 bigIntToDecimals(karFees, KARURA_DECIMALS),266 );267 console.log('[Karura -> Quartz] outcome %s QTZ', bigIntToDecimals(qtzOutcomeTransfer));268269 expect(karFees > 0).to.be.true;270 expect(qtzOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;271 },272 karuraOptions(),273 );274275 // Quartz side276 await usingApi(async (api) => {277 await waitNewBlocks(api, 3);278 279 [balanceQuartzTokenFinal] = await getBalance(api, [randomAccount.address]);280 const actuallyDelivered = balanceQuartzTokenFinal - balanceQuartzTokenMiddle;281 expect(actuallyDelivered > 0).to.be.true;282283 console.log('[Karura -> Quartz] actually delivered %s QTZ', bigIntToDecimals(actuallyDelivered));284 285 const qtzFees = TRANSFER_AMOUNT - actuallyDelivered;286 console.log('[Karura -> Quartz] transaction fees on Quartz: %s QTZ', bigIntToDecimals(qtzFees));287 expect(qtzFees == 0n).to.be.true;288 });289 });290});291292// These tests are relevant only when the foreign asset pallet is disabled293describe_xcm('[XCM] Integration test: Quartz rejects non-native tokens', () => {294 let alice: IKeyringPair;295296 before(async () => {297 await usingApi(async (api, privateKeyWrapper) => {298 alice = privateKeyWrapper('//Alice');299 });300 });301 302 it('Quartz rejects tokens from the Relay', async () => {303 await usingApi(async (api) => {304 const destination = {305 V1: {306 parents: 0,307 interior: {X1: {308 Parachain: QUARTZ_CHAIN,309 },310 },311 }};312313 const beneficiary = {314 V1: {315 parents: 0,316 interior: {X1: {317 AccountId32: {318 network: 'Any',319 id: alice.addressRaw,320 },321 }},322 },323 };324325 const assets = {326 V1: [327 {328 id: {329 Concrete: {330 parents: 0,331 interior: 'Here',332 },333 },334 fun: {335 Fungible: 50_000_000_000_000_000n,336 },337 },338 ],339 };340341 const feeAssetItem = 0;342343 const weightLimit = {344 Limited: 5_000_000_000,345 };346347 const tx = api.tx.xcmPallet.limitedReserveTransferAssets(destination, beneficiary, assets, feeAssetItem, weightLimit);348 const events = await submitTransactionAsync(alice, tx);349 const result = getGenericResult(events);350 expect(result.success).to.be.true;351 }, relayOptions());352353 await usingApi(async api => {354 const maxWaitBlocks = 3;355 const dmpQueueExecutedDownward = await waitEvent(356 api,357 maxWaitBlocks,358 'dmpQueue',359 'ExecutedDownward',360 );361362 expect(363 dmpQueueExecutedDownward != null,364 '[Relay] dmpQueue.ExecutedDownward event is expected',365 ).to.be.true;366367 const event = dmpQueueExecutedDownward!.event;368 const outcome = event.data[1] as XcmV2TraitsOutcome;369370 expect(371 outcome.isIncomplete,372 '[Relay] The outcome of the XCM should be `Incomplete`',373 ).to.be.true;374375 const incomplete = outcome.asIncomplete;376 expect(377 incomplete[1].toString() == 'AssetNotFound',378 '[Relay] The XCM error should be `AssetNotFound`',379 ).to.be.true;380 });381 });382383 it('Quartz rejects KAR tokens from Karura', async () => {384 await usingApi(async (api) => {385 const destination = {386 V1: {387 parents: 1,388 interior: {389 X2: [390 {Parachain: QUARTZ_CHAIN},391 {392 AccountId32: {393 network: 'Any',394 id: alice.addressRaw,395 },396 },397 ],398 },399 },400 };401402 const id = {403 Token: 'KAR',404 };405406 const destWeight = 50000000;407408 const tx = api.tx.xTokens.transfer(id as any, 100_000_000_000, destination, destWeight);409 const events = await submitTransactionAsync(alice, tx);410 const result = getGenericResult(events);411 expect(result.success).to.be.true;412 }, karuraOptions());413414 await usingApi(async api => {415 const maxWaitBlocks = 3;416 const xcmpQueueFailEvent = await waitEvent(api, maxWaitBlocks, 'xcmpQueue', 'Fail');417418 expect(419 xcmpQueueFailEvent != null,420 '[Karura] xcmpQueue.FailEvent event is expected',421 ).to.be.true;422423 const event = xcmpQueueFailEvent!.event;424 const outcome = event.data[1] as XcmV2TraitsError;425426 expect(427 outcome.isUntrustedReserveLocation,428 '[Karura] The XCM error should be `UntrustedReserveLocation`',429 ).to.be.true;430 });431 });432});433434describe_xcm('[XCM] Integration test: Exchanging QTZ with Moonriver', () => {435436 // Quartz constants437 let quartzAlice: IKeyringPair;438 let quartzAssetLocation;439440 let randomAccountQuartz: IKeyringPair;441 let randomAccountMoonriver: IKeyringPair;442443 // Moonriver constants444 let assetId: string;445446 const moonriverKeyring = new Keyring({type: 'ethereum'});447 const alithPrivateKey = '0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133';448 const baltatharPrivateKey = '0x8075991ce870b93a8870eca0c0f91913d12f47948ca0fd25b49c6fa7cdbeee8b';449 const dorothyPrivateKey = '0x39539ab1876910bbf3a223d84a29e28f1cb4e2e456503e7e91ed39b2e7223d68';450451 const alithAccount = moonriverKeyring.addFromUri(alithPrivateKey, undefined, 'ethereum');452 const baltatharAccount = moonriverKeyring.addFromUri(baltatharPrivateKey, undefined, 'ethereum');453 const dorothyAccount = moonriverKeyring.addFromUri(dorothyPrivateKey, undefined, 'ethereum');454455 const councilVotingThreshold = 2;456 const technicalCommitteeThreshold = 2;457 const votingPeriod = 3;458 const delayPeriod = 0;459460 const quartzAssetMetadata = {461 name: 'xcQuartz',462 symbol: 'xcQTZ',463 decimals: 18,464 isFrozen: false,465 minimalBalance: 1,466 };467468 let balanceQuartzTokenInit: bigint;469 let balanceQuartzTokenMiddle: bigint;470 let balanceQuartzTokenFinal: bigint;471 let balanceForeignQtzTokenInit: bigint;472 let balanceForeignQtzTokenMiddle: bigint;473 let balanceForeignQtzTokenFinal: bigint;474 let balanceMovrTokenInit: bigint;475 let balanceMovrTokenMiddle: bigint;476 let balanceMovrTokenFinal: bigint;477478 before(async () => {479 await usingApi(async (api, privateKeyWrapper) => {480 quartzAlice = privateKeyWrapper('//Alice');481 randomAccountQuartz = generateKeyringPair();482 randomAccountMoonriver = generateKeyringPair('ethereum');483484 balanceForeignQtzTokenInit = 0n;485 });486487 await usingApi(488 async (api) => {489490 // >>> Sponsoring Dorothy >>>491 console.log('Sponsoring Dorothy.......');492 const tx0 = api.tx.balances.transfer(dorothyAccount.address, 11_000_000_000_000_000_000n);493 const events0 = await submitTransactionAsync(alithAccount, tx0);494 const result0 = getGenericResult(events0);495 expect(result0.success).to.be.true;496 console.log('Sponsoring Dorothy.......DONE');497 // <<< Sponsoring Dorothy <<<498499 const sourceLocation: MultiLocation = api.createType(500 'MultiLocation',501 {502 parents: 1,503 interior: {X1: {Parachain: QUARTZ_CHAIN}},504 },505 );506507 quartzAssetLocation = {XCM: sourceLocation};508 const existentialDeposit = 1;509 const isSufficient = true;510 const unitsPerSecond = '1';511 const numAssetsWeightHint = 0;512513 const registerTx = api.tx.assetManager.registerForeignAsset(514 quartzAssetLocation,515 quartzAssetMetadata,516 existentialDeposit,517 isSufficient,518 );519 console.log('Encoded proposal for registerAsset is %s', registerTx.method.toHex() || '');520521 const setUnitsTx = api.tx.assetManager.setAssetUnitsPerSecond(522 quartzAssetLocation,523 unitsPerSecond,524 numAssetsWeightHint,525 );526 console.log('Encoded proposal for setAssetUnitsPerSecond is %s', setUnitsTx.method.toHex() || '');527528 const batchCall = api.tx.utility.batchAll([registerTx, setUnitsTx]);529 console.log('Encoded proposal for batchCall is %s', batchCall.method.toHex() || '');530531 // >>> Note motion preimage >>>532 console.log('Note motion preimage.......');533 const encodedProposal = batchCall?.method.toHex() || '';534 const proposalHash = blake2AsHex(encodedProposal);535 console.log('Encoded proposal for batch utility after schedule is %s', encodedProposal);536 console.log('Encoded proposal hash for batch utility after schedule is %s', proposalHash);537 console.log('Encoded length %d', encodedProposal.length);538539 const tx1 = api.tx.democracy.notePreimage(encodedProposal);540 const events1 = await submitTransactionAsync(baltatharAccount, tx1);541 const result1 = getGenericResult(events1);542 expect(result1.success).to.be.true;543 console.log('Note motion preimage.......DONE');544 // <<< Note motion preimage <<<545546 // >>> Propose external motion through council >>>547 console.log('Propose external motion through council.......');548 const externalMotion = api.tx.democracy.externalProposeMajority(proposalHash);549 const tx2 = api.tx.councilCollective.propose(550 councilVotingThreshold,551 externalMotion,552 externalMotion.encodedLength,553 );554 const events2 = await submitTransactionAsync(baltatharAccount, tx2);555 const result2 = getGenericResult(events2);556 expect(result2.success).to.be.true;557558 const encodedMotion = externalMotion?.method.toHex() || '';559 const motionHash = blake2AsHex(encodedMotion);560 console.log('Motion hash is %s', motionHash);561562 const tx3 = api.tx.councilCollective.vote(motionHash, 0, true);563 {564 const events3 = await submitTransactionAsync(dorothyAccount, tx3);565 const result3 = getGenericResult(events3);566 expect(result3.success).to.be.true;567 }568 {569 const events3 = await submitTransactionAsync(baltatharAccount, tx3);570 const result3 = getGenericResult(events3);571 expect(result3.success).to.be.true;572 }573574 const tx4 = api.tx.councilCollective.close(motionHash, 0, 1_000_000_000, externalMotion.encodedLength);575 const events4 = await submitTransactionAsync(dorothyAccount, tx4);576 const result4 = getGenericResult(events4);577 expect(result4.success).to.be.true;578 console.log('Propose external motion through council.......DONE');579 // <<< Propose external motion through council <<<580581 // >>> Fast track proposal through technical committee >>>582 console.log('Fast track proposal through technical committee.......');583 const fastTrack = api.tx.democracy.fastTrack(proposalHash, votingPeriod, delayPeriod);584 const tx5 = api.tx.techCommitteeCollective.propose(585 technicalCommitteeThreshold,586 fastTrack,587 fastTrack.encodedLength,588 );589 const events5 = await submitTransactionAsync(alithAccount, tx5);590 const result5 = getGenericResult(events5);591 expect(result5.success).to.be.true;592593 const encodedFastTrack = fastTrack?.method.toHex() || '';594 const fastTrackHash = blake2AsHex(encodedFastTrack);595 console.log('FastTrack hash is %s', fastTrackHash);596597 const proposalIdx = Number(await api.query.techCommitteeCollective.proposalCount()) - 1;598 const tx6 = api.tx.techCommitteeCollective.vote(fastTrackHash, proposalIdx, true);599 {600 const events6 = await submitTransactionAsync(baltatharAccount, tx6);601 const result6 = getGenericResult(events6);602 expect(result6.success).to.be.true;603 }604 {605 const events6 = await submitTransactionAsync(alithAccount, tx6);606 const result6 = getGenericResult(events6);607 expect(result6.success).to.be.true;608 }609610 const tx7 = api.tx.techCommitteeCollective611 .close(fastTrackHash, proposalIdx, 1_000_000_000, fastTrack.encodedLength);612 const events7 = await submitTransactionAsync(baltatharAccount, tx7);613 const result7 = getGenericResult(events7);614 expect(result7.success).to.be.true;615 console.log('Fast track proposal through technical committee.......DONE');616 // <<< Fast track proposal through technical committee <<<617618 // >>> Referendum voting >>>619 console.log('Referendum voting.......');620 const tx8 = api.tx.democracy.vote(621 0,622 {Standard: {balance: 10_000_000_000_000_000_000n, vote: {aye: true, conviction: 1}}},623 );624 const events8 = await submitTransactionAsync(dorothyAccount, tx8);625 const result8 = getGenericResult(events8);626 expect(result8.success).to.be.true;627 console.log('Referendum voting.......DONE');628 // <<< Referendum voting <<<629630 // >>> Acquire Quartz AssetId Info on Moonriver >>>631 console.log('Acquire Quartz AssetId Info on Moonriver.......');632633 // Wait for the democracy execute634 await waitNewBlocks(api, 5);635636 assetId = (await api.query.assetManager.assetTypeId({637 XCM: sourceLocation,638 })).toString();639640 console.log('QTZ asset ID is %s', assetId);641 console.log('Acquire Quartz AssetId Info on Moonriver.......DONE');642 // >>> Acquire Quartz AssetId Info on Moonriver >>>643644 // >>> Sponsoring random Account >>>645 console.log('Sponsoring random Account.......');646 const tx10 = api.tx.balances.transfer(randomAccountMoonriver.address, 11_000_000_000_000_000_000n);647 const events10 = await submitTransactionAsync(baltatharAccount, tx10);648 const result10 = getGenericResult(events10);649 expect(result10.success).to.be.true;650 console.log('Sponsoring random Account.......DONE');651 // <<< Sponsoring random Account <<<652653 [balanceMovrTokenInit] = await getBalance(api, [randomAccountMoonriver.address]);654 },655 moonriverOptions(),656 );657658 await usingApi(async (api) => {659 const tx0 = api.tx.balances.transfer(randomAccountQuartz.address, 10n * TRANSFER_AMOUNT);660 const events0 = await submitTransactionAsync(quartzAlice, tx0);661 const result0 = getGenericResult(events0);662 expect(result0.success).to.be.true;663664 [balanceQuartzTokenInit] = await getBalance(api, [randomAccountQuartz.address]);665 });666 });667668 it('Should connect and send QTZ to Moonriver', async () => {669 await usingApi(async (api) => {670 const currencyId = {671 NativeAssetId: 'Here',672 };673 const dest = {674 V1: {675 parents: 1,676 interior: {677 X2: [678 {Parachain: MOONRIVER_CHAIN},679 {AccountKey20: {network: 'Any', key: randomAccountMoonriver.address}},680 ],681 },682 },683 };684 const amount = TRANSFER_AMOUNT;685 const destWeight = 850000000;686687 const tx = api.tx.xTokens.transfer(currencyId, amount, dest, destWeight);688 const events = await submitTransactionAsync(randomAccountQuartz, tx);689 const result = getGenericResult(events);690 expect(result.success).to.be.true;691692 [balanceQuartzTokenMiddle] = await getBalance(api, [randomAccountQuartz.address]);693 expect(balanceQuartzTokenMiddle < balanceQuartzTokenInit).to.be.true;694695 const transactionFees = balanceQuartzTokenInit - balanceQuartzTokenMiddle - TRANSFER_AMOUNT;696 console.log('[Quartz -> Moonriver] transaction fees on Quartz: %s QTZ', bigIntToDecimals(transactionFees));697 expect(transactionFees > 0).to.be.true;698 });699700 await usingApi(701 async (api) => {702 await waitNewBlocks(api, 3);703704 [balanceMovrTokenMiddle] = await getBalance(api, [randomAccountMoonriver.address]);705706 const movrFees = balanceMovrTokenInit - balanceMovrTokenMiddle;707 console.log('[Quartz -> Moonriver] transaction fees on Moonriver: %s MOVR',bigIntToDecimals(movrFees));708 expect(movrFees == 0n).to.be.true;709710 const qtzRandomAccountAsset = (711 await api.query.assets.account(assetId, randomAccountMoonriver.address)712 ).toJSON()! as any;713714 balanceForeignQtzTokenMiddle = BigInt(qtzRandomAccountAsset['balance']);715 const qtzIncomeTransfer = balanceForeignQtzTokenMiddle - balanceForeignQtzTokenInit;716 console.log('[Quartz -> Moonriver] income %s QTZ', bigIntToDecimals(qtzIncomeTransfer));717 expect(qtzIncomeTransfer == TRANSFER_AMOUNT).to.be.true;718 },719 moonriverOptions(),720 );721 });722723 it('Should connect to Moonriver and send QTZ back', async () => {724 await usingApi(725 async (api) => {726 const asset = {727 V1: {728 id: {729 Concrete: {730 parents: 1,731 interior: {732 X1: {Parachain: QUARTZ_CHAIN},733 },734 },735 },736 fun: {737 Fungible: TRANSFER_AMOUNT,738 },739 },740 };741 const destination = {742 V1: {743 parents: 1,744 interior: {745 X2: [746 {Parachain: QUARTZ_CHAIN},747 {AccountId32: {network: 'Any', id: randomAccountQuartz.addressRaw}},748 ],749 },750 },751 };752 const destWeight = 50000000;753754 const tx = api.tx.xTokens.transferMultiasset(asset, destination, destWeight);755 const events = await submitTransactionAsync(randomAccountMoonriver, tx);756 const result = getGenericResult(events);757 expect(result.success).to.be.true;758759 [balanceMovrTokenFinal] = await getBalance(api, [randomAccountMoonriver.address]);760761 const movrFees = balanceMovrTokenMiddle - balanceMovrTokenFinal;762 console.log('[Moonriver -> Quartz] transaction fees on Moonriver: %s MOVR', bigIntToDecimals(movrFees));763 expect(movrFees > 0).to.be.true;764765 const qtzRandomAccountAsset = (766 await api.query.assets.account(assetId, randomAccountMoonriver.address)767 ).toJSON()! as any;768769 expect(qtzRandomAccountAsset).to.be.null;770771 balanceForeignQtzTokenFinal = 0n;772773 const qtzOutcomeTransfer = balanceForeignQtzTokenMiddle - balanceForeignQtzTokenFinal;774 console.log('[Quartz -> Moonriver] outcome %s QTZ', bigIntToDecimals(qtzOutcomeTransfer));775 expect(qtzOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;776 },777 moonriverOptions(),778 );779780 await usingApi(async (api) => {781 await waitNewBlocks(api, 3);782783 [balanceQuartzTokenFinal] = await getBalance(api, [randomAccountQuartz.address]);784 const actuallyDelivered = balanceQuartzTokenFinal - balanceQuartzTokenMiddle;785 expect(actuallyDelivered > 0).to.be.true;786787 console.log('[Moonriver -> Quartz] actually delivered %s QTZ', bigIntToDecimals(actuallyDelivered));788789 const qtzFees = TRANSFER_AMOUNT - actuallyDelivered;790 console.log('[Moonriver -> Quartz] transaction fees on Quartz: %s QTZ', bigIntToDecimals(qtzFees));791 expect(qtzFees == 0n).to.be.true;792 });793 });794});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 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, waitEvent, describe_xcm, bigIntToDecimals} 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';29import {XcmV2TraitsOutcome, XcmV2TraitsError} from '../interfaces';3031chai.use(chaiAsPromised);32const expect = chai.expect;3334const QUARTZ_CHAIN = 2095;35const KARURA_CHAIN = 2000;36const MOONRIVER_CHAIN = 2023;3738const RELAY_PORT = 9844;39const KARURA_PORT = 9946;40const MOONRIVER_PORT = 9947;4142const KARURA_DECIMALS = 12;4344const TRANSFER_AMOUNT = 2000000000000000000000000n;4546function parachainApiOptions(port: number): ApiOptions {47 return {48 provider: new WsProvider('ws://127.0.0.1:' + port.toString()),49 };50}5152function karuraOptions(): ApiOptions {53 return parachainApiOptions(KARURA_PORT);54}5556function moonriverOptions(): ApiOptions {57 return parachainApiOptions(MOONRIVER_PORT);58}5960function relayOptions(): ApiOptions {61 return parachainApiOptions(RELAY_PORT);62}6364describe_xcm('[XCM] Integration test: Exchanging tokens with Karura', () => {65 let alice: IKeyringPair;66 let randomAccount: IKeyringPair;67 68 let balanceQuartzTokenInit: bigint;69 let balanceQuartzTokenMiddle: bigint;70 let balanceQuartzTokenFinal: bigint;71 let balanceKaruraTokenInit: bigint;72 let balanceKaruraTokenMiddle: bigint;73 let balanceKaruraTokenFinal: bigint;74 let balanceQuartzForeignTokenInit: bigint;75 let balanceQuartzForeignTokenMiddle: bigint;76 let balanceQuartzForeignTokenFinal: bigint;77 78 before(async () => {79 await usingApi(async (api, privateKeyWrapper) => {80 const keyringSr25519 = new Keyring({type: 'sr25519'});8182 alice = privateKeyWrapper('//Alice');83 randomAccount = generateKeyringPair(keyringSr25519);84 });8586 // Karura side87 await usingApi(88 async (api) => {89 const destination = {90 V0: {91 X2: [92 'Parent',93 {94 Parachain: QUARTZ_CHAIN,95 },96 ],97 },98 };99 100 const metadata = {101 name: 'QTZ',102 symbol: 'QTZ',103 decimals: 18,104 minimalBalance: 1,105 };106 107 const tx = api.tx.assetRegistry.registerForeignAsset(destination, metadata);108 const sudoTx = api.tx.sudo.sudo(tx as any);109 const events = await submitTransactionAsync(alice, sudoTx);110 const result = getGenericResult(events);111 expect(result.success).to.be.true;112 113 const tx1 = api.tx.balances.transfer(randomAccount.address, 10000000000000n);114 const events1 = await submitTransactionAsync(alice, tx1);115 const result1 = getGenericResult(events1);116 expect(result1.success).to.be.true;117 118 [balanceKaruraTokenInit] = await getBalance(api, [randomAccount.address]);119 {120 const {free} = (await api.query.tokens.accounts(randomAccount.addressRaw, {ForeignAsset: 0})).toJSON() as any;121 balanceQuartzForeignTokenInit = BigInt(free);122 }123 },124 karuraOptions(),125 );126 127 // Quartz side128 await usingApi(async (api) => {129 const tx0 = api.tx.balances.transfer(randomAccount.address, 10n * TRANSFER_AMOUNT);130 const events0 = await submitTransactionAsync(alice, tx0);131 const result0 = getGenericResult(events0);132 expect(result0.success).to.be.true;133 134 [balanceQuartzTokenInit] = await getBalance(api, [randomAccount.address]);135 });136 });137 138 it('Should connect and send QTZ to Karura', async () => {139 140 // Quartz side141 await usingApi(async (api) => {142 143 const destination = {144 V0: {145 X2: [146 'Parent',147 {148 Parachain: KARURA_CHAIN,149 },150 ],151 },152 };153 154 const beneficiary = {155 V0: {156 X1: {157 AccountId32: {158 network: 'Any',159 id: randomAccount.addressRaw,160 },161 },162 },163 };164 165 const assets = {166 V1: [167 {168 id: {169 Concrete: {170 parents: 0,171 interior: 'Here',172 },173 },174 fun: {175 Fungible: TRANSFER_AMOUNT,176 },177 },178 ],179 };180 181 const feeAssetItem = 0;182 183 const weightLimit = {184 Limited: 5000000000,185 };186 187 const tx = api.tx.polkadotXcm.limitedReserveTransferAssets(destination, beneficiary, assets, feeAssetItem, weightLimit);188 const events = await submitTransactionAsync(randomAccount, tx);189 const result = getGenericResult(events);190 expect(result.success).to.be.true;191 192 [balanceQuartzTokenMiddle] = await getBalance(api, [randomAccount.address]);193 194 const qtzFees = balanceQuartzTokenInit - balanceQuartzTokenMiddle - TRANSFER_AMOUNT;195 console.log('[Quartz -> Karura] transaction fees on Quartz: %s QTZ', bigIntToDecimals(qtzFees));196 expect(qtzFees > 0n).to.be.true;197 });198 199 // Karura side200 await usingApi(201 async (api) => {202 await waitNewBlocks(api, 3);203 const {free} = (await api.query.tokens.accounts(randomAccount.addressRaw, {ForeignAsset: 0})).toJSON() as any;204 balanceQuartzForeignTokenMiddle = BigInt(free);205 206 [balanceKaruraTokenMiddle] = await getBalance(api, [randomAccount.address]);207208 const karFees = balanceKaruraTokenInit - balanceKaruraTokenMiddle;209 const qtzIncomeTransfer = balanceQuartzForeignTokenMiddle - balanceQuartzForeignTokenInit;210211 console.log(212 '[Quartz -> Karura] transaction fees on Karura: %s KAR',213 bigIntToDecimals(karFees, KARURA_DECIMALS),214 );215 console.log('[Quartz -> Karura] income %s QTZ', bigIntToDecimals(qtzIncomeTransfer));216 expect(karFees == 0n).to.be.true;217 expect(qtzIncomeTransfer == TRANSFER_AMOUNT).to.be.true;218 },219 karuraOptions(),220 );221 });222 223 it('Should connect to Karura and send QTZ back', async () => {224 225 // Karura side226 await usingApi(227 async (api) => {228 const destination = {229 V1: {230 parents: 1,231 interior: {232 X2: [233 {Parachain: QUARTZ_CHAIN},234 {235 AccountId32: {236 network: 'Any',237 id: randomAccount.addressRaw,238 },239 },240 ],241 },242 },243 };244 245 const id = {246 ForeignAsset: 0,247 };248249 const destWeight = 50000000;250 251 const tx = api.tx.xTokens.transfer(id as any, TRANSFER_AMOUNT, destination, destWeight);252 const events = await submitTransactionAsync(randomAccount, tx);253 const result = getGenericResult(events);254 expect(result.success).to.be.true;255 256 [balanceKaruraTokenFinal] = await getBalance(api, [randomAccount.address]);257 {258 const {free} = (await api.query.tokens.accounts(randomAccount.addressRaw, {ForeignAsset: 0})).toJSON() as any;259 balanceQuartzForeignTokenFinal = BigInt(free);260 }261 262 const karFees = balanceKaruraTokenMiddle - balanceKaruraTokenFinal;263 const qtzOutcomeTransfer = balanceQuartzForeignTokenMiddle - balanceQuartzForeignTokenFinal;264265 console.log(266 '[Karura -> Quartz] transaction fees on Karura: %s KAR',267 bigIntToDecimals(karFees, KARURA_DECIMALS),268 );269 console.log('[Karura -> Quartz] outcome %s QTZ', bigIntToDecimals(qtzOutcomeTransfer));270271 expect(karFees > 0).to.be.true;272 expect(qtzOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;273 },274 karuraOptions(),275 );276277 // Quartz side278 await usingApi(async (api) => {279 await waitNewBlocks(api, 3);280 281 [balanceQuartzTokenFinal] = await getBalance(api, [randomAccount.address]);282 const actuallyDelivered = balanceQuartzTokenFinal - balanceQuartzTokenMiddle;283 expect(actuallyDelivered > 0).to.be.true;284285 console.log('[Karura -> Quartz] actually delivered %s QTZ', bigIntToDecimals(actuallyDelivered));286 287 const qtzFees = TRANSFER_AMOUNT - actuallyDelivered;288 console.log('[Karura -> Quartz] transaction fees on Quartz: %s QTZ', bigIntToDecimals(qtzFees));289 expect(qtzFees == 0n).to.be.true;290 });291 });292});293294// These tests are relevant only when the foreign asset pallet is disabled295describe_xcm('[XCM] Integration test: Quartz rejects non-native tokens', () => {296 let alice: IKeyringPair;297298 before(async () => {299 await usingApi(async (api, privateKeyWrapper) => {300 alice = privateKeyWrapper('//Alice');301 });302 });303 304 it('Quartz rejects tokens from the Relay', async () => {305 await usingApi(async (api) => {306 const destination = {307 V1: {308 parents: 0,309 interior: {X1: {310 Parachain: QUARTZ_CHAIN,311 },312 },313 }};314315 const beneficiary = {316 V1: {317 parents: 0,318 interior: {X1: {319 AccountId32: {320 network: 'Any',321 id: alice.addressRaw,322 },323 }},324 },325 };326327 const assets = {328 V1: [329 {330 id: {331 Concrete: {332 parents: 0,333 interior: 'Here',334 },335 },336 fun: {337 Fungible: 50_000_000_000_000_000n,338 },339 },340 ],341 };342343 const feeAssetItem = 0;344345 const weightLimit = {346 Limited: 5_000_000_000,347 };348349 const tx = api.tx.xcmPallet.limitedReserveTransferAssets(destination, beneficiary, assets, feeAssetItem, weightLimit);350 const events = await submitTransactionAsync(alice, tx);351 const result = getGenericResult(events);352 expect(result.success).to.be.true;353 }, relayOptions());354355 await usingApi(async api => {356 const maxWaitBlocks = 3;357 const dmpQueueExecutedDownward = await waitEvent(358 api,359 maxWaitBlocks,360 'dmpQueue',361 'ExecutedDownward',362 );363364 expect(365 dmpQueueExecutedDownward != null,366 '[Relay] dmpQueue.ExecutedDownward event is expected',367 ).to.be.true;368369 const event = dmpQueueExecutedDownward!.event;370 const outcome = event.data[1] as XcmV2TraitsOutcome;371372 expect(373 outcome.isIncomplete,374 '[Relay] The outcome of the XCM should be `Incomplete`',375 ).to.be.true;376377 const incomplete = outcome.asIncomplete;378 expect(379 incomplete[1].toString() == 'AssetNotFound',380 '[Relay] The XCM error should be `AssetNotFound`',381 ).to.be.true;382 });383 });384385 it('Quartz rejects KAR tokens from Karura', async () => {386 await usingApi(async (api) => {387 const destination = {388 V1: {389 parents: 1,390 interior: {391 X2: [392 {Parachain: QUARTZ_CHAIN},393 {394 AccountId32: {395 network: 'Any',396 id: alice.addressRaw,397 },398 },399 ],400 },401 },402 };403404 const id = {405 Token: 'KAR',406 };407408 const destWeight = 50000000;409410 const tx = api.tx.xTokens.transfer(id as any, 100_000_000_000, destination, destWeight);411 const events = await submitTransactionAsync(alice, tx);412 const result = getGenericResult(events);413 expect(result.success).to.be.true;414 }, karuraOptions());415416 await usingApi(async api => {417 const maxWaitBlocks = 3;418 const xcmpQueueFailEvent = await waitEvent(api, maxWaitBlocks, 'xcmpQueue', 'Fail');419420 expect(421 xcmpQueueFailEvent != null,422 '[Karura] xcmpQueue.FailEvent event is expected',423 ).to.be.true;424425 const event = xcmpQueueFailEvent!.event;426 const outcome = event.data[1] as XcmV2TraitsError;427428 expect(429 outcome.isUntrustedReserveLocation,430 '[Karura] The XCM error should be `UntrustedReserveLocation`',431 ).to.be.true;432 });433 });434});435436describe_xcm('[XCM] Integration test: Exchanging QTZ with Moonriver', () => {437438 // Quartz constants439 let quartzAlice: IKeyringPair;440 let quartzAssetLocation;441442 let randomAccountQuartz: IKeyringPair;443 let randomAccountMoonriver: IKeyringPair;444445 // Moonriver constants446 let assetId: string;447448 const moonriverKeyring = new Keyring({type: 'ethereum'});449 const alithPrivateKey = '0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133';450 const baltatharPrivateKey = '0x8075991ce870b93a8870eca0c0f91913d12f47948ca0fd25b49c6fa7cdbeee8b';451 const dorothyPrivateKey = '0x39539ab1876910bbf3a223d84a29e28f1cb4e2e456503e7e91ed39b2e7223d68';452453 const alithAccount = moonriverKeyring.addFromUri(alithPrivateKey, undefined, 'ethereum');454 const baltatharAccount = moonriverKeyring.addFromUri(baltatharPrivateKey, undefined, 'ethereum');455 const dorothyAccount = moonriverKeyring.addFromUri(dorothyPrivateKey, undefined, 'ethereum');456457 const councilVotingThreshold = 2;458 const technicalCommitteeThreshold = 2;459 const votingPeriod = 3;460 const delayPeriod = 0;461462 const quartzAssetMetadata = {463 name: 'xcQuartz',464 symbol: 'xcQTZ',465 decimals: 18,466 isFrozen: false,467 minimalBalance: 1,468 };469470 let balanceQuartzTokenInit: bigint;471 let balanceQuartzTokenMiddle: bigint;472 let balanceQuartzTokenFinal: bigint;473 let balanceForeignQtzTokenInit: bigint;474 let balanceForeignQtzTokenMiddle: bigint;475 let balanceForeignQtzTokenFinal: bigint;476 let balanceMovrTokenInit: bigint;477 let balanceMovrTokenMiddle: bigint;478 let balanceMovrTokenFinal: bigint;479480 before(async () => {481 await usingApi(async (api, privateKeyWrapper) => {482 const keyringEth = new Keyring({type: 'ethereum'});483 const keyringSr25519 = new Keyring({type: 'sr25519'});484485 quartzAlice = privateKeyWrapper('//Alice');486 randomAccountQuartz = generateKeyringPair(keyringSr25519);487 randomAccountMoonriver = generateKeyringPair(keyringEth);488489 balanceForeignQtzTokenInit = 0n;490 });491492 await usingApi(493 async (api) => {494495 // >>> Sponsoring Dorothy >>>496 console.log('Sponsoring Dorothy.......');497 const tx0 = api.tx.balances.transfer(dorothyAccount.address, 11_000_000_000_000_000_000n);498 const events0 = await submitTransactionAsync(alithAccount, tx0);499 const result0 = getGenericResult(events0);500 expect(result0.success).to.be.true;501 console.log('Sponsoring Dorothy.......DONE');502 // <<< Sponsoring Dorothy <<<503504 const sourceLocation: MultiLocation = api.createType(505 'MultiLocation',506 {507 parents: 1,508 interior: {X1: {Parachain: QUARTZ_CHAIN}},509 },510 );511512 quartzAssetLocation = {XCM: sourceLocation};513 const existentialDeposit = 1;514 const isSufficient = true;515 const unitsPerSecond = '1';516 const numAssetsWeightHint = 0;517518 const registerTx = api.tx.assetManager.registerForeignAsset(519 quartzAssetLocation,520 quartzAssetMetadata,521 existentialDeposit,522 isSufficient,523 );524 console.log('Encoded proposal for registerAsset is %s', registerTx.method.toHex() || '');525526 const setUnitsTx = api.tx.assetManager.setAssetUnitsPerSecond(527 quartzAssetLocation,528 unitsPerSecond,529 numAssetsWeightHint,530 );531 console.log('Encoded proposal for setAssetUnitsPerSecond is %s', setUnitsTx.method.toHex() || '');532533 const batchCall = api.tx.utility.batchAll([registerTx, setUnitsTx]);534 console.log('Encoded proposal for batchCall is %s', batchCall.method.toHex() || '');535536 // >>> Note motion preimage >>>537 console.log('Note motion preimage.......');538 const encodedProposal = batchCall?.method.toHex() || '';539 const proposalHash = blake2AsHex(encodedProposal);540 console.log('Encoded proposal for batch utility after schedule is %s', encodedProposal);541 console.log('Encoded proposal hash for batch utility after schedule is %s', proposalHash);542 console.log('Encoded length %d', encodedProposal.length);543544 const tx1 = api.tx.democracy.notePreimage(encodedProposal);545 const events1 = await submitTransactionAsync(baltatharAccount, tx1);546 const result1 = getGenericResult(events1);547 expect(result1.success).to.be.true;548 console.log('Note motion preimage.......DONE');549 // <<< Note motion preimage <<<550551 // >>> Propose external motion through council >>>552 console.log('Propose external motion through council.......');553 const externalMotion = api.tx.democracy.externalProposeMajority(proposalHash);554 const tx2 = api.tx.councilCollective.propose(555 councilVotingThreshold,556 externalMotion,557 externalMotion.encodedLength,558 );559 const events2 = await submitTransactionAsync(baltatharAccount, tx2);560 const result2 = getGenericResult(events2);561 expect(result2.success).to.be.true;562563 const encodedMotion = externalMotion?.method.toHex() || '';564 const motionHash = blake2AsHex(encodedMotion);565 console.log('Motion hash is %s', motionHash);566567 const tx3 = api.tx.councilCollective.vote(motionHash, 0, true);568 {569 const events3 = await submitTransactionAsync(dorothyAccount, tx3);570 const result3 = getGenericResult(events3);571 expect(result3.success).to.be.true;572 }573 {574 const events3 = await submitTransactionAsync(baltatharAccount, tx3);575 const result3 = getGenericResult(events3);576 expect(result3.success).to.be.true;577 }578579 const tx4 = api.tx.councilCollective.close(motionHash, 0, 1_000_000_000, externalMotion.encodedLength);580 const events4 = await submitTransactionAsync(dorothyAccount, tx4);581 const result4 = getGenericResult(events4);582 expect(result4.success).to.be.true;583 console.log('Propose external motion through council.......DONE');584 // <<< Propose external motion through council <<<585586 // >>> Fast track proposal through technical committee >>>587 console.log('Fast track proposal through technical committee.......');588 const fastTrack = api.tx.democracy.fastTrack(proposalHash, votingPeriod, delayPeriod);589 const tx5 = api.tx.techCommitteeCollective.propose(590 technicalCommitteeThreshold,591 fastTrack,592 fastTrack.encodedLength,593 );594 const events5 = await submitTransactionAsync(alithAccount, tx5);595 const result5 = getGenericResult(events5);596 expect(result5.success).to.be.true;597598 const encodedFastTrack = fastTrack?.method.toHex() || '';599 const fastTrackHash = blake2AsHex(encodedFastTrack);600 console.log('FastTrack hash is %s', fastTrackHash);601602 const proposalIdx = Number(await api.query.techCommitteeCollective.proposalCount()) - 1;603 const tx6 = api.tx.techCommitteeCollective.vote(fastTrackHash, proposalIdx, true);604 {605 const events6 = await submitTransactionAsync(baltatharAccount, tx6);606 const result6 = getGenericResult(events6);607 expect(result6.success).to.be.true;608 }609 {610 const events6 = await submitTransactionAsync(alithAccount, tx6);611 const result6 = getGenericResult(events6);612 expect(result6.success).to.be.true;613 }614615 const tx7 = api.tx.techCommitteeCollective616 .close(fastTrackHash, proposalIdx, 1_000_000_000, fastTrack.encodedLength);617 const events7 = await submitTransactionAsync(baltatharAccount, tx7);618 const result7 = getGenericResult(events7);619 expect(result7.success).to.be.true;620 console.log('Fast track proposal through technical committee.......DONE');621 // <<< Fast track proposal through technical committee <<<622623 // >>> Referendum voting >>>624 console.log('Referendum voting.......');625 const tx8 = api.tx.democracy.vote(626 0,627 {Standard: {balance: 10_000_000_000_000_000_000n, vote: {aye: true, conviction: 1}}},628 );629 const events8 = await submitTransactionAsync(dorothyAccount, tx8);630 const result8 = getGenericResult(events8);631 expect(result8.success).to.be.true;632 console.log('Referendum voting.......DONE');633 // <<< Referendum voting <<<634635 // >>> Acquire Quartz AssetId Info on Moonriver >>>636 console.log('Acquire Quartz AssetId Info on Moonriver.......');637638 // Wait for the democracy execute639 await waitNewBlocks(api, 5);640641 assetId = (await api.query.assetManager.assetTypeId({642 XCM: sourceLocation,643 })).toString();644645 console.log('QTZ asset ID is %s', assetId);646 console.log('Acquire Quartz AssetId Info on Moonriver.......DONE');647 // >>> Acquire Quartz AssetId Info on Moonriver >>>648649 // >>> Sponsoring random Account >>>650 console.log('Sponsoring random Account.......');651 const tx10 = api.tx.balances.transfer(randomAccountMoonriver.address, 11_000_000_000_000_000_000n);652 const events10 = await submitTransactionAsync(baltatharAccount, tx10);653 const result10 = getGenericResult(events10);654 expect(result10.success).to.be.true;655 console.log('Sponsoring random Account.......DONE');656 // <<< Sponsoring random Account <<<657658 [balanceMovrTokenInit] = await getBalance(api, [randomAccountMoonriver.address]);659 },660 moonriverOptions(),661 );662663 await usingApi(async (api) => {664 const tx0 = api.tx.balances.transfer(randomAccountQuartz.address, 10n * TRANSFER_AMOUNT);665 const events0 = await submitTransactionAsync(quartzAlice, tx0);666 const result0 = getGenericResult(events0);667 expect(result0.success).to.be.true;668669 [balanceQuartzTokenInit] = await getBalance(api, [randomAccountQuartz.address]);670 });671 });672673 it('Should connect and send QTZ to Moonriver', async () => {674 await usingApi(async (api) => {675 const currencyId = {676 NativeAssetId: 'Here',677 };678 const dest = {679 V1: {680 parents: 1,681 interior: {682 X2: [683 {Parachain: MOONRIVER_CHAIN},684 {AccountKey20: {network: 'Any', key: randomAccountMoonriver.address}},685 ],686 },687 },688 };689 const amount = TRANSFER_AMOUNT;690 const destWeight = 850000000;691692 const tx = api.tx.xTokens.transfer(currencyId, amount, dest, destWeight);693 const events = await submitTransactionAsync(randomAccountQuartz, tx);694 const result = getGenericResult(events);695 expect(result.success).to.be.true;696697 [balanceQuartzTokenMiddle] = await getBalance(api, [randomAccountQuartz.address]);698 expect(balanceQuartzTokenMiddle < balanceQuartzTokenInit).to.be.true;699700 const transactionFees = balanceQuartzTokenInit - balanceQuartzTokenMiddle - TRANSFER_AMOUNT;701 console.log('[Quartz -> Moonriver] transaction fees on Quartz: %s QTZ', bigIntToDecimals(transactionFees));702 expect(transactionFees > 0).to.be.true;703 });704705 await usingApi(706 async (api) => {707 await waitNewBlocks(api, 3);708709 [balanceMovrTokenMiddle] = await getBalance(api, [randomAccountMoonriver.address]);710711 const movrFees = balanceMovrTokenInit - balanceMovrTokenMiddle;712 console.log('[Quartz -> Moonriver] transaction fees on Moonriver: %s MOVR',bigIntToDecimals(movrFees));713 expect(movrFees == 0n).to.be.true;714715 const qtzRandomAccountAsset = (716 await api.query.assets.account(assetId, randomAccountMoonriver.address)717 ).toJSON()! as any;718719 balanceForeignQtzTokenMiddle = BigInt(qtzRandomAccountAsset['balance']);720 const qtzIncomeTransfer = balanceForeignQtzTokenMiddle - balanceForeignQtzTokenInit;721 console.log('[Quartz -> Moonriver] income %s QTZ', bigIntToDecimals(qtzIncomeTransfer));722 expect(qtzIncomeTransfer == TRANSFER_AMOUNT).to.be.true;723 },724 moonriverOptions(),725 );726 });727728 it('Should connect to Moonriver and send QTZ back', async () => {729 await usingApi(730 async (api) => {731 const asset = {732 V1: {733 id: {734 Concrete: {735 parents: 1,736 interior: {737 X1: {Parachain: QUARTZ_CHAIN},738 },739 },740 },741 fun: {742 Fungible: TRANSFER_AMOUNT,743 },744 },745 };746 const destination = {747 V1: {748 parents: 1,749 interior: {750 X2: [751 {Parachain: QUARTZ_CHAIN},752 {AccountId32: {network: 'Any', id: randomAccountQuartz.addressRaw}},753 ],754 },755 },756 };757 const destWeight = 50000000;758759 const tx = api.tx.xTokens.transferMultiasset(asset, destination, destWeight);760 const events = await submitTransactionAsync(randomAccountMoonriver, tx);761 const result = getGenericResult(events);762 expect(result.success).to.be.true;763764 [balanceMovrTokenFinal] = await getBalance(api, [randomAccountMoonriver.address]);765766 const movrFees = balanceMovrTokenMiddle - balanceMovrTokenFinal;767 console.log('[Moonriver -> Quartz] transaction fees on Moonriver: %s MOVR', bigIntToDecimals(movrFees));768 expect(movrFees > 0).to.be.true;769770 const qtzRandomAccountAsset = (771 await api.query.assets.account(assetId, randomAccountMoonriver.address)772 ).toJSON()! as any;773774 expect(qtzRandomAccountAsset).to.be.null;775776 balanceForeignQtzTokenFinal = 0n;777778 const qtzOutcomeTransfer = balanceForeignQtzTokenMiddle - balanceForeignQtzTokenFinal;779 console.log('[Quartz -> Moonriver] outcome %s QTZ', bigIntToDecimals(qtzOutcomeTransfer));780 expect(qtzOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;781 },782 moonriverOptions(),783 );784785 await usingApi(async (api) => {786 await waitNewBlocks(api, 3);787788 [balanceQuartzTokenFinal] = await getBalance(api, [randomAccountQuartz.address]);789 const actuallyDelivered = balanceQuartzTokenFinal - balanceQuartzTokenMiddle;790 expect(actuallyDelivered > 0).to.be.true;791792 console.log('[Moonriver -> Quartz] actually delivered %s QTZ', bigIntToDecimals(actuallyDelivered));793794 const qtzFees = TRANSFER_AMOUNT - actuallyDelivered;795 console.log('[Moonriver -> Quartz] transaction fees on Quartz: %s QTZ', bigIntToDecimals(qtzFees));796 expect(qtzFees == 0n).to.be.true;797 });798 });799});tests/src/xcm/xcmUnique.test.tsdiffbeforeafterboth--- a/tests/src/xcm/xcmUnique.test.ts
+++ b/tests/src/xcm/xcmUnique.test.ts
@@ -77,8 +77,10 @@
before(async () => {
await usingApi(async (api, privateKeyWrapper) => {
+ const keyringSr25519 = new Keyring({type: 'sr25519'});
+
alice = privateKeyWrapper('//Alice');
- randomAccount = generateKeyringPair();
+ randomAccount = generateKeyringPair(keyringSr25519);
});
// Acala side
@@ -477,9 +479,12 @@
before(async () => {
await usingApi(async (api, privateKeyWrapper) => {
+ const keyringEth = new Keyring({type: 'ethereum'});
+ const keyringSr25519 = new Keyring({type: 'sr25519'});
+
uniqueAlice = privateKeyWrapper('//Alice');
- randomAccountUnique = generateKeyringPair();
- randomAccountMoonbeam = generateKeyringPair('ethereum');
+ randomAccountUnique = generateKeyringPair(keyringSr25519);
+ randomAccountMoonbeam = generateKeyringPair(keyringEth);
balanceForeignUnqTokenInit = 0n;
});