difftreelog
test(xcm) qtz xcm tests
in: master
2 files changed
tests/package.jsondiffbeforeafterboth1{2 "name": "unique-tests",3 "version": "1.0.0",4 "description": "Unique Chain Tests",5 "main": "",6 "devDependencies": {7 "@polkadot/ts": "0.4.22",8 "@polkadot/typegen": "9.2.2",9 "@types/chai": "^4.3.1",10 "@types/chai-as-promised": "^7.1.5",11 "@types/chai-like": "^1.1.1",12 "@types/mocha": "^9.1.1",13 "@types/node": "^17.0.35",14 "@typescript-eslint/eslint-plugin": "^5.26.0",15 "@typescript-eslint/parser": "^5.26.0",16 "chai": "^4.3.6",17 "eslint": "^8.16.0",18 "mocha": "^10.0.0",19 "ts-node": "^10.8.0",20 "typescript": "^4.7.2"21 },22 "mocha": {23 "timeout": 9999999,24 "require": "ts-node/register"25 },26 "scripts": {27 "lint": "eslint --ext .ts,.js src/",28 "fix": "eslint --ext .ts,.js src/ --fix",29 "test": "mocha --timeout 9999999 -r ts-node/register './src/**/*.test.ts'",30 "testEth": "mocha --timeout 9999999 -r ts-node/register './**/eth/**/*.test.ts'",31 "testEthMarketplace": "mocha --timeout 9999999 -r ts-node/register './**/eth/marketplace/**/*.test.ts'",32 "testEthNesting": "mocha --timeout 9999999 -r ts-node/register './**/eth/nesting/**/*.test.ts'",33 "load": "mocha --timeout 9999999 -r ts-node/register './**/*.load.ts'",34 "loadTransfer": "ts-node src/transfer.nload.ts",35 "testCollision": "mocha --timeout 9999999 -r ts-node/register ./src/collision-tests/*.test.ts",36 "testEvent": "mocha --timeout 9999999 -r ts-node/register ./src/check-event/*.test.ts",37 "testNesting": "mocha --timeout 9999999 -r ts-node/register ./**/nest.test.ts",38 "testUnnesting": "mocha --timeout 9999999 -r ts-node/register ./**/unnest.test.ts",39 "testStructure": "mocha --timeout 9999999 -r ts-node/register ./**/nesting/**.test.ts",40 "testProperties": "mocha --timeout 9999999 -r ts-node/register ./**/properties.test.ts",41 "testMigration": "mocha --timeout 9999999 -r ts-node/register ./**/nesting/migration-check.test.ts",42 "testRmrk": "mocha --timeout 9999999 -r ts-node/register ./**/rmrk/**.test.ts",43 "testAddCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/addCollectionAdmin.test.ts",44 "testSetSchemaVersion": "mocha --timeout 9999999 -r ts-node/register ./**/setSchemaVersion.test.ts",45 "testSetCollectionLimits": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionLimits.test.ts",46 "testSetCollectionSponsor": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionSponsor.test.ts",47 "testConfirmSponsorship": "mocha --timeout 9999999 -r ts-node/register ./**/confirmSponsorship.test.ts",48 "testRemoveCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/removeCollectionAdmin.test.ts",49 "testRemoveCollectionSponsor": "mocha --timeout 9999999 -r ts-node/register ./**/removeCollectionSponsor.test.ts",50 "testRemoveFromAllowList": "mocha --timeout 9999999 -r ts-node/register ./**/removeFromAllowList.test.ts",51 "testConnection": "mocha --timeout 9999999 -r ts-node/register ./**/connection.test.ts",52 "testContracts": "mocha --timeout 9999999 -r ts-node/register ./**/contracts.test.ts",53 "testCreateItem": "mocha --timeout 9999999 -r ts-node/register ./**/createItem.test.ts",54 "testCreateMultipleItems": "mocha --timeout 9999999 -r ts-node/register ./**/createMultipleItems.test.ts",55 "testCreateMultipleItemsEx": "mocha --timeout 9999999 -r ts-node/register ./**/createMultipleItemsEx.test.ts",56 "testApprove": "mocha --timeout 9999999 -r ts-node/register ./**/approve.test.ts",57 "testTransferFrom": "mocha --timeout 9999999 -r ts-node/register ./**/transferFrom.test.ts",58 "testCreateCollection": "mocha --timeout 9999999 -r ts-node/register ./**/createCollection.test.ts",59 "testDestroyCollection": "mocha --timeout 9999999 -r ts-node/register ./**/destroyCollection.test.ts",60 "testToggleContractAllowList": "mocha --timeout 9999999 -r ts-node/register ./**/toggleContractAllowList.test.ts",61 "testAddToContractAllowList": "mocha --timeout 9999999 -r ts-node/register ./**/addToContractAllowList.test.ts",62 "testTransfer": "mocha --timeout 9999999 -r ts-node/register ./**/transfer.test.ts",63 "testBurnItem": "mocha --timeout 9999999 -r ts-node/register ./**/burnItem.test.ts",64 "testAdminTransferAndBurn": "mocha --timeout 9999999 -r ts-node/register ./**/adminTransferAndBurn.test.ts",65 "testSetMintPermission": "mocha --timeout 9999999 -r ts-node/register ./**/setMintPermission.test.ts",66 "testCreditFeesToTreasury": "mocha --timeout 9999999 -r ts-node/register ./**/creditFeesToTreasury.test.ts",67 "testContractSponsoring": "mocha --timeout 9999999 -r ts-node/register ./**/contractSponsoring.test.ts",68 "testEnableContractSponsoring": "mocha --timeout 9999999 -r ts-node/register ./**/enableContractSponsoring.test.ts",69 "testRemoveFromContractAllowList": "mocha --timeout 9999999 -r ts-node/register ./**/removeFromContractAllowList.test.ts",70 "testSetContractSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setContractSponsoringRateLimit.test.ts",71 "testSetOffchainSchema": "mocha --timeout 9999999 -r ts-node/register ./**/setOffchainSchema.test.ts",72 "testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts",73 "testSetVariableMetadataSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetadataSponsoringRateLimit.test.ts",74 "testInflation": "mocha --timeout 9999999 -r ts-node/register ./**/inflation.test.ts",75 "testScheduler": "mocha --timeout 9999999 -r ts-node/register ./**/scheduler.test.ts",76 "testSchedulingEVM": "mocha --timeout 9999999 -r ts-node/register ./**/eth/scheduling.test.ts",77 "testXcmUnique": "RUN_XCM_TESTS=1 mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmUnique.test.ts",78 "testXcmOpal": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmOpal.test.ts",79 "testXcmTransferAcala": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferAcala.test.ts acalaId=2000 uniqueId=5000",80 "testXcmTransferStatemine": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferStatemine.test.ts statemineId=1000 uniqueId=5000",81 "testXcmTransferMoonbeam": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferMoonbeam.test.ts",82 "testPalletPresence": "mocha --timeout 9999999 -r ts-node/register ./**/pallet-presence.test.ts",83 "testBlockProduction": "mocha --timeout 9999999 -r ts-node/register ./**/block-production.test.ts",84 "testEnableDisableTransfers": "mocha --timeout 9999999 -r ts-node/register ./**/enableDisableTransfer.test.ts",85 "testLimits": "mocha --timeout 9999999 -r ts-node/register ./**/limits.test.ts",86 "testEthCreateCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createCollection.test.ts",87 "testRFT": "mocha --timeout 9999999 -r ts-node/register ./**/refungible.test.ts",88 "testFT": "mocha --timeout 9999999 -r ts-node/register ./**/fungible.test.ts",89 "testRPC": "mocha --timeout 9999999 -r ts-node/register ./**/rpc.test.ts",90 "polkadot-types-fetch-metadata": "curl -H 'Content-Type: application/json' -d '{\"id\":\"1\", \"jsonrpc\":\"2.0\", \"method\": \"state_getMetadata\", \"params\":[]}' http://localhost:9933 > src/interfaces/metadata.json",91 "polkadot-types-from-defs": "ts-node ./node_modules/.bin/polkadot-types-from-defs --endpoint src/interfaces/metadata.json --input src/interfaces/ --package .",92 "polkadot-types-from-chain": "ts-node ./node_modules/.bin/polkadot-types-from-chain --endpoint src/interfaces/metadata.json --output src/interfaces/ --package .",93 "polkadot-types": "echo \"export default {}\" > src/interfaces/lookup.ts && yarn polkadot-types-fetch-metadata && yarn polkadot-types-from-defs && yarn polkadot-types-from-defs && yarn polkadot-types-from-chain"94 },95 "author": "",96 "license": "SEE LICENSE IN ../LICENSE",97 "homepage": "",98 "dependencies": {99 "@polkadot/api": "9.2.2",100 "@polkadot/api-contract": "9.2.2",101 "@polkadot/util-crypto": "10.1.1",102 "bignumber.js": "^9.0.2",103 "chai-as-promised": "^7.1.1",104 "chai-like": "^1.1.1",105 "find-process": "^1.4.7",106 "solc": "0.8.14-fixed",107 "web3": "^1.7.3"108 },109 "standard": {110 "globals": [111 "it",112 "assert",113 "beforeEach",114 "afterEach",115 "describe",116 "contract",117 "artifacts"118 ]119 },120 "resolutions": {121 "simple-get": "^4.0.1"122 }123}1{2 "name": "unique-tests",3 "version": "1.0.0",4 "description": "Unique Chain Tests",5 "main": "",6 "devDependencies": {7 "@polkadot/ts": "0.4.22",8 "@polkadot/typegen": "9.2.2",9 "@types/chai": "^4.3.1",10 "@types/chai-as-promised": "^7.1.5",11 "@types/chai-like": "^1.1.1",12 "@types/mocha": "^9.1.1",13 "@types/node": "^17.0.35",14 "@typescript-eslint/eslint-plugin": "^5.26.0",15 "@typescript-eslint/parser": "^5.26.0",16 "chai": "^4.3.6",17 "eslint": "^8.16.0",18 "mocha": "^10.0.0",19 "ts-node": "^10.8.0",20 "typescript": "^4.7.2"21 },22 "mocha": {23 "timeout": 9999999,24 "require": "ts-node/register"25 },26 "scripts": {27 "lint": "eslint --ext .ts,.js src/",28 "fix": "eslint --ext .ts,.js src/ --fix",29 "test": "mocha --timeout 9999999 -r ts-node/register './src/**/*.test.ts'",30 "testEth": "mocha --timeout 9999999 -r ts-node/register './**/eth/**/*.test.ts'",31 "testEthMarketplace": "mocha --timeout 9999999 -r ts-node/register './**/eth/marketplace/**/*.test.ts'",32 "testEthNesting": "mocha --timeout 9999999 -r ts-node/register './**/eth/nesting/**/*.test.ts'",33 "load": "mocha --timeout 9999999 -r ts-node/register './**/*.load.ts'",34 "loadTransfer": "ts-node src/transfer.nload.ts",35 "testCollision": "mocha --timeout 9999999 -r ts-node/register ./src/collision-tests/*.test.ts",36 "testEvent": "mocha --timeout 9999999 -r ts-node/register ./src/check-event/*.test.ts",37 "testNesting": "mocha --timeout 9999999 -r ts-node/register ./**/nest.test.ts",38 "testUnnesting": "mocha --timeout 9999999 -r ts-node/register ./**/unnest.test.ts",39 "testStructure": "mocha --timeout 9999999 -r ts-node/register ./**/nesting/**.test.ts",40 "testProperties": "mocha --timeout 9999999 -r ts-node/register ./**/properties.test.ts",41 "testMigration": "mocha --timeout 9999999 -r ts-node/register ./**/nesting/migration-check.test.ts",42 "testRmrk": "mocha --timeout 9999999 -r ts-node/register ./**/rmrk/**.test.ts",43 "testAddCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/addCollectionAdmin.test.ts",44 "testSetSchemaVersion": "mocha --timeout 9999999 -r ts-node/register ./**/setSchemaVersion.test.ts",45 "testSetCollectionLimits": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionLimits.test.ts",46 "testSetCollectionSponsor": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionSponsor.test.ts",47 "testConfirmSponsorship": "mocha --timeout 9999999 -r ts-node/register ./**/confirmSponsorship.test.ts",48 "testRemoveCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/removeCollectionAdmin.test.ts",49 "testRemoveCollectionSponsor": "mocha --timeout 9999999 -r ts-node/register ./**/removeCollectionSponsor.test.ts",50 "testRemoveFromAllowList": "mocha --timeout 9999999 -r ts-node/register ./**/removeFromAllowList.test.ts",51 "testConnection": "mocha --timeout 9999999 -r ts-node/register ./**/connection.test.ts",52 "testContracts": "mocha --timeout 9999999 -r ts-node/register ./**/contracts.test.ts",53 "testCreateItem": "mocha --timeout 9999999 -r ts-node/register ./**/createItem.test.ts",54 "testCreateMultipleItems": "mocha --timeout 9999999 -r ts-node/register ./**/createMultipleItems.test.ts",55 "testCreateMultipleItemsEx": "mocha --timeout 9999999 -r ts-node/register ./**/createMultipleItemsEx.test.ts",56 "testApprove": "mocha --timeout 9999999 -r ts-node/register ./**/approve.test.ts",57 "testTransferFrom": "mocha --timeout 9999999 -r ts-node/register ./**/transferFrom.test.ts",58 "testCreateCollection": "mocha --timeout 9999999 -r ts-node/register ./**/createCollection.test.ts",59 "testDestroyCollection": "mocha --timeout 9999999 -r ts-node/register ./**/destroyCollection.test.ts",60 "testToggleContractAllowList": "mocha --timeout 9999999 -r ts-node/register ./**/toggleContractAllowList.test.ts",61 "testAddToContractAllowList": "mocha --timeout 9999999 -r ts-node/register ./**/addToContractAllowList.test.ts",62 "testTransfer": "mocha --timeout 9999999 -r ts-node/register ./**/transfer.test.ts",63 "testBurnItem": "mocha --timeout 9999999 -r ts-node/register ./**/burnItem.test.ts",64 "testAdminTransferAndBurn": "mocha --timeout 9999999 -r ts-node/register ./**/adminTransferAndBurn.test.ts",65 "testSetMintPermission": "mocha --timeout 9999999 -r ts-node/register ./**/setMintPermission.test.ts",66 "testCreditFeesToTreasury": "mocha --timeout 9999999 -r ts-node/register ./**/creditFeesToTreasury.test.ts",67 "testContractSponsoring": "mocha --timeout 9999999 -r ts-node/register ./**/contractSponsoring.test.ts",68 "testEnableContractSponsoring": "mocha --timeout 9999999 -r ts-node/register ./**/enableContractSponsoring.test.ts",69 "testRemoveFromContractAllowList": "mocha --timeout 9999999 -r ts-node/register ./**/removeFromContractAllowList.test.ts",70 "testSetContractSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setContractSponsoringRateLimit.test.ts",71 "testSetOffchainSchema": "mocha --timeout 9999999 -r ts-node/register ./**/setOffchainSchema.test.ts",72 "testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts",73 "testSetVariableMetadataSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetadataSponsoringRateLimit.test.ts",74 "testInflation": "mocha --timeout 9999999 -r ts-node/register ./**/inflation.test.ts",75 "testScheduler": "mocha --timeout 9999999 -r ts-node/register ./**/scheduler.test.ts",76 "testSchedulingEVM": "mocha --timeout 9999999 -r ts-node/register ./**/eth/scheduling.test.ts",77 "testXcmUnique": "RUN_XCM_TESTS=1 mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmUnique.test.ts",78 "testXcmQuartz": "RUN_XCM_TESTS=1 mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmQuartz.test.ts",79 "testXcmOpal": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmOpal.test.ts",80 "testXcmTransferAcala": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferAcala.test.ts acalaId=2000 uniqueId=5000",81 "testXcmTransferStatemine": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferStatemine.test.ts statemineId=1000 uniqueId=5000",82 "testXcmTransferMoonbeam": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferMoonbeam.test.ts",83 "testPalletPresence": "mocha --timeout 9999999 -r ts-node/register ./**/pallet-presence.test.ts",84 "testBlockProduction": "mocha --timeout 9999999 -r ts-node/register ./**/block-production.test.ts",85 "testEnableDisableTransfers": "mocha --timeout 9999999 -r ts-node/register ./**/enableDisableTransfer.test.ts",86 "testLimits": "mocha --timeout 9999999 -r ts-node/register ./**/limits.test.ts",87 "testEthCreateCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createCollection.test.ts",88 "testRFT": "mocha --timeout 9999999 -r ts-node/register ./**/refungible.test.ts",89 "testFT": "mocha --timeout 9999999 -r ts-node/register ./**/fungible.test.ts",90 "testRPC": "mocha --timeout 9999999 -r ts-node/register ./**/rpc.test.ts",91 "polkadot-types-fetch-metadata": "curl -H 'Content-Type: application/json' -d '{\"id\":\"1\", \"jsonrpc\":\"2.0\", \"method\": \"state_getMetadata\", \"params\":[]}' http://localhost:9933 > src/interfaces/metadata.json",92 "polkadot-types-from-defs": "ts-node ./node_modules/.bin/polkadot-types-from-defs --endpoint src/interfaces/metadata.json --input src/interfaces/ --package .",93 "polkadot-types-from-chain": "ts-node ./node_modules/.bin/polkadot-types-from-chain --endpoint src/interfaces/metadata.json --output src/interfaces/ --package .",94 "polkadot-types": "echo \"export default {}\" > src/interfaces/lookup.ts && yarn polkadot-types-fetch-metadata && yarn polkadot-types-from-defs && yarn polkadot-types-from-defs && yarn polkadot-types-from-chain"95 },96 "author": "",97 "license": "SEE LICENSE IN ../LICENSE",98 "homepage": "",99 "dependencies": {100 "@polkadot/api": "9.2.2",101 "@polkadot/api-contract": "9.2.2",102 "@polkadot/util-crypto": "10.1.1",103 "bignumber.js": "^9.0.2",104 "chai-as-promised": "^7.1.1",105 "chai-like": "^1.1.1",106 "find-process": "^1.4.7",107 "solc": "0.8.14-fixed",108 "web3": "^1.7.3"109 },110 "standard": {111 "globals": [112 "it",113 "assert",114 "beforeEach",115 "afterEach",116 "describe",117 "contract",118 "artifacts"119 ]120 },121 "resolutions": {122 "simple-get": "^4.0.1"123 }124}tests/src/xcm/xcmQuartz.test.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/xcm/xcmQuartz.test.ts
@@ -0,0 +1,682 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import chai from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+
+import {WsProvider, Keyring} from '@polkadot/api';
+import {ApiOptions} from '@polkadot/api/types';
+import {IKeyringPair} from '@polkadot/types/types';
+import usingApi, {submitTransactionAsync} from '../substrate/substrate-api';
+import {getGenericResult, generateKeyringPair, waitEvent, describe_xcm} from '../util/helpers';
+import {MultiLocation} from '@polkadot/types/interfaces';
+import {blake2AsHex} from '@polkadot/util-crypto';
+import waitNewBlocks from '../substrate/wait-new-blocks';
+import getBalance from '../substrate/get-balance';
+
+chai.use(chaiAsPromised);
+const expect = chai.expect;
+
+const QUARTZ_CHAIN = 2095;
+const KARURA_CHAIN = 2000;
+const MOONRIVER_CHAIN = 2023;
+
+const KARURA_PORT = 9946;
+const MOONRIVER_PORT = 9947;
+
+const TRANSFER_AMOUNT = 2000000000000000000000000n;
+
+function parachainApiOptions(port: number): ApiOptions {
+ return {
+ provider: new WsProvider('ws://127.0.0.1:' + port.toString()),
+ };
+}
+
+function karuraOptions(): ApiOptions {
+ return parachainApiOptions(KARURA_PORT);
+}
+
+function moonriverOptions(): ApiOptions {
+ return parachainApiOptions(MOONRIVER_PORT);
+}
+
+describe_xcm('Integration test: Exchanging tokens with Karura', () => {
+ let alice: IKeyringPair;
+ let randomAccount: IKeyringPair;
+
+ let balanceQuartzTokenInit: bigint;
+ let balanceQuartzTokenMiddle: bigint;
+ let balanceQuartzTokenFinal: bigint;
+ let balanceKaruraTokenInit: bigint;
+ let balanceKaruraTokenMiddle: bigint;
+ let balanceKaruraTokenFinal: bigint;
+ let balanceQuartzForeignTokenInit: bigint;
+ let balanceQuartzForeignTokenMiddle: bigint;
+ let balanceQuartzForeignTokenFinal: bigint;
+
+ before(async () => {
+ await usingApi(async (api, privateKeyWrapper) => {
+ alice = privateKeyWrapper('//Alice');
+ randomAccount = generateKeyringPair();
+ });
+
+ // Karura side
+ await usingApi(
+ async (api) => {
+ const destination = {
+ V0: {
+ X2: [
+ 'Parent',
+ {
+ Parachain: QUARTZ_CHAIN,
+ },
+ ],
+ },
+ };
+
+ const metadata = {
+ name: 'QTZ',
+ symbol: 'QTZ',
+ decimals: 18,
+ minimalBalance: 1,
+ };
+
+ const tx = api.tx.assetRegistry.registerForeignAsset(destination, metadata);
+ const sudoTx = api.tx.sudo.sudo(tx as any);
+ const events = await submitTransactionAsync(alice, sudoTx);
+ const result = getGenericResult(events);
+ expect(result.success).to.be.true;
+
+ const tx1 = api.tx.balances.transfer(randomAccount.address, 10000000000000n);
+ const events1 = await submitTransactionAsync(alice, tx1);
+ const result1 = getGenericResult(events1);
+ expect(result1.success).to.be.true;
+
+ [balanceKaruraTokenInit] = await getBalance(api, [randomAccount.address]);
+ {
+ const {free} = (await api.query.tokens.accounts(randomAccount.addressRaw, {ForeignAsset: 0})).toJSON() as any;
+ balanceQuartzForeignTokenInit = BigInt(free);
+ }
+ },
+ karuraOptions(),
+ );
+
+ // Quartz side
+ await usingApi(async (api) => {
+ const tx0 = api.tx.balances.transfer(randomAccount.address, 10n * TRANSFER_AMOUNT);
+ const events0 = await submitTransactionAsync(alice, tx0);
+ const result0 = getGenericResult(events0);
+ expect(result0.success).to.be.true;
+
+ [balanceQuartzTokenInit] = await getBalance(api, [randomAccount.address]);
+ });
+ });
+
+ it('Should connect and send QTZ to Karura', async () => {
+
+ // Quartz side
+ await usingApi(async (api) => {
+
+ const destination = {
+ V0: {
+ X2: [
+ 'Parent',
+ {
+ Parachain: KARURA_CHAIN,
+ },
+ ],
+ },
+ };
+
+ const beneficiary = {
+ V0: {
+ X1: {
+ AccountId32: {
+ network: 'Any',
+ id: randomAccount.addressRaw,
+ },
+ },
+ },
+ };
+
+ const assets = {
+ V1: [
+ {
+ id: {
+ Concrete: {
+ parents: 0,
+ interior: 'Here',
+ },
+ },
+ fun: {
+ Fungible: TRANSFER_AMOUNT,
+ },
+ },
+ ],
+ };
+
+ const feeAssetItem = 0;
+
+ const weightLimit = {
+ Limited: 5000000000,
+ };
+
+ const tx = api.tx.polkadotXcm.limitedReserveTransferAssets(destination, beneficiary, assets, feeAssetItem, weightLimit);
+ const events = await submitTransactionAsync(randomAccount, tx);
+ const result = getGenericResult(events);
+ expect(result.success).to.be.true;
+
+ [balanceQuartzTokenMiddle] = await getBalance(api, [randomAccount.address]);
+
+ const qtzFees = balanceQuartzTokenInit - balanceQuartzTokenMiddle - TRANSFER_AMOUNT;
+ console.log('[Quartz -> Karura] transaction fees on Quartz: %s QTZ', qtzFees);
+ expect(qtzFees > 0n).to.be.true;
+ });
+
+ // Karura side
+ await usingApi(
+ async (api) => {
+ await waitNewBlocks(api, 3);
+ const {free} = (await api.query.tokens.accounts(randomAccount.addressRaw, {ForeignAsset: 0})).toJSON() as any;
+ balanceQuartzForeignTokenMiddle = BigInt(free);
+
+ [balanceKaruraTokenMiddle] = await getBalance(api, [randomAccount.address]);
+
+ const karFees = balanceKaruraTokenInit - balanceKaruraTokenMiddle;
+ const qtzIncomeTransfer = balanceQuartzForeignTokenMiddle - balanceQuartzForeignTokenInit;
+
+ console.log('[Quartz -> Karura] transaction fees on Karura: %s KAR', karFees);
+ console.log('[Quartz -> Karura] income %s QTZ', qtzIncomeTransfer);
+ expect(karFees == 0n).to.be.true;
+ expect(qtzIncomeTransfer == TRANSFER_AMOUNT).to.be.true;
+ },
+ karuraOptions(),
+ );
+ });
+
+ it('Should connect to Karura and send QTZ back', async () => {
+
+ // Karura side
+ await usingApi(
+ async (api) => {
+ const destination = {
+ V1: {
+ parents: 1,
+ interior: {
+ X2: [
+ {Parachain: QUARTZ_CHAIN},
+ {
+ AccountId32: {
+ network: 'Any',
+ id: randomAccount.addressRaw,
+ },
+ },
+ ],
+ },
+ },
+ };
+
+ const id = {
+ ForeignAsset: 0,
+ };
+
+ const destWeight = 50000000;
+
+ const tx = api.tx.xTokens.transfer(id, TRANSFER_AMOUNT, destination, destWeight);
+ const events = await submitTransactionAsync(randomAccount, tx);
+ const result = getGenericResult(events);
+ expect(result.success).to.be.true;
+
+ [balanceKaruraTokenFinal] = await getBalance(api, [randomAccount.address]);
+ {
+ const {free} = (await api.query.tokens.accounts(randomAccount.addressRaw, {ForeignAsset: 0})).toJSON() as any;
+ balanceQuartzForeignTokenFinal = BigInt(free);
+ }
+
+ const karFees = balanceKaruraTokenMiddle - balanceKaruraTokenFinal;
+ const qtzOutcomeTransfer = balanceQuartzForeignTokenMiddle - balanceQuartzForeignTokenFinal;
+
+ console.log('[Karura -> Quartz] transaction fees on Karura: %s KAR', karFees);
+ console.log('[Karura -> Quartz] outcome %s QTZ', qtzOutcomeTransfer);
+
+ expect(karFees > 0).to.be.true;
+ expect(qtzOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;
+ },
+ karuraOptions(),
+ );
+
+ // Quartz side
+ await usingApi(async (api) => {
+ await waitNewBlocks(api, 3);
+
+ [balanceQuartzTokenFinal] = await getBalance(api, [randomAccount.address]);
+ const actuallyDelivered = balanceQuartzTokenFinal - balanceQuartzTokenMiddle;
+ expect(actuallyDelivered > 0).to.be.true;
+
+ console.log('[Karura -> Quartz] actually delivered %s QTZ', actuallyDelivered);
+
+ const qtzFees = TRANSFER_AMOUNT - actuallyDelivered;
+ console.log('[Karura -> Quartz] transaction fees on Quartz: %s QTZ', qtzFees);
+ expect(qtzFees == 0n).to.be.true;
+ });
+ });
+
+ it('Quartz rejects KAR tokens from Karura', async () => {
+ // This test is relevant only when the foreign asset pallet is disabled
+
+ await usingApi(async (api) => {
+ const destination = {
+ V1: {
+ parents: 1,
+ interior: {
+ X2: [
+ {Parachain: QUARTZ_CHAIN},
+ {
+ AccountId32: {
+ network: 'Any',
+ id: randomAccount.addressRaw,
+ },
+ },
+ ],
+ },
+ },
+ };
+
+ const id = {
+ Token: 'KAR',
+ };
+
+ const destWeight = 50000000;
+
+ const tx = api.tx.xTokens.transfer(id, 100_000_000_000, destination, destWeight);
+ const events = await submitTransactionAsync(alice, tx);
+ const result = getGenericResult(events);
+ expect(result.success).to.be.true;
+ }, karuraOptions());
+
+ await usingApi(async api => {
+ const maxWaitBlocks = 3;
+ const xcmpQueueFailEvent = await waitEvent(api, maxWaitBlocks, 'xcmpQueue', 'Fail');
+
+ expect(
+ xcmpQueueFailEvent != null,
+ 'Only native token is supported when the Foreign-Assets pallet is not connected',
+ ).to.be.true;
+ });
+ });
+});
+
+describe_xcm('Integration test: Exchanging QTZ with Moonriver', () => {
+
+ // Quartz constants
+ let quartzAlice: IKeyringPair;
+ let quartzAssetLocation;
+
+ let randomAccountQuartz: IKeyringPair;
+ let randomAccountMoonriver: IKeyringPair;
+
+ // Moonriver constants
+ let assetId: string;
+
+ const moonriverKeyring = new Keyring({type: 'ethereum'});
+ const alithPrivateKey = '0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133';
+ const baltatharPrivateKey = '0x8075991ce870b93a8870eca0c0f91913d12f47948ca0fd25b49c6fa7cdbeee8b';
+ const dorothyPrivateKey = '0x39539ab1876910bbf3a223d84a29e28f1cb4e2e456503e7e91ed39b2e7223d68';
+
+ const alithAccount = moonriverKeyring.addFromUri(alithPrivateKey, undefined, 'ethereum');
+ const baltatharAccount = moonriverKeyring.addFromUri(baltatharPrivateKey, undefined, 'ethereum');
+ const dorothyAccount = moonriverKeyring.addFromUri(dorothyPrivateKey, undefined, 'ethereum');
+
+ const councilVotingThreshold = 2;
+ const technicalCommitteeThreshold = 2;
+ const votingPeriod = 3;
+ const delayPeriod = 0;
+
+ const quartzAssetMetadata = {
+ name: 'xcQuartz',
+ symbol: 'xcQTZ',
+ decimals: 18,
+ isFrozen: false,
+ minimalBalance: 1,
+ };
+
+ let balanceQuartzTokenInit: bigint;
+ let balanceQuartzTokenMiddle: bigint;
+ let balanceQuartzTokenFinal: bigint;
+ let balanceForeignQtzTokenInit: bigint;
+ let balanceForeignQtzTokenMiddle: bigint;
+ let balanceForeignQtzTokenFinal: bigint;
+ let balanceMovrTokenInit: bigint;
+ let balanceMovrTokenMiddle: bigint;
+ let balanceMovrTokenFinal: bigint;
+
+ before(async () => {
+ await usingApi(async (api, privateKeyWrapper) => {
+ quartzAlice = privateKeyWrapper('//Alice');
+ randomAccountQuartz = generateKeyringPair();
+ randomAccountMoonriver = generateKeyringPair('ethereum');
+
+ balanceForeignQtzTokenInit = 0n;
+ });
+
+ await usingApi(
+ async (api) => {
+
+ // >>> Sponsoring Dorothy >>>
+ console.log('Sponsoring Dorothy.......');
+ const tx0 = api.tx.balances.transfer(dorothyAccount.address, 11_000_000_000_000_000_000n);
+ const events0 = await submitTransactionAsync(alithAccount, tx0);
+ const result0 = getGenericResult(events0);
+ expect(result0.success).to.be.true;
+ console.log('Sponsoring Dorothy.......DONE');
+ // <<< Sponsoring Dorothy <<<
+
+ const sourceLocation: MultiLocation = api.createType(
+ 'MultiLocation',
+ {
+ parents: 1,
+ interior: {X1: {Parachain: QUARTZ_CHAIN}},
+ },
+ );
+
+ quartzAssetLocation = {XCM: sourceLocation};
+ const existentialDeposit = 1;
+ const isSufficient = true;
+ const unitsPerSecond = '1';
+ const numAssetsWeightHint = 0;
+
+ const registerTx = api.tx.assetManager.registerForeignAsset(
+ quartzAssetLocation,
+ quartzAssetMetadata,
+ existentialDeposit,
+ isSufficient,
+ );
+ console.log('Encoded proposal for registerAsset is %s', registerTx.method.toHex() || '');
+
+ const setUnitsTx = api.tx.assetManager.setAssetUnitsPerSecond(
+ quartzAssetLocation,
+ unitsPerSecond,
+ numAssetsWeightHint,
+ );
+ console.log('Encoded proposal for setAssetUnitsPerSecond is %s', setUnitsTx.method.toHex() || '');
+
+ const batchCall = api.tx.utility.batchAll([registerTx, setUnitsTx]);
+ console.log('Encoded proposal for batchCall is %s', batchCall.method.toHex() || '');
+
+ // >>> Note motion preimage >>>
+ console.log('Note motion preimage.......');
+ const encodedProposal = batchCall?.method.toHex() || '';
+ const proposalHash = blake2AsHex(encodedProposal);
+ console.log('Encoded proposal for batch utility after schedule is %s', encodedProposal);
+ console.log('Encoded proposal hash for batch utility after schedule is %s', proposalHash);
+ console.log('Encoded length %d', encodedProposal.length);
+
+ const tx1 = api.tx.democracy.notePreimage(encodedProposal);
+ const events1 = await submitTransactionAsync(baltatharAccount, tx1);
+ const result1 = getGenericResult(events1);
+ expect(result1.success).to.be.true;
+ console.log('Note motion preimage.......DONE');
+ // <<< Note motion preimage <<<
+
+ // >>> Propose external motion through council >>>
+ console.log('Propose external motion through council.......');
+ const externalMotion = api.tx.democracy.externalProposeMajority(proposalHash);
+ const tx2 = api.tx.councilCollective.propose(
+ councilVotingThreshold,
+ externalMotion,
+ externalMotion.encodedLength,
+ );
+ const events2 = await submitTransactionAsync(baltatharAccount, tx2);
+ const result2 = getGenericResult(events2);
+ expect(result2.success).to.be.true;
+
+ const encodedMotion = externalMotion?.method.toHex() || '';
+ const motionHash = blake2AsHex(encodedMotion);
+ console.log('Motion hash is %s', motionHash);
+
+ const tx3 = api.tx.councilCollective.vote(motionHash, 0, true);
+ {
+ const events3 = await submitTransactionAsync(dorothyAccount, tx3);
+ const result3 = getGenericResult(events3);
+ expect(result3.success).to.be.true;
+ }
+ {
+ const events3 = await submitTransactionAsync(baltatharAccount, tx3);
+ const result3 = getGenericResult(events3);
+ expect(result3.success).to.be.true;
+ }
+
+ const tx4 = api.tx.councilCollective.close(motionHash, 0, 1_000_000_000, externalMotion.encodedLength);
+ const events4 = await submitTransactionAsync(dorothyAccount, tx4);
+ const result4 = getGenericResult(events4);
+ expect(result4.success).to.be.true;
+ console.log('Propose external motion through council.......DONE');
+ // <<< Propose external motion through council <<<
+
+ // >>> Fast track proposal through technical committee >>>
+ console.log('Fast track proposal through technical committee.......');
+ const fastTrack = api.tx.democracy.fastTrack(proposalHash, votingPeriod, delayPeriod);
+ const tx5 = api.tx.techCommitteeCollective.propose(
+ technicalCommitteeThreshold,
+ fastTrack,
+ fastTrack.encodedLength,
+ );
+ const events5 = await submitTransactionAsync(alithAccount, tx5);
+ const result5 = getGenericResult(events5);
+ expect(result5.success).to.be.true;
+
+ const encodedFastTrack = fastTrack?.method.toHex() || '';
+ const fastTrackHash = blake2AsHex(encodedFastTrack);
+ console.log('FastTrack hash is %s', fastTrackHash);
+
+ const proposalIdx = Number(await api.query.techCommitteeCollective.proposalCount()) - 1;
+ const tx6 = api.tx.techCommitteeCollective.vote(fastTrackHash, proposalIdx, true);
+ {
+ const events6 = await submitTransactionAsync(baltatharAccount, tx6);
+ const result6 = getGenericResult(events6);
+ expect(result6.success).to.be.true;
+ }
+ {
+ const events6 = await submitTransactionAsync(alithAccount, tx6);
+ const result6 = getGenericResult(events6);
+ expect(result6.success).to.be.true;
+ }
+
+ const tx7 = api.tx.techCommitteeCollective
+ .close(fastTrackHash, proposalIdx, 1_000_000_000, fastTrack.encodedLength);
+ const events7 = await submitTransactionAsync(baltatharAccount, tx7);
+ const result7 = getGenericResult(events7);
+ expect(result7.success).to.be.true;
+ console.log('Fast track proposal through technical committee.......DONE');
+ // <<< Fast track proposal through technical committee <<<
+
+ // >>> Referendum voting >>>
+ console.log('Referendum voting.......');
+ const tx8 = api.tx.democracy.vote(
+ 0,
+ {Standard: {balance: 10_000_000_000_000_000_000n, vote: {aye: true, conviction: 1}}},
+ );
+ const events8 = await submitTransactionAsync(dorothyAccount, tx8);
+ const result8 = getGenericResult(events8);
+ expect(result8.success).to.be.true;
+ console.log('Referendum voting.......DONE');
+ // <<< Referendum voting <<<
+
+ // >>> Acquire Quartz AssetId Info on Moonriver >>>
+ console.log('Acquire Quartz AssetId Info on Moonriver.......');
+
+ // Wait for the democracy execute
+ await waitNewBlocks(api, 5);
+
+ assetId = (await api.query.assetManager.assetTypeId({
+ XCM: sourceLocation,
+ })).toString();
+
+ console.log('QTZ asset ID is %s', assetId);
+ console.log('Acquire Quartz AssetId Info on Moonriver.......DONE');
+ // >>> Acquire Quartz AssetId Info on Moonriver >>>
+
+ // >>> Sponsoring random Account >>>
+ console.log('Sponsoring random Account.......');
+ const tx10 = api.tx.balances.transfer(randomAccountMoonriver.address, 11_000_000_000_000_000_000n);
+ const events10 = await submitTransactionAsync(baltatharAccount, tx10);
+ const result10 = getGenericResult(events10);
+ expect(result10.success).to.be.true;
+ console.log('Sponsoring random Account.......DONE');
+ // <<< Sponsoring random Account <<<
+
+ [balanceMovrTokenInit] = await getBalance(api, [randomAccountMoonriver.address]);
+ },
+ moonriverOptions(),
+ );
+
+ await usingApi(async (api) => {
+ const tx0 = api.tx.balances.transfer(randomAccountQuartz.address, 10n * TRANSFER_AMOUNT);
+ const events0 = await submitTransactionAsync(quartzAlice, tx0);
+ const result0 = getGenericResult(events0);
+ expect(result0.success).to.be.true;
+
+ [balanceQuartzTokenInit] = await getBalance(api, [randomAccountQuartz.address]);
+ });
+ });
+
+ it('Should connect and send QTZ to Moonriver', async () => {
+ await usingApi(async (api) => {
+ const currencyId = {
+ NativeAssetId: 'Here',
+ };
+ const dest = {
+ V1: {
+ parents: 1,
+ interior: {
+ X2: [
+ {Parachain: MOONRIVER_CHAIN},
+ {AccountKey20: {network: 'Any', key: randomAccountMoonriver.address}},
+ ],
+ },
+ },
+ };
+ const amount = TRANSFER_AMOUNT;
+ const destWeight = 850000000;
+
+ const tx = api.tx.xTokens.transfer(currencyId, amount, dest, destWeight);
+ const events = await submitTransactionAsync(randomAccountQuartz, tx);
+ const result = getGenericResult(events);
+ expect(result.success).to.be.true;
+
+ [balanceQuartzTokenMiddle] = await getBalance(api, [randomAccountQuartz.address]);
+ expect(balanceQuartzTokenMiddle < balanceQuartzTokenInit).to.be.true;
+
+ const transactionFees = balanceQuartzTokenInit - balanceQuartzTokenMiddle - TRANSFER_AMOUNT;
+ console.log('[Quartz -> Moonriver] transaction fees on Quartz: %s QTZ', transactionFees);
+ expect(transactionFees > 0).to.be.true;
+ });
+
+ await usingApi(
+ async (api) => {
+ await waitNewBlocks(api, 3);
+
+ [balanceMovrTokenMiddle] = await getBalance(api, [randomAccountMoonriver.address]);
+
+ const movrFees = balanceMovrTokenInit - balanceMovrTokenMiddle;
+ console.log('[Quartz -> Moonriver] transaction fees on Moonriver: %s MOVR', movrFees);
+ expect(movrFees == 0n).to.be.true;
+
+ const qtzRandomAccountAsset = (
+ await api.query.assets.account(assetId, randomAccountMoonriver.address)
+ ).toJSON()! as any;
+
+ balanceForeignQtzTokenMiddle = BigInt(qtzRandomAccountAsset['balance']);
+ const qtzIncomeTransfer = balanceForeignQtzTokenMiddle - balanceForeignQtzTokenInit;
+ console.log('[Quartz -> Moonriver] income %s QTZ', qtzIncomeTransfer);
+ expect(qtzIncomeTransfer == TRANSFER_AMOUNT).to.be.true;
+ },
+ moonriverOptions(),
+ );
+ });
+
+ it('Should connect to Moonriver and send QTZ back', async () => {
+ await usingApi(
+ async (api) => {
+ const asset = {
+ V1: {
+ id: {
+ Concrete: {
+ parents: 1,
+ interior: {
+ X1: {Parachain: QUARTZ_CHAIN},
+ },
+ },
+ },
+ fun: {
+ Fungible: TRANSFER_AMOUNT,
+ },
+ },
+ };
+ const destination = {
+ V1: {
+ parents: 1,
+ interior: {
+ X2: [
+ {Parachain: QUARTZ_CHAIN},
+ {AccountId32: {network: 'Any', id: randomAccountQuartz.addressRaw}},
+ ],
+ },
+ },
+ };
+ const destWeight = 50000000;
+
+ const tx = api.tx.xTokens.transferMultiasset(asset, destination, destWeight);
+ const events = await submitTransactionAsync(randomAccountMoonriver, tx);
+ const result = getGenericResult(events);
+ expect(result.success).to.be.true;
+
+ [balanceMovrTokenFinal] = await getBalance(api, [randomAccountMoonriver.address]);
+
+ const movrFees = balanceMovrTokenMiddle - balanceMovrTokenFinal;
+ console.log('[Moonriver -> Quartz] transaction fees on Moonriver: %s MOVR', movrFees);
+ expect(movrFees > 0).to.be.true;
+
+ const qtzRandomAccountAsset = (
+ await api.query.assets.account(assetId, randomAccountMoonriver.address)
+ ).toJSON()! as any;
+
+ expect(qtzRandomAccountAsset).to.be.null;
+
+ balanceForeignQtzTokenFinal = 0n;
+
+ const qtzOutcomeTransfer = balanceForeignQtzTokenMiddle - balanceForeignQtzTokenFinal;
+ console.log('[Quartz -> Moonriver] outcome %s QTZ', qtzOutcomeTransfer);
+ expect(qtzOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;
+ },
+ moonriverOptions(),
+ );
+
+ await usingApi(async (api) => {
+ await waitNewBlocks(api, 3);
+
+ [balanceQuartzTokenFinal] = await getBalance(api, [randomAccountQuartz.address]);
+ const actuallyDelivered = balanceQuartzTokenFinal - balanceQuartzTokenMiddle;
+ expect(actuallyDelivered > 0).to.be.true;
+
+ console.log('[Moonriver -> Quartz] actually delivered %s QTZ', actuallyDelivered);
+
+ const qtzFees = TRANSFER_AMOUNT - actuallyDelivered;
+ console.log('[Moonriver -> Quartz] transaction fees on Quartz: %s QTZ', qtzFees);
+ expect(qtzFees == 0n).to.be.true;
+ });
+ });
+});