difftreelog
test statemine usdt exchange
in: master
4 files changed
tests/src/config.tsdiffbeforeafterboth--- a/tests/src/config.ts
+++ b/tests/src/config.ts
@@ -25,6 +25,8 @@
moonbeamUrl: process.env.moonbeamUrl || 'ws://127.0.0.1:9947',
moonriverUrl: process.env.moonbeamUrl || 'ws://127.0.0.1:9947',
westmintUrl: process.env.westmintUrl || 'ws://127.0.0.1:9948',
+ statemineUrl: process.env.statemineUrl || 'ws://127.0.0.1:9948',
+ statemintUrl: process.env.statemintUrl || 'ws://127.0.0.1:9948',
};
export default config;
tests/src/util/index.tsdiffbeforeafterboth--- a/tests/src/util/index.ts
+++ b/tests/src/util/index.ts
@@ -11,7 +11,7 @@
import config from '../config';
import {ChainHelperBase} from './playgrounds/unique';
import {ILogger} from './playgrounds/types';
-import {DevUniqueHelper, SilentLogger, SilentConsole, DevMoonbeamHelper, DevMoonriverHelper, DevAcalaHelper, DevKaruraHelper, DevRelayHelper, DevWestmintHelper} from './playgrounds/unique.dev';
+import {DevUniqueHelper, SilentLogger, SilentConsole, DevMoonbeamHelper, DevMoonriverHelper, DevAcalaHelper, DevKaruraHelper, DevRelayHelper, DevWestmintHelper, DevStatemineHelper, DevStatemintHelper} from './playgrounds/unique.dev';
chai.use(chaiAsPromised);
chai.use(chaiSubset);
@@ -65,6 +65,14 @@
return usingPlaygroundsGeneral<DevWestmintHelper>(DevWestmintHelper, url, code);
};
+export const usingStateminePlaygrounds = (url: string, code: (helper: DevWestmintHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => {
+ return usingPlaygroundsGeneral<DevStatemineHelper>(DevWestmintHelper, url, code);
+};
+
+export const usingStatemintPlaygrounds = (url: string, code: (helper: DevWestmintHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => {
+ return usingPlaygroundsGeneral<DevStatemintHelper>(DevWestmintHelper, url, code);
+};
+
export const usingRelayPlaygrounds = (url: string, code: (helper: DevRelayHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => {
return usingPlaygroundsGeneral<DevRelayHelper>(DevRelayHelper, url, code);
};
tests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth--- a/tests/src/util/playgrounds/unique.dev.ts
+++ b/tests/src/util/playgrounds/unique.dev.ts
@@ -131,6 +131,10 @@
}
}
+export class DevStatemineHelper extends DevWestmintHelper {}
+
+export class DevStatemintHelper extends DevWestmintHelper {}
+
export class DevMoonbeamHelper extends MoonbeamHelper {
account: MoonbeamAccountGroup;
wait: WaitGroup;
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 {IKeyringPair} from '@polkadot/types/types';18import {blake2AsHex} from '@polkadot/util-crypto';19import config from '../config';20import {XcmV2TraitsOutcome, XcmV2TraitsError} from '../interfaces';21import {itSub, expect, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds, usingRelayPlaygrounds, usingMoonriverPlaygrounds} from '../util';2223const QUARTZ_CHAIN = 2095;24const KARURA_CHAIN = 2000;25const MOONRIVER_CHAIN = 2023;2627const relayUrl = config.relayUrl;28const karuraUrl = config.karuraUrl;29const moonriverUrl = config.moonriverUrl;3031const KARURA_DECIMALS = 12;3233const TRANSFER_AMOUNT = 2000000000000000000000000n;3435describeXCM('[XCM] Integration test: Exchanging tokens with Karura', () => {36 let alice: IKeyringPair;37 let randomAccount: IKeyringPair;3839 let balanceQuartzTokenInit: bigint;40 let balanceQuartzTokenMiddle: bigint;41 let balanceQuartzTokenFinal: bigint;42 let balanceKaruraTokenInit: bigint;43 let balanceKaruraTokenMiddle: bigint;44 let balanceKaruraTokenFinal: bigint;45 let balanceQuartzForeignTokenInit: bigint;46 let balanceQuartzForeignTokenMiddle: bigint;47 let balanceQuartzForeignTokenFinal: bigint;4849 before(async () => {50 await usingPlaygrounds(async (helper, privateKey) => {51 alice = await privateKey('//Alice');52 [randomAccount] = await helper.arrange.createAccounts([0n], alice);53 });5455 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {56 const destination = {57 V0: {58 X2: [59 'Parent',60 {61 Parachain: QUARTZ_CHAIN,62 },63 ],64 },65 };6667 const metadata = {68 name: 'QTZ',69 symbol: 'QTZ',70 decimals: 18,71 minimalBalance: 1n,72 };7374 await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);75 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);76 balanceKaruraTokenInit = await helper.balance.getSubstrate(randomAccount.address);77 balanceQuartzForeignTokenInit = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});78 });7980 await usingPlaygrounds(async (helper) => {81 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10n * TRANSFER_AMOUNT);82 balanceQuartzTokenInit = await helper.balance.getSubstrate(randomAccount.address);83 });84 });8586 itSub('Should connect and send QTZ to Karura', async ({helper}) => {87 const destination = {88 V0: {89 X2: [90 'Parent',91 {92 Parachain: KARURA_CHAIN,93 },94 ],95 },96 };9798 const beneficiary = {99 V0: {100 X1: {101 AccountId32: {102 network: 'Any',103 id: randomAccount.addressRaw,104 },105 },106 },107 };108109 const assets = {110 V1: [111 {112 id: {113 Concrete: {114 parents: 0,115 interior: 'Here',116 },117 },118 fun: {119 Fungible: TRANSFER_AMOUNT,120 },121 },122 ],123 };124125 const feeAssetItem = 0;126 const weightLimit = 5000000000;127128 await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, weightLimit);129 balanceQuartzTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);130131 const qtzFees = balanceQuartzTokenInit - balanceQuartzTokenMiddle - TRANSFER_AMOUNT;132 console.log('[Quartz -> Karura] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(qtzFees));133 expect(qtzFees > 0n).to.be.true;134135 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {136 await helper.wait.newBlocks(3);137 balanceQuartzForeignTokenMiddle = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});138 balanceKaruraTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);139140 const karFees = balanceKaruraTokenInit - balanceKaruraTokenMiddle;141 const qtzIncomeTransfer = balanceQuartzForeignTokenMiddle - balanceQuartzForeignTokenInit;142143 console.log(144 '[Quartz -> Karura] transaction fees on Karura: %s KAR',145 helper.util.bigIntToDecimals(karFees, KARURA_DECIMALS),146 );147 console.log('[Quartz -> Karura] income %s QTZ', helper.util.bigIntToDecimals(qtzIncomeTransfer));148 expect(karFees == 0n).to.be.true;149 expect(qtzIncomeTransfer == TRANSFER_AMOUNT).to.be.true;150 });151 });152153 itSub('Should connect to Karura and send QTZ back', async ({helper}) => {154 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {155 const destination = {156 V1: {157 parents: 1,158 interior: {159 X2: [160 {Parachain: QUARTZ_CHAIN},161 {162 AccountId32: {163 network: 'Any',164 id: randomAccount.addressRaw,165 },166 },167 ],168 },169 },170 };171172 const id = {173 ForeignAsset: 0,174 };175176 const destWeight = 50000000;177178 await helper.xTokens.transfer(randomAccount, id, TRANSFER_AMOUNT, destination, destWeight);179 balanceKaruraTokenFinal = await helper.balance.getSubstrate(randomAccount.address);180 balanceQuartzForeignTokenFinal = await helper.tokens.accounts(randomAccount.address, id);181182 const karFees = balanceKaruraTokenMiddle - balanceKaruraTokenFinal;183 const qtzOutcomeTransfer = balanceQuartzForeignTokenMiddle - balanceQuartzForeignTokenFinal;184185 console.log(186 '[Karura -> Quartz] transaction fees on Karura: %s KAR',187 helper.util.bigIntToDecimals(karFees, KARURA_DECIMALS),188 );189 console.log('[Karura -> Quartz] outcome %s QTZ', helper.util.bigIntToDecimals(qtzOutcomeTransfer));190191 expect(karFees > 0).to.be.true;192 expect(qtzOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;193 });194195 await helper.wait.newBlocks(3);196197 balanceQuartzTokenFinal = await helper.balance.getSubstrate(randomAccount.address);198 const actuallyDelivered = balanceQuartzTokenFinal - balanceQuartzTokenMiddle;199 expect(actuallyDelivered > 0).to.be.true;200201 console.log('[Karura -> Quartz] actually delivered %s QTZ', helper.util.bigIntToDecimals(actuallyDelivered));202203 const qtzFees = TRANSFER_AMOUNT - actuallyDelivered;204 console.log('[Karura -> Quartz] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(qtzFees));205 expect(qtzFees == 0n).to.be.true;206 });207});208209// These tests are relevant only when the foreign asset pallet is disabled210describeXCM('[XCM] Integration test: Quartz rejects non-native tokens', () => {211 let alice: IKeyringPair;212213 before(async () => {214 await usingPlaygrounds(async (_helper, privateKey) => {215 alice = await privateKey('//Alice');216 });217 });218219 itSub('Quartz rejects tokens from the Relay', async ({helper}) => {220 await usingRelayPlaygrounds(relayUrl, async (helper) => {221 const destination = {222 V1: {223 parents: 0,224 interior: {X1: {225 Parachain: QUARTZ_CHAIN,226 },227 },228 }};229230 const beneficiary = {231 V1: {232 parents: 0,233 interior: {X1: {234 AccountId32: {235 network: 'Any',236 id: alice.addressRaw,237 },238 }},239 },240 };241242 const assets = {243 V1: [244 {245 id: {246 Concrete: {247 parents: 0,248 interior: 'Here',249 },250 },251 fun: {252 Fungible: 50_000_000_000_000_000n,253 },254 },255 ],256 };257258 const feeAssetItem = 0;259 const weightLimit = 5_000_000_000;260261 await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, weightLimit);262 });263264 const maxWaitBlocks = 3;265266 const dmpQueueExecutedDownward = await helper.wait.event(maxWaitBlocks, 'dmpQueue', 'ExecutedDownward');267268 expect(269 dmpQueueExecutedDownward != null,270 '[Relay] dmpQueue.ExecutedDownward event is expected',271 ).to.be.true;272273 const event = dmpQueueExecutedDownward!.event;274 const outcome = event.data[1] as XcmV2TraitsOutcome;275276 expect(277 outcome.isIncomplete,278 '[Relay] The outcome of the XCM should be `Incomplete`',279 ).to.be.true;280281 const incomplete = outcome.asIncomplete;282 expect(283 incomplete[1].toString() == 'AssetNotFound',284 '[Relay] The XCM error should be `AssetNotFound`',285 ).to.be.true;286 });287288 itSub('Quartz rejects KAR tokens from Karura', async ({helper}) => {289 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {290 const destination = {291 V1: {292 parents: 1,293 interior: {294 X2: [295 {Parachain: QUARTZ_CHAIN},296 {297 AccountId32: {298 network: 'Any',299 id: alice.addressRaw,300 },301 },302 ],303 },304 },305 };306307 const id = {308 Token: 'KAR',309 };310311 const destWeight = 50000000;312313 await helper.xTokens.transfer(alice, id, 100_000_000_000n, destination, destWeight);314 });315316 const maxWaitBlocks = 3;317318 const xcmpQueueFailEvent = await helper.wait.event(maxWaitBlocks, 'xcmpQueue', 'Fail');319320 expect(321 xcmpQueueFailEvent != null,322 '[Karura] xcmpQueue.FailEvent event is expected',323 ).to.be.true;324325 const event = xcmpQueueFailEvent!.event;326 const outcome = event.data[1] as XcmV2TraitsError;327328 expect(329 outcome.isUntrustedReserveLocation,330 '[Karura] The XCM error should be `UntrustedReserveLocation`',331 ).to.be.true;332 });333});334335describeXCM('[XCM] Integration test: Exchanging QTZ with Moonriver', () => {336 // Quartz constants337 let quartzDonor: IKeyringPair;338 let quartzAssetLocation;339340 let randomAccountQuartz: IKeyringPair;341 let randomAccountMoonriver: IKeyringPair;342343 // Moonriver constants344 let assetId: string;345346 const councilVotingThreshold = 2;347 const technicalCommitteeThreshold = 2;348 const votingPeriod = 3;349 const delayPeriod = 0;350351 const quartzAssetMetadata = {352 name: 'xcQuartz',353 symbol: 'xcQTZ',354 decimals: 18,355 isFrozen: false,356 minimalBalance: 1n,357 };358359 let balanceQuartzTokenInit: bigint;360 let balanceQuartzTokenMiddle: bigint;361 let balanceQuartzTokenFinal: bigint;362 let balanceForeignQtzTokenInit: bigint;363 let balanceForeignQtzTokenMiddle: bigint;364 let balanceForeignQtzTokenFinal: bigint;365 let balanceMovrTokenInit: bigint;366 let balanceMovrTokenMiddle: bigint;367 let balanceMovrTokenFinal: bigint;368369 before(async () => {370 await usingPlaygrounds(async (helper, privateKey) => {371 quartzDonor = await privateKey('//Alice');372 [randomAccountQuartz] = await helper.arrange.createAccounts([0n], quartzDonor);373374 balanceForeignQtzTokenInit = 0n;375 });376377 await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {378 const alithAccount = helper.account.alithAccount();379 const baltatharAccount = helper.account.baltatharAccount();380 const dorothyAccount = helper.account.dorothyAccount();381382 randomAccountMoonriver = helper.account.create();383384 // >>> Sponsoring Dorothy >>>385 console.log('Sponsoring Dorothy.......');386 await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);387 console.log('Sponsoring Dorothy.......DONE');388 // <<< Sponsoring Dorothy <<<389390 quartzAssetLocation = {391 XCM: {392 parents: 1,393 interior: {X1: {Parachain: QUARTZ_CHAIN}},394 },395 };396 const existentialDeposit = 1n;397 const isSufficient = true;398 const unitsPerSecond = 1n;399 const numAssetsWeightHint = 0;400401 const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({402 location: quartzAssetLocation,403 metadata: quartzAssetMetadata,404 existentialDeposit,405 isSufficient,406 unitsPerSecond,407 numAssetsWeightHint,408 });409 const proposalHash = blake2AsHex(encodedProposal);410411 console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);412 console.log('Encoded length %d', encodedProposal.length);413 console.log('Encoded proposal hash for batch utility after schedule is %s', proposalHash);414415 // >>> Note motion preimage >>>416 console.log('Note motion preimage.......');417 await helper.democracy.notePreimage(baltatharAccount, encodedProposal);418 console.log('Note motion preimage.......DONE');419 // <<< Note motion preimage <<<420421 // >>> Propose external motion through council >>>422 console.log('Propose external motion through council.......');423 const externalMotion = helper.democracy.externalProposeMajority(proposalHash);424 const encodedMotion = externalMotion?.method.toHex() || '';425 const motionHash = blake2AsHex(encodedMotion);426 console.log('Motion hash is %s', motionHash);427428 await helper.collective.council.propose(baltatharAccount, councilVotingThreshold, externalMotion, externalMotion.encodedLength);429430 const councilProposalIdx = await helper.collective.council.proposalCount() - 1;431 await helper.collective.council.vote(dorothyAccount, motionHash, councilProposalIdx, true);432 await helper.collective.council.vote(baltatharAccount, motionHash, councilProposalIdx, true);433434 await helper.collective.council.close(dorothyAccount, motionHash, councilProposalIdx, 1_000_000_000, externalMotion.encodedLength);435 console.log('Propose external motion through council.......DONE');436 // <<< Propose external motion through council <<<437438 // >>> Fast track proposal through technical committee >>>439 console.log('Fast track proposal through technical committee.......');440 const fastTrack = helper.democracy.fastTrack(proposalHash, votingPeriod, delayPeriod);441 const encodedFastTrack = fastTrack?.method.toHex() || '';442 const fastTrackHash = blake2AsHex(encodedFastTrack);443 console.log('FastTrack hash is %s', fastTrackHash);444445 await helper.collective.techCommittee.propose(alithAccount, technicalCommitteeThreshold, fastTrack, fastTrack.encodedLength);446447 const techProposalIdx = await helper.collective.techCommittee.proposalCount() - 1;448 await helper.collective.techCommittee.vote(baltatharAccount, fastTrackHash, techProposalIdx, true);449 await helper.collective.techCommittee.vote(alithAccount, fastTrackHash, techProposalIdx, true);450451 await helper.collective.techCommittee.close(baltatharAccount, fastTrackHash, techProposalIdx, 1_000_000_000, fastTrack.encodedLength);452 console.log('Fast track proposal through technical committee.......DONE');453 // <<< Fast track proposal through technical committee <<<454455 // >>> Referendum voting >>>456 console.log('Referendum voting.......');457 await helper.democracy.referendumVote(dorothyAccount, 0, {458 balance: 10_000_000_000_000_000_000n,459 vote: {aye: true, conviction: 1},460 });461 console.log('Referendum voting.......DONE');462 // <<< Referendum voting <<<463464 // >>> Acquire Quartz AssetId Info on Moonriver >>>465 console.log('Acquire Quartz AssetId Info on Moonriver.......');466467 // Wait for the democracy execute468 await helper.wait.newBlocks(5);469470 assetId = (await helper.assetManager.assetTypeId(quartzAssetLocation)).toString();471472 console.log('QTZ asset ID is %s', assetId);473 console.log('Acquire Quartz AssetId Info on Moonriver.......DONE');474 // >>> Acquire Quartz AssetId Info on Moonriver >>>475476 // >>> Sponsoring random Account >>>477 console.log('Sponsoring random Account.......');478 await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonriver.address, 11_000_000_000_000_000_000n);479 console.log('Sponsoring random Account.......DONE');480 // <<< Sponsoring random Account <<<481482 balanceMovrTokenInit = await helper.balance.getEthereum(randomAccountMoonriver.address);483 });484485 await usingPlaygrounds(async (helper) => {486 await helper.balance.transferToSubstrate(quartzDonor, randomAccountQuartz.address, 10n * TRANSFER_AMOUNT);487 balanceQuartzTokenInit = await helper.balance.getSubstrate(randomAccountQuartz.address);488 });489 });490491 itSub('Should connect and send QTZ to Moonriver', async ({helper}) => {492 const currencyId = {493 NativeAssetId: 'Here',494 };495 const dest = {496 V1: {497 parents: 1,498 interior: {499 X2: [500 {Parachain: MOONRIVER_CHAIN},501 {AccountKey20: {network: 'Any', key: randomAccountMoonriver.address}},502 ],503 },504 },505 };506 const amount = TRANSFER_AMOUNT;507 const destWeight = 850000000;508509 await helper.xTokens.transfer(randomAccountQuartz, currencyId, amount, dest, destWeight);510511 balanceQuartzTokenMiddle = await helper.balance.getSubstrate(randomAccountQuartz.address);512 expect(balanceQuartzTokenMiddle < balanceQuartzTokenInit).to.be.true;513514 const transactionFees = balanceQuartzTokenInit - balanceQuartzTokenMiddle - TRANSFER_AMOUNT;515 console.log('[Quartz -> Moonriver] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(transactionFees));516 expect(transactionFees > 0).to.be.true;517518 await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {519 await helper.wait.newBlocks(3);520521 balanceMovrTokenMiddle = await helper.balance.getEthereum(randomAccountMoonriver.address);522523 const movrFees = balanceMovrTokenInit - balanceMovrTokenMiddle;524 console.log('[Quartz -> Moonriver] transaction fees on Moonriver: %s MOVR',helper.util.bigIntToDecimals(movrFees));525 expect(movrFees == 0n).to.be.true;526527 balanceForeignQtzTokenMiddle = (await helper.assets.account(assetId, randomAccountMoonriver.address))!; // BigInt(qtzRandomAccountAsset['balance']);528 const qtzIncomeTransfer = balanceForeignQtzTokenMiddle - balanceForeignQtzTokenInit;529 console.log('[Quartz -> Moonriver] income %s QTZ', helper.util.bigIntToDecimals(qtzIncomeTransfer));530 expect(qtzIncomeTransfer == TRANSFER_AMOUNT).to.be.true;531 });532 });533534 itSub('Should connect to Moonriver and send QTZ back', async ({helper}) => {535 await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {536 const asset = {537 V1: {538 id: {539 Concrete: {540 parents: 1,541 interior: {542 X1: {Parachain: QUARTZ_CHAIN},543 },544 },545 },546 fun: {547 Fungible: TRANSFER_AMOUNT,548 },549 },550 };551 const destination = {552 V1: {553 parents: 1,554 interior: {555 X2: [556 {Parachain: QUARTZ_CHAIN},557 {AccountId32: {network: 'Any', id: randomAccountQuartz.addressRaw}},558 ],559 },560 },561 };562 const destWeight = 50000000;563564 await helper.xTokens.transferMultiasset(randomAccountMoonriver, asset, destination, destWeight);565566 balanceMovrTokenFinal = await helper.balance.getEthereum(randomAccountMoonriver.address);567568 const movrFees = balanceMovrTokenMiddle - balanceMovrTokenFinal;569 console.log('[Moonriver -> Quartz] transaction fees on Moonriver: %s MOVR', helper.util.bigIntToDecimals(movrFees));570 expect(movrFees > 0).to.be.true;571572 const qtzRandomAccountAsset = await helper.assets.account(assetId, randomAccountMoonriver.address);573574 expect(qtzRandomAccountAsset).to.be.null;575576 balanceForeignQtzTokenFinal = 0n;577578 const qtzOutcomeTransfer = balanceForeignQtzTokenMiddle - balanceForeignQtzTokenFinal;579 console.log('[Quartz -> Moonriver] outcome %s QTZ', helper.util.bigIntToDecimals(qtzOutcomeTransfer));580 expect(qtzOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;581 });582583 await helper.wait.newBlocks(3);584585 balanceQuartzTokenFinal = await helper.balance.getSubstrate(randomAccountQuartz.address);586 const actuallyDelivered = balanceQuartzTokenFinal - balanceQuartzTokenMiddle;587 expect(actuallyDelivered > 0).to.be.true;588589 console.log('[Moonriver -> Quartz] actually delivered %s QTZ', helper.util.bigIntToDecimals(actuallyDelivered));590591 const qtzFees = TRANSFER_AMOUNT - actuallyDelivered;592 console.log('[Moonriver -> Quartz] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(qtzFees));593 expect(qtzFees == 0n).to.be.true;594 });595});1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import {IKeyringPair} from '@polkadot/types/types';18import {blake2AsHex} from '@polkadot/util-crypto';19import config from '../config';20import {XcmV2TraitsOutcome, XcmV2TraitsError} from '../interfaces';21import {itSub, expect, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds, usingRelayPlaygrounds, usingMoonriverPlaygrounds, usingStateminePlaygrounds} from '../util';2223const QUARTZ_CHAIN = 2095;24const STATEMINE_CHAIN = 1000;25const KARURA_CHAIN = 2000;26const MOONRIVER_CHAIN = 2023;2728const STATEMINE_PALLET_INSTANCE = 50;2930const relayUrl = config.relayUrl;31const statemineUrl = config.statemineUrl;32const karuraUrl = config.karuraUrl;33const moonriverUrl = config.moonriverUrl;3435const STATEMINE_DECIMALS = 12;36const KARURA_DECIMALS = 12;3738const TRANSFER_AMOUNT = 2000000000000000000000000n;3940const USDT_ASSET_ID = 100;41const USDT_ASSET_METADATA_DECIMALS = 18;42const USDT_ASSET_METADATA_NAME = 'USDT';43const USDT_ASSET_METADATA_DESCRIPTION = 'USDT';44const USDT_ASSET_METADATA_MINIMAL_BALANCE = 1n;4546describeXCM('[XCM] Integration test: Exchanging USDT with Statemine', () => {47 let alice: IKeyringPair;48 let bob: IKeyringPair;49 50 let balanceStmnBefore: bigint;51 let balanceStmnAfter: bigint;5253 let balanceQuartzBefore: bigint;54 let balanceQuartzAfter: bigint;55 let balanceQuartzFinal: bigint;5657 let balanceBobBefore: bigint;58 let balanceBobAfter: bigint;59 let balanceBobFinal: bigint;6061 let balanceBobRelayTokenBefore: bigint;62 let balanceBobRelayTokenAfter: bigint;636465 before(async () => {66 await usingPlaygrounds(async (_helper, privateKey) => {67 alice = await privateKey('//Alice');68 bob = await privateKey('//Bob'); // funds donor69 });7071 await usingStateminePlaygrounds(statemineUrl, async (helper) => {72 // 350.00 (three hundred fifty) DOT73 const fundingAmount = 3_500_000_000_000n; 7475 await helper.assets.create(76 alice,77 USDT_ASSET_ID,78 alice.address,79 USDT_ASSET_METADATA_MINIMAL_BALANCE,80 );81 await helper.assets.setMetadata(82 alice,83 USDT_ASSET_ID,84 USDT_ASSET_METADATA_NAME,85 USDT_ASSET_METADATA_DESCRIPTION,86 USDT_ASSET_METADATA_DECIMALS,87 );88 await helper.assets.mint(89 alice,90 USDT_ASSET_ID,91 alice.address,92 TRANSFER_AMOUNT,93 );9495 // funding parachain sovereing account (Parachain: 2095)96 const parachainSovereingAccount = helper.address.paraSiblingSovereignAccount(QUARTZ_CHAIN);97 await helper.balance.transferToSubstrate(bob, parachainSovereingAccount, fundingAmount);98 });99100101 await usingPlaygrounds(async (helper) => {102 const location = {103 V1: {104 parents: 1,105 interior: {X3: [106 {107 Parachain: STATEMINE_CHAIN,108 },109 {110 PalletInstance: STATEMINE_PALLET_INSTANCE,111 },112 {113 GeneralIndex: USDT_ASSET_ID,114 },115 ]},116 },117 };118119 const metadata =120 {121 name: USDT_ASSET_ID,122 symbol: USDT_ASSET_METADATA_NAME,123 decimals: USDT_ASSET_METADATA_DECIMALS,124 minimalBalance: USDT_ASSET_METADATA_MINIMAL_BALANCE,125 };126 await helper.getSudo().foreignAssets.register(alice, alice.address, location, metadata);127 balanceQuartzBefore = await helper.balance.getSubstrate(alice.address);128 });129130131 // Providing the relay currency to the unique sender account132 await usingRelayPlaygrounds(relayUrl, async (helper) => {133 const destination = {134 V1: {135 parents: 0,136 interior: {X1: {137 Parachain: QUARTZ_CHAIN,138 },139 },140 }};141142 const beneficiary = {143 V1: {144 parents: 0,145 interior: {X1: {146 AccountId32: {147 network: 'Any',148 id: alice.addressRaw,149 },150 }},151 },152 };153154 const assets = {155 V1: [156 {157 id: {158 Concrete: {159 parents: 0,160 interior: 'Here',161 },162 },163 fun: {164 Fungible: TRANSFER_AMOUNT,165 },166 },167 ],168 };169170 const feeAssetItem = 0;171 const weightLimit = 5_000_000_000;172173 await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, weightLimit);174 });175 176 });177178 itSub('Should connect and send USDT from Statemine to Quartz', async ({helper}) => {179 await usingStateminePlaygrounds(statemineUrl, async (helper) => {180 const dest = {181 V1: {182 parents: 1,183 interior: {X1: {184 Parachain: QUARTZ_CHAIN,185 },186 },187 }};188189 const beneficiary = {190 V1: {191 parents: 0,192 interior: {X1: {193 AccountId32: {194 network: 'Any',195 id: alice.addressRaw,196 },197 }},198 },199 };200201 const assets = {202 V1: [203 {204 id: {205 Concrete: {206 parents: 0,207 interior: {208 X2: [209 {210 PalletInstance: STATEMINE_PALLET_INSTANCE,211 },212 {213 GeneralIndex: USDT_ASSET_ID,214 }, 215 ]},216 },217 },218 fun: {219 Fungible: TRANSFER_AMOUNT,220 },221 },222 ],223 };224225 const feeAssetItem = 0;226 const weightLimit = 5000000000;227228 balanceStmnBefore = await helper.balance.getSubstrate(alice.address);229 await helper.xcm.limitedReserveTransferAssets(alice, dest, beneficiary, assets, feeAssetItem, weightLimit);230231 balanceStmnAfter = await helper.balance.getSubstrate(alice.address);232233 // common good parachain take commission in it native token234 console.log(235 '[Quartz -> Statemine] transaction fees on Statemine: %s WND',236 helper.util.bigIntToDecimals(balanceStmnBefore - balanceStmnAfter, STATEMINE_DECIMALS),237 );238 expect(balanceStmnBefore > balanceStmnAfter).to.be.true;239240 });241242243 // ensure that asset has been delivered244 await helper.wait.newBlocks(3);245246 // expext collection id will be with id 1247 const free = await helper.ft.getBalance(1, {Substrate: alice.address});248249 balanceQuartzAfter = await helper.balance.getSubstrate(alice.address);250251 // commission has not paid in USDT token252 expect(free == TRANSFER_AMOUNT).to.be.true;253 console.log(254 '[Quartz -> Statemine] transaction fees on Quartz: %s USDT',255 helper.util.bigIntToDecimals(TRANSFER_AMOUNT - free),256 );257 // ... and parachain native token258 expect(balanceQuartzAfter == balanceQuartzBefore).to.be.true;259 console.log(260 '[Quartz -> Statemine] transaction fees on Quartz: %s WND',261 helper.util.bigIntToDecimals(balanceQuartzAfter - balanceQuartzBefore, STATEMINE_DECIMALS),262 ); 263 });264265 itSub('Should connect and send USDT from Quartz to Statemine back', async ({helper}) => {266 const destination = {267 V1: {268 parents: 1,269 interior: {X2: [270 {271 Parachain: STATEMINE_CHAIN,272 },273 {274 AccountId32: {275 network: 'Any',276 id: alice.addressRaw,277 },278 },279 ]},280 },281 };282283 const currencies: [any, bigint][] = [284 [285 {286 ForeignAssetId: 0,287 },288 //10_000_000_000_000_000n,289 TRANSFER_AMOUNT,290 ], 291 [292 {293 NativeAssetId: 'Parent',294 },295 400_000_000_000_000n,296 ],297 ];298299 const feeItem = 1;300 const destWeight = 500000000000;301302 await helper.xTokens.transferMulticurrencies(alice, currencies, feeItem, destination, destWeight);303 304 // the commission has been paid in parachain native token305 balanceQuartzFinal = await helper.balance.getSubstrate(alice.address);306 expect(balanceQuartzAfter > balanceQuartzFinal).to.be.true;307308 await usingStateminePlaygrounds(statemineUrl, async (helper) => {309 await helper.wait.newBlocks(3);310 311 // The USDT token never paid fees. Its amount not changed from begin value.312 // Also check that xcm transfer has been succeeded 313 expect((await helper.assets.account(USDT_ASSET_ID, alice.address))! == TRANSFER_AMOUNT).to.be.true;314 });315 });316317 itSub('Should connect and send Relay token to Quartz', async ({helper}) => {318 balanceBobBefore = await helper.balance.getSubstrate(bob.address);319 balanceBobRelayTokenBefore = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});320321 // Providing the relay currency to the unique sender account322 await usingRelayPlaygrounds(relayUrl, async (helper) => {323 const destination = {324 V1: {325 parents: 0,326 interior: {X1: {327 Parachain: QUARTZ_CHAIN,328 },329 },330 }};331332 const beneficiary = {333 V1: {334 parents: 0,335 interior: {X1: {336 AccountId32: {337 network: 'Any',338 id: bob.addressRaw,339 },340 }},341 },342 };343344 const assets = {345 V1: [346 {347 id: {348 Concrete: {349 parents: 0,350 interior: 'Here',351 },352 },353 fun: {354 Fungible: TRANSFER_AMOUNT,355 },356 },357 ],358 };359360 const feeAssetItem = 0;361 const weightLimit = 5_000_000_000;362363 await helper.xcm.limitedReserveTransferAssets(bob, destination, beneficiary, assets, feeAssetItem, weightLimit);364 });365 366 await helper.wait.newBlocks(3);367368 balanceBobAfter = await helper.balance.getSubstrate(bob.address); 369 balanceBobRelayTokenAfter = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});370371 const wndFee = balanceBobRelayTokenAfter - TRANSFER_AMOUNT - balanceBobRelayTokenBefore; 372 console.log(373 '[Relay (Westend) -> Quartz] transaction fees: %s QTZ',374 helper.util.bigIntToDecimals(balanceBobAfter - balanceBobBefore),375 );376 console.log(377 '[Relay (Westend) -> Quartz] transaction fees: %s WND',378 helper.util.bigIntToDecimals(wndFee, STATEMINE_DECIMALS),379 );380 expect(balanceBobBefore == balanceBobAfter).to.be.true;381 expect(balanceBobRelayTokenBefore < balanceBobRelayTokenAfter).to.be.true;382 });383384 itSub('Should connect and send Relay token back', async ({helper}) => {385 const destination = {386 V1: {387 parents: 1,388 interior: {X2: [389 {390 Parachain: STATEMINE_CHAIN,391 },392 {393 AccountId32: {394 network: 'Any',395 id: bob.addressRaw,396 },397 },398 ]},399 },400 };401402 const currencies: any = [403 [404 {405 NativeAssetId: 'Parent',406 },407 TRANSFER_AMOUNT,408 ],409 ];410411 const feeItem = 0;412 const destWeight = 500000000000;413414 await helper.xTokens.transferMulticurrencies(bob, currencies, feeItem, destination, destWeight);415416 balanceBobFinal = await helper.balance.getSubstrate(bob.address);417 console.log('[Relay (Westend) to Quartz] transaction fees: %s QTZ', balanceBobAfter - balanceBobFinal);418 });419});420421describeXCM('[XCM] Integration test: Exchanging tokens with Karura', () => {422 let alice: IKeyringPair;423 let randomAccount: IKeyringPair;424425 let balanceQuartzTokenInit: bigint;426 let balanceQuartzTokenMiddle: bigint;427 let balanceQuartzTokenFinal: bigint;428 let balanceKaruraTokenInit: bigint;429 let balanceKaruraTokenMiddle: bigint;430 let balanceKaruraTokenFinal: bigint;431 let balanceQuartzForeignTokenInit: bigint;432 let balanceQuartzForeignTokenMiddle: bigint;433 let balanceQuartzForeignTokenFinal: bigint;434435 before(async () => {436 await usingPlaygrounds(async (helper, privateKey) => {437 alice = await privateKey('//Alice');438 [randomAccount] = await helper.arrange.createAccounts([0n], alice);439 });440441 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {442 const destination = {443 V0: {444 X2: [445 'Parent',446 {447 Parachain: QUARTZ_CHAIN,448 },449 ],450 },451 };452453 const metadata = {454 name: 'QTZ',455 symbol: 'QTZ',456 decimals: 18,457 minimalBalance: 1n,458 };459460 await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);461 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);462 balanceKaruraTokenInit = await helper.balance.getSubstrate(randomAccount.address);463 balanceQuartzForeignTokenInit = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});464 });465466 await usingPlaygrounds(async (helper) => {467 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10n * TRANSFER_AMOUNT);468 balanceQuartzTokenInit = await helper.balance.getSubstrate(randomAccount.address);469 });470 });471472 itSub('Should connect and send QTZ to Karura', async ({helper}) => {473 const destination = {474 V0: {475 X2: [476 'Parent',477 {478 Parachain: KARURA_CHAIN,479 },480 ],481 },482 };483484 const beneficiary = {485 V0: {486 X1: {487 AccountId32: {488 network: 'Any',489 id: randomAccount.addressRaw,490 },491 },492 },493 };494495 const assets = {496 V1: [497 {498 id: {499 Concrete: {500 parents: 0,501 interior: 'Here',502 },503 },504 fun: {505 Fungible: TRANSFER_AMOUNT,506 },507 },508 ],509 };510511 const feeAssetItem = 0;512 const weightLimit = 5000000000;513514 await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, weightLimit);515 balanceQuartzTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);516517 const qtzFees = balanceQuartzTokenInit - balanceQuartzTokenMiddle - TRANSFER_AMOUNT;518 console.log('[Quartz -> Karura] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(qtzFees));519 expect(qtzFees > 0n).to.be.true;520521 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {522 await helper.wait.newBlocks(3);523 balanceQuartzForeignTokenMiddle = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});524 balanceKaruraTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);525526 const karFees = balanceKaruraTokenInit - balanceKaruraTokenMiddle;527 const qtzIncomeTransfer = balanceQuartzForeignTokenMiddle - balanceQuartzForeignTokenInit;528529 console.log(530 '[Quartz -> Karura] transaction fees on Karura: %s KAR',531 helper.util.bigIntToDecimals(karFees, KARURA_DECIMALS),532 );533 console.log('[Quartz -> Karura] income %s QTZ', helper.util.bigIntToDecimals(qtzIncomeTransfer));534 expect(karFees == 0n).to.be.true;535 expect(qtzIncomeTransfer == TRANSFER_AMOUNT).to.be.true;536 });537 });538539 itSub('Should connect to Karura and send QTZ back', async ({helper}) => {540 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {541 const destination = {542 V1: {543 parents: 1,544 interior: {545 X2: [546 {Parachain: QUARTZ_CHAIN},547 {548 AccountId32: {549 network: 'Any',550 id: randomAccount.addressRaw,551 },552 },553 ],554 },555 },556 };557558 const id = {559 ForeignAsset: 0,560 };561562 const destWeight = 50000000;563564 await helper.xTokens.transfer(randomAccount, id, TRANSFER_AMOUNT, destination, destWeight);565 balanceKaruraTokenFinal = await helper.balance.getSubstrate(randomAccount.address);566 balanceQuartzForeignTokenFinal = await helper.tokens.accounts(randomAccount.address, id);567568 const karFees = balanceKaruraTokenMiddle - balanceKaruraTokenFinal;569 const qtzOutcomeTransfer = balanceQuartzForeignTokenMiddle - balanceQuartzForeignTokenFinal;570571 console.log(572 '[Karura -> Quartz] transaction fees on Karura: %s KAR',573 helper.util.bigIntToDecimals(karFees, KARURA_DECIMALS),574 );575 console.log('[Karura -> Quartz] outcome %s QTZ', helper.util.bigIntToDecimals(qtzOutcomeTransfer));576577 expect(karFees > 0).to.be.true;578 expect(qtzOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;579 });580581 await helper.wait.newBlocks(3);582583 balanceQuartzTokenFinal = await helper.balance.getSubstrate(randomAccount.address);584 const actuallyDelivered = balanceQuartzTokenFinal - balanceQuartzTokenMiddle;585 expect(actuallyDelivered > 0).to.be.true;586587 console.log('[Karura -> Quartz] actually delivered %s QTZ', helper.util.bigIntToDecimals(actuallyDelivered));588589 const qtzFees = TRANSFER_AMOUNT - actuallyDelivered;590 console.log('[Karura -> Quartz] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(qtzFees));591 expect(qtzFees == 0n).to.be.true;592 });593});594595// These tests are relevant only when the foreign asset pallet is disabled596describeXCM('[XCM] Integration test: Quartz rejects non-native tokens', () => {597 let alice: IKeyringPair;598599 before(async () => {600 await usingPlaygrounds(async (_helper, privateKey) => {601 alice = await privateKey('//Alice');602 });603 });604605 itSub('Quartz rejects tokens from the Relay', async ({helper}) => {606 await usingRelayPlaygrounds(relayUrl, async (helper) => {607 const destination = {608 V1: {609 parents: 0,610 interior: {X1: {611 Parachain: QUARTZ_CHAIN,612 },613 },614 }};615616 const beneficiary = {617 V1: {618 parents: 0,619 interior: {X1: {620 AccountId32: {621 network: 'Any',622 id: alice.addressRaw,623 },624 }},625 },626 };627628 const assets = {629 V1: [630 {631 id: {632 Concrete: {633 parents: 0,634 interior: 'Here',635 },636 },637 fun: {638 Fungible: TRANSFER_AMOUNT,639 },640 },641 ],642 };643644 const feeAssetItem = 0;645 const weightLimit = 5_000_000_000;646647 await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, weightLimit);648 });649650 const maxWaitBlocks = 3;651652 const dmpQueueExecutedDownward = await helper.wait.event(maxWaitBlocks, 'dmpQueue', 'ExecutedDownward');653654 expect(655 dmpQueueExecutedDownward != null,656 '[Relay] dmpQueue.ExecutedDownward event is expected',657 ).to.be.true;658659 const event = dmpQueueExecutedDownward!.event;660 const outcome = event.data[1] as XcmV2TraitsOutcome;661662 expect(663 outcome.isIncomplete,664 '[Relay] The outcome of the XCM should be `Incomplete`',665 ).to.be.true;666667 const incomplete = outcome.asIncomplete;668 expect(669 incomplete[1].toString() == 'AssetNotFound',670 '[Relay] The XCM error should be `AssetNotFound`',671 ).to.be.true;672 });673674 itSub('Quartz rejects KAR tokens from Karura', async ({helper}) => {675 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {676 const destination = {677 V1: {678 parents: 1,679 interior: {680 X2: [681 {Parachain: QUARTZ_CHAIN},682 {683 AccountId32: {684 network: 'Any',685 id: alice.addressRaw,686 },687 },688 ],689 },690 },691 };692693 const id = {694 Token: 'KAR',695 };696697 const destWeight = 50000000;698699 await helper.xTokens.transfer(alice, id, 100_000_000_000n, destination, destWeight);700 });701702 const maxWaitBlocks = 3;703704 const xcmpQueueFailEvent = await helper.wait.event(maxWaitBlocks, 'xcmpQueue', 'Fail');705706 expect(707 xcmpQueueFailEvent != null,708 '[Karura] xcmpQueue.FailEvent event is expected',709 ).to.be.true;710711 const event = xcmpQueueFailEvent!.event;712 const outcome = event.data[1] as XcmV2TraitsError;713714 expect(715 outcome.isUntrustedReserveLocation,716 '[Karura] The XCM error should be `UntrustedReserveLocation`',717 ).to.be.true;718 });719});720721describeXCM('[XCM] Integration test: Exchanging QTZ with Moonriver', () => {722 // Quartz constants723 let quartzDonor: IKeyringPair;724 let quartzAssetLocation;725726 let randomAccountQuartz: IKeyringPair;727 let randomAccountMoonriver: IKeyringPair;728729 // Moonriver constants730 let assetId: string;731732 const councilVotingThreshold = 2;733 const technicalCommitteeThreshold = 2;734 const votingPeriod = 3;735 const delayPeriod = 0;736737 const quartzAssetMetadata = {738 name: 'xcQuartz',739 symbol: 'xcQTZ',740 decimals: 18,741 isFrozen: false,742 minimalBalance: 1n,743 };744745 let balanceQuartzTokenInit: bigint;746 let balanceQuartzTokenMiddle: bigint;747 let balanceQuartzTokenFinal: bigint;748 let balanceForeignQtzTokenInit: bigint;749 let balanceForeignQtzTokenMiddle: bigint;750 let balanceForeignQtzTokenFinal: bigint;751 let balanceMovrTokenInit: bigint;752 let balanceMovrTokenMiddle: bigint;753 let balanceMovrTokenFinal: bigint;754755 before(async () => {756 await usingPlaygrounds(async (helper, privateKey) => {757 quartzDonor = await privateKey('//Alice');758 [randomAccountQuartz] = await helper.arrange.createAccounts([0n], quartzDonor);759760 balanceForeignQtzTokenInit = 0n;761 });762763 await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {764 const alithAccount = helper.account.alithAccount();765 const baltatharAccount = helper.account.baltatharAccount();766 const dorothyAccount = helper.account.dorothyAccount();767768 randomAccountMoonriver = helper.account.create();769770 // >>> Sponsoring Dorothy >>>771 console.log('Sponsoring Dorothy.......');772 await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);773 console.log('Sponsoring Dorothy.......DONE');774 // <<< Sponsoring Dorothy <<<775776 quartzAssetLocation = {777 XCM: {778 parents: 1,779 interior: {X1: {Parachain: QUARTZ_CHAIN}},780 },781 };782 const existentialDeposit = 1n;783 const isSufficient = true;784 const unitsPerSecond = 1n;785 const numAssetsWeightHint = 0;786787 const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({788 location: quartzAssetLocation,789 metadata: quartzAssetMetadata,790 existentialDeposit,791 isSufficient,792 unitsPerSecond,793 numAssetsWeightHint,794 });795 const proposalHash = blake2AsHex(encodedProposal);796797 console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);798 console.log('Encoded length %d', encodedProposal.length);799 console.log('Encoded proposal hash for batch utility after schedule is %s', proposalHash);800801 // >>> Note motion preimage >>>802 console.log('Note motion preimage.......');803 await helper.democracy.notePreimage(baltatharAccount, encodedProposal);804 console.log('Note motion preimage.......DONE');805 // <<< Note motion preimage <<<806807 // >>> Propose external motion through council >>>808 console.log('Propose external motion through council.......');809 const externalMotion = helper.democracy.externalProposeMajority(proposalHash);810 const encodedMotion = externalMotion?.method.toHex() || '';811 const motionHash = blake2AsHex(encodedMotion);812 console.log('Motion hash is %s', motionHash);813814 await helper.collective.council.propose(baltatharAccount, councilVotingThreshold, externalMotion, externalMotion.encodedLength);815816 const councilProposalIdx = await helper.collective.council.proposalCount() - 1;817 await helper.collective.council.vote(dorothyAccount, motionHash, councilProposalIdx, true);818 await helper.collective.council.vote(baltatharAccount, motionHash, councilProposalIdx, true);819820 await helper.collective.council.close(dorothyAccount, motionHash, councilProposalIdx, 1_000_000_000, externalMotion.encodedLength);821 console.log('Propose external motion through council.......DONE');822 // <<< Propose external motion through council <<<823824 // >>> Fast track proposal through technical committee >>>825 console.log('Fast track proposal through technical committee.......');826 const fastTrack = helper.democracy.fastTrack(proposalHash, votingPeriod, delayPeriod);827 const encodedFastTrack = fastTrack?.method.toHex() || '';828 const fastTrackHash = blake2AsHex(encodedFastTrack);829 console.log('FastTrack hash is %s', fastTrackHash);830831 await helper.collective.techCommittee.propose(alithAccount, technicalCommitteeThreshold, fastTrack, fastTrack.encodedLength);832833 const techProposalIdx = await helper.collective.techCommittee.proposalCount() - 1;834 await helper.collective.techCommittee.vote(baltatharAccount, fastTrackHash, techProposalIdx, true);835 await helper.collective.techCommittee.vote(alithAccount, fastTrackHash, techProposalIdx, true);836837 await helper.collective.techCommittee.close(baltatharAccount, fastTrackHash, techProposalIdx, 1_000_000_000, fastTrack.encodedLength);838 console.log('Fast track proposal through technical committee.......DONE');839 // <<< Fast track proposal through technical committee <<<840841 // >>> Referendum voting >>>842 console.log('Referendum voting.......');843 await helper.democracy.referendumVote(dorothyAccount, 0, {844 balance: 10_000_000_000_000_000_000n,845 vote: {aye: true, conviction: 1},846 });847 console.log('Referendum voting.......DONE');848 // <<< Referendum voting <<<849850 // >>> Acquire Quartz AssetId Info on Moonriver >>>851 console.log('Acquire Quartz AssetId Info on Moonriver.......');852853 // Wait for the democracy execute854 await helper.wait.newBlocks(5);855856 assetId = (await helper.assetManager.assetTypeId(quartzAssetLocation)).toString();857858 console.log('QTZ asset ID is %s', assetId);859 console.log('Acquire Quartz AssetId Info on Moonriver.......DONE');860 // >>> Acquire Quartz AssetId Info on Moonriver >>>861862 // >>> Sponsoring random Account >>>863 console.log('Sponsoring random Account.......');864 await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonriver.address, 11_000_000_000_000_000_000n);865 console.log('Sponsoring random Account.......DONE');866 // <<< Sponsoring random Account <<<867868 balanceMovrTokenInit = await helper.balance.getEthereum(randomAccountMoonriver.address);869 });870871 await usingPlaygrounds(async (helper) => {872 await helper.balance.transferToSubstrate(quartzDonor, randomAccountQuartz.address, 10n * TRANSFER_AMOUNT);873 balanceQuartzTokenInit = await helper.balance.getSubstrate(randomAccountQuartz.address);874 });875 });876877 itSub('Should connect and send QTZ to Moonriver', async ({helper}) => {878 const currencyId = {879 NativeAssetId: 'Here',880 };881 const dest = {882 V1: {883 parents: 1,884 interior: {885 X2: [886 {Parachain: MOONRIVER_CHAIN},887 {AccountKey20: {network: 'Any', key: randomAccountMoonriver.address}},888 ],889 },890 },891 };892 const amount = TRANSFER_AMOUNT;893 const destWeight = 850000000;894895 await helper.xTokens.transfer(randomAccountQuartz, currencyId, amount, dest, destWeight);896897 balanceQuartzTokenMiddle = await helper.balance.getSubstrate(randomAccountQuartz.address);898 expect(balanceQuartzTokenMiddle < balanceQuartzTokenInit).to.be.true;899900 const transactionFees = balanceQuartzTokenInit - balanceQuartzTokenMiddle - TRANSFER_AMOUNT;901 console.log('[Quartz -> Moonriver] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(transactionFees));902 expect(transactionFees > 0).to.be.true;903904 await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {905 await helper.wait.newBlocks(3);906907 balanceMovrTokenMiddle = await helper.balance.getEthereum(randomAccountMoonriver.address);908909 const movrFees = balanceMovrTokenInit - balanceMovrTokenMiddle;910 console.log('[Quartz -> Moonriver] transaction fees on Moonriver: %s MOVR',helper.util.bigIntToDecimals(movrFees));911 expect(movrFees == 0n).to.be.true;912913 balanceForeignQtzTokenMiddle = (await helper.assets.account(assetId, randomAccountMoonriver.address))!; // BigInt(qtzRandomAccountAsset['balance']);914 const qtzIncomeTransfer = balanceForeignQtzTokenMiddle - balanceForeignQtzTokenInit;915 console.log('[Quartz -> Moonriver] income %s QTZ', helper.util.bigIntToDecimals(qtzIncomeTransfer));916 expect(qtzIncomeTransfer == TRANSFER_AMOUNT).to.be.true;917 });918 });919920 itSub('Should connect to Moonriver and send QTZ back', async ({helper}) => {921 await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {922 const asset = {923 V1: {924 id: {925 Concrete: {926 parents: 1,927 interior: {928 X1: {Parachain: QUARTZ_CHAIN},929 },930 },931 },932 fun: {933 Fungible: TRANSFER_AMOUNT,934 },935 },936 };937 const destination = {938 V1: {939 parents: 1,940 interior: {941 X2: [942 {Parachain: QUARTZ_CHAIN},943 {AccountId32: {network: 'Any', id: randomAccountQuartz.addressRaw}},944 ],945 },946 },947 };948 const destWeight = 50000000;949950 await helper.xTokens.transferMultiasset(randomAccountMoonriver, asset, destination, destWeight);951952 balanceMovrTokenFinal = await helper.balance.getEthereum(randomAccountMoonriver.address);953954 const movrFees = balanceMovrTokenMiddle - balanceMovrTokenFinal;955 console.log('[Moonriver -> Quartz] transaction fees on Moonriver: %s MOVR', helper.util.bigIntToDecimals(movrFees));956 expect(movrFees > 0).to.be.true;957958 const qtzRandomAccountAsset = await helper.assets.account(assetId, randomAccountMoonriver.address);959960 expect(qtzRandomAccountAsset).to.be.null;961962 balanceForeignQtzTokenFinal = 0n;963964 const qtzOutcomeTransfer = balanceForeignQtzTokenMiddle - balanceForeignQtzTokenFinal;965 console.log('[Quartz -> Moonriver] outcome %s QTZ', helper.util.bigIntToDecimals(qtzOutcomeTransfer));966 expect(qtzOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;967 });968969 await helper.wait.newBlocks(3);970971 balanceQuartzTokenFinal = await helper.balance.getSubstrate(randomAccountQuartz.address);972 const actuallyDelivered = balanceQuartzTokenFinal - balanceQuartzTokenMiddle;973 expect(actuallyDelivered > 0).to.be.true;974975 console.log('[Moonriver -> Quartz] actually delivered %s QTZ', helper.util.bigIntToDecimals(actuallyDelivered));976977 const qtzFees = TRANSFER_AMOUNT - actuallyDelivered;978 console.log('[Moonriver -> Quartz] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(qtzFees));979 expect(qtzFees == 0n).to.be.true;980 });981});