git.delta.rocks / unique-network / refs/commits / ceb84596992e

difftreelog

Merge pull request #801 from UniqueNetwork/fix/xcm-qtz-unq-tests

Yaroslav Bolyukin2022-12-22parents: #b9448b5 #3e66406.patch.diff
in: master
Fix xcm

10 files changed

modifiedpallets/foreign-assets/src/lib.rsdiffbeforeafterboth
161161
162 fn get_currency_id(multi_location: MultiLocation) -> Option<CurrencyId> {162 fn get_currency_id(multi_location: MultiLocation) -> Option<CurrencyId> {
163 log::trace!(target: "fassets::get_currency_id", "call");163 log::trace!(target: "fassets::get_currency_id", "call");
164 Some(AssetIds::ForeignAssetId(
165 Pallet::<T>::location_to_currency_ids(multi_location).unwrap_or(0),164 Pallet::<T>::location_to_currency_ids(multi_location).map(|id| AssetIds::ForeignAssetId(id))
166 ))
167 }165 }
168}166}
169167
modifiedruntime/common/config/xcm/foreignassets.rsdiffbeforeafterboth
18 traits::{Contains, Get, fungibles},18 traits::{Contains, Get, fungibles},
19 parameter_types,19 parameter_types,
20};20};
21use sp_runtime::traits::{Zero, Convert};21use sp_runtime::traits::Convert;
22use xcm::v1::{Junction::*, MultiLocation, Junctions::*};22use xcm::v1::{Junction::*, MultiLocation, Junctions::*};
23use xcm::latest::MultiAsset;23use xcm::latest::MultiAsset;
24use xcm_builder::{FungiblesAdapter, ConvertedConcreteAssetId};24use xcm_builder::{FungiblesAdapter, ConvertedConcreteAssetId};
38 pub CheckingAccount: AccountId = PolkadotXcm::check_account();38 pub CheckingAccount: AccountId = PolkadotXcm::check_account();
39}39}
4040
41/// Allow checking in assets that have issuance > 0.41/// No teleports are allowed
42pub struct NonZeroIssuance<AccountId, ForeignAssets>(PhantomData<(AccountId, ForeignAssets)>);42pub struct NoTeleports<AccountId, ForeignAssets>(PhantomData<(AccountId, ForeignAssets)>);
4343
44impl<AccountId, ForeignAssets> Contains<<ForeignAssets as fungibles::Inspect<AccountId>>::AssetId>44impl<AccountId, ForeignAssets> Contains<<ForeignAssets as fungibles::Inspect<AccountId>>::AssetId>
45 for NonZeroIssuance<AccountId, ForeignAssets>45 for NoTeleports<AccountId, ForeignAssets>
46where46where
47 ForeignAssets: fungibles::Inspect<AccountId>,47 ForeignAssets: fungibles::Inspect<AccountId>,
48{48{
49 fn contains(id: &<ForeignAssets as fungibles::Inspect<AccountId>>::AssetId) -> bool {49 fn contains(_id: &<ForeignAssets as fungibles::Inspect<AccountId>>::AssetId) -> bool {
50 !ForeignAssets::total_issuance(*id).is_zero()50 false
51 }51 }
52}52}
5353
84 Some(AssetIds::ForeignAssetId(foreign_asset_id)) => {84 Some(AssetIds::ForeignAssetId(foreign_asset_id)) => {
85 ConvertAssetId::convert_ref(AssetIds::ForeignAssetId(foreign_asset_id))85 ConvertAssetId::convert_ref(AssetIds::ForeignAssetId(foreign_asset_id))
86 }86 }
87 _ => ConvertAssetId::convert_ref(AssetIds::ForeignAssetId(0)),87 _ => Err(()),
88 }88 }
89 }89 }
9090
132 LocationToAccountId,132 LocationToAccountId,
133 // Our chain's account ID type (we can't get away without mentioning it explicitly):133 // Our chain's account ID type (we can't get away without mentioning it explicitly):
134 AccountId,134 AccountId,
135 // We only want to allow teleports of known assets. We use non-zero issuance as an indication135 // No teleports are allowed
136 // that this asset is known.
137 NonZeroIssuance<AccountId, ForeignAssets>,136 NoTeleports<AccountId, ForeignAssets>,
138 // The account to use for tracking teleports.137 // The account to use for tracking teleports.
139 CheckingAccount,138 CheckingAccount,
140>;139>;
modifiedruntime/common/config/xcm/mod.rsdiffbeforeafterboth
186 TransferReserveAsset { dest: dst, .. } => {186 TransferReserveAsset { dest: dst, .. } => {
187 allowed |= allowed_locations.contains(dst);187 allowed |= allowed_locations.contains(dst);
188 }188 }
189 InitiateReserveWithdraw { reserve: dst, .. } => {
190 allowed |= allowed_locations.contains(dst);
191 }
189 _ => {}192 _ => {}
190 });193 });
191194
modifiedtests/src/config.tsdiffbeforeafterboth
25 moonbeamUrl: process.env.moonbeamUrl || 'ws://127.0.0.1:9947',25 moonbeamUrl: process.env.moonbeamUrl || 'ws://127.0.0.1:9947',
26 moonriverUrl: process.env.moonbeamUrl || 'ws://127.0.0.1:9947',26 moonriverUrl: process.env.moonbeamUrl || 'ws://127.0.0.1:9947',
27 westmintUrl: process.env.westmintUrl || 'ws://127.0.0.1:9948',27 westmintUrl: process.env.westmintUrl || 'ws://127.0.0.1:9948',
28 statemineUrl: process.env.statemineUrl || 'ws://127.0.0.1:9948',
29 statemintUrl: process.env.statemintUrl || 'ws://127.0.0.1:9948',
28};30};
2931
30export default config;32export default config;
modifiedtests/src/util/index.tsdiffbeforeafterboth
11import config from '../config';11import config from '../config';
12import {ChainHelperBase} from './playgrounds/unique';12import {ChainHelperBase} from './playgrounds/unique';
13import {ILogger} from './playgrounds/types';13import {ILogger} from './playgrounds/types';
14import {DevUniqueHelper, SilentLogger, SilentConsole, DevMoonbeamHelper, DevMoonriverHelper, DevAcalaHelper, DevKaruraHelper, DevRelayHelper, DevWestmintHelper} from './playgrounds/unique.dev';14import {DevUniqueHelper, SilentLogger, SilentConsole, DevMoonbeamHelper, DevMoonriverHelper, DevAcalaHelper, DevKaruraHelper, DevRelayHelper, DevWestmintHelper, DevStatemineHelper, DevStatemintHelper} from './playgrounds/unique.dev';
1515
16chai.use(chaiAsPromised);16chai.use(chaiAsPromised);
17chai.use(chaiSubset);17chai.use(chaiSubset);
65 return usingPlaygroundsGeneral<DevWestmintHelper>(DevWestmintHelper, url, code);65 return usingPlaygroundsGeneral<DevWestmintHelper>(DevWestmintHelper, url, code);
66};66};
67
68export const usingStateminePlaygrounds = (url: string, code: (helper: DevWestmintHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => {
69 return usingPlaygroundsGeneral<DevStatemineHelper>(DevWestmintHelper, url, code);
70};
71
72export const usingStatemintPlaygrounds = (url: string, code: (helper: DevWestmintHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => {
73 return usingPlaygroundsGeneral<DevStatemintHelper>(DevWestmintHelper, url, code);
74};
6775
68export const usingRelayPlaygrounds = (url: string, code: (helper: DevRelayHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => {76export const usingRelayPlaygrounds = (url: string, code: (helper: DevRelayHelper, privateKey: (seed: string) => Promise<IKeyringPair>) => Promise<void>) => {
69 return usingPlaygroundsGeneral<DevRelayHelper>(DevRelayHelper, url, code);77 return usingPlaygroundsGeneral<DevRelayHelper>(DevRelayHelper, url, code);
modifiedtests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth
119}119}
120120
121export class DevRelayHelper extends RelayHelper {}121export class DevRelayHelper extends RelayHelper {
122 wait: WaitGroup;
123
124 constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
125 options.helperBase = options.helperBase ?? DevRelayHelper;
126
127 super(logger, options);
128 this.wait = new WaitGroup(this);
129 }
130}
122131
123export class DevWestmintHelper extends WestmintHelper {132export class DevWestmintHelper extends WestmintHelper {
131 }140 }
132}141}
142
143export class DevStatemineHelper extends DevWestmintHelper {}
144
145export class DevStatemintHelper extends DevWestmintHelper {}
133146
134export class DevMoonbeamHelper extends MoonbeamHelper {147export class DevMoonbeamHelper extends MoonbeamHelper {
135 account: MoonbeamAccountGroup;148 account: MoonbeamAccountGroup;
136 wait: WaitGroup;149 wait: WaitGroup;
137150
138 constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {151 constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
139 options.helperBase = options.helperBase ?? DevMoonbeamHelper;152 options.helperBase = options.helperBase ?? DevMoonbeamHelper;
153 options.notePreimagePallet = options.notePreimagePallet ?? 'democracy';
140154
141 super(logger, options);155 super(logger, options);
142 this.account = new MoonbeamAccountGroup(this);156 this.account = new MoonbeamAccountGroup(this);
145}159}
146160
147export class DevMoonriverHelper extends DevMoonbeamHelper {}161export class DevMoonriverHelper extends DevMoonbeamHelper {
162 constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
163 options.notePreimagePallet = options.notePreimagePallet ?? 'preimage';
164 super(logger, options);
165 }
166}
148167
149export class DevAcalaHelper extends AcalaHelper {168export class DevAcalaHelper extends AcalaHelper {
modifiedtests/src/util/playgrounds/unique.tsdiffbeforeafterboth
2740 this.palletName = palletName;2740 this.palletName = palletName;
2741 }2741 }
27422742
2743 async limitedReserveTransferAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number, weightLimit: number) {2743 async limitedReserveTransferAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number, weightLimit: any) {
2744 await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.limitedReserveTransferAssets`, [destination, beneficiary, assets, feeAssetItem, {Limited: weightLimit}], true);2744 await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.limitedReserveTransferAssets`, [destination, beneficiary, assets, feeAssetItem, weightLimit], true);
2745 }2745 }
2746
2747 async teleportAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number) {
2748 await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.teleportAssets`, [destination, beneficiary, assets, feeAssetItem], true);
2749 }
2750
2751 async teleportNativeAsset(signer: TSigner, destinationParaId: number, targetAccount: Uint8Array, amount: bigint) {
2752 const destination = {
2753 V1: {
2754 parents: 0,
2755 interior: {
2756 X1: {
2757 Parachain: destinationParaId,
2758 },
2759 },
2760 },
2761 };
2762
2763 const beneficiary = {
2764 V1: {
2765 parents: 0,
2766 interior: {
2767 X1: {
2768 AccountId32: {
2769 network: 'Any',
2770 id: targetAccount,
2771 },
2772 },
2773 },
2774 },
2775 };
2776
2777 const assets = {
2778 V1: [
2779 {
2780 id: {
2781 Concrete: {
2782 parents: 0,
2783 interior: 'Here',
2784 },
2785 },
2786 fun: {
2787 Fungible: amount,
2788 },
2789 },
2790 ],
2791 };
2792
2793 const feeAssetItem = 0;
2794
2795 await this.teleportAssets(signer, destination, beneficiary, assets, feeAssetItem);
2796 }
2746}2797}
27472798
2748class XTokensGroup<T extends ChainHelperBase> extends HelperGroup<T> {2799class XTokensGroup<T extends ChainHelperBase> extends HelperGroup<T> {
2749 async transfer(signer: TSigner, currencyId: any, amount: bigint, destination: any, destWeight: number) {2800 async transfer(signer: TSigner, currencyId: any, amount: bigint, destination: any, destWeight: any) {
2750 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transfer', [currencyId, amount, destination, destWeight], true);2801 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transfer', [currencyId, amount, destination, destWeight], true);
2751 }2802 }
27522803
2753 async transferMultiasset(signer: TSigner, asset: any, destination: any, destWeight: number) {2804 async transferMultiasset(signer: TSigner, asset: any, destination: any, destWeight: any) {
2754 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMultiasset', [asset, destination, destWeight], true);2805 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMultiasset', [asset, destination, destWeight], true);
2755 }2806 }
27562807
2757 async transferMulticurrencies(signer: TSigner, currencies: any[], feeItem: number, destLocation: any, destWeight: number) {2808 async transferMulticurrencies(signer: TSigner, currencies: any[], feeItem: number, destLocation: any, destWeight: any) {
2758 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMulticurrencies', [currencies, feeItem, destLocation, destWeight], true);2809 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMulticurrencies', [currencies, feeItem, destLocation, destWeight], true);
2759 }2810 }
2760}2811}
2823}2874}
28242875
2825class MoonbeamDemocracyGroup extends HelperGroup<MoonbeamHelper> {2876class MoonbeamDemocracyGroup extends HelperGroup<MoonbeamHelper> {
2877 notePreimagePallet: string;
2878
2879 constructor(helper: MoonbeamHelper, options: {[key: string]: any} = {}) {
2880 super(helper);
2881 this.notePreimagePallet = options.notePreimagePallet;
2882 }
2883
2826 async notePreimage(signer: TSigner, encodedProposal: string) {2884 async notePreimage(signer: TSigner, encodedProposal: string) {
2827 await this.helper.executeExtrinsic(signer, 'api.tx.democracy.notePreimage', [encodedProposal], true);2885 await this.helper.executeExtrinsic(signer, `api.tx.${this.notePreimagePallet}.notePreimage`, [encodedProposal], true);
2828 }2886 }
28292887
2830 externalProposeMajority(proposalHash: string) {2888 externalProposeMajority(proposal: any) {
2831 return this.helper.constructApiCall('api.tx.democracy.externalProposeMajority', [proposalHash]);2889 return this.helper.constructApiCall('api.tx.democracy.externalProposeMajority', [proposal]);
2832 }2890 }
28332891
2834 fastTrack(proposalHash: string, votingPeriod: number, delayPeriod: number) {2892 fastTrack(proposalHash: string, votingPeriod: number, delayPeriod: number) {
2857 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.vote`, [proposalHash, proposalIndex, approve], true);2915 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.vote`, [proposalHash, proposalIndex, approve], true);
2858 }2916 }
28592917
2860 async close(signer: TSigner, proposalHash: string, proposalIndex: number, weightBound: number, lengthBound: number) {2918 async close(signer: TSigner, proposalHash: string, proposalIndex: number, weightBound: any, lengthBound: number) {
2861 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.close`, [proposalHash, proposalIndex, weightBound, lengthBound], true);2919 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.close`, [proposalHash, proposalIndex, weightBound, lengthBound], true);
2862 }2920 }
28632921
2917}2975}
29182976
2919export class RelayHelper extends XcmChainHelper {2977export class RelayHelper extends XcmChainHelper {
2978 balance: SubstrateBalanceGroup<RelayHelper>;
2920 xcm: XcmGroup<RelayHelper>;2979 xcm: XcmGroup<RelayHelper>;
29212980
2922 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2981 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {
2923 super(logger, options.helperBase ?? RelayHelper);2982 super(logger, options.helperBase ?? RelayHelper);
29242983
2984 this.balance = new SubstrateBalanceGroup(this);
2925 this.xcm = new XcmGroup(this, 'xcmPallet');2985 this.xcm = new XcmGroup(this, 'xcmPallet');
2926 }2986 }
2927}2987}
2960 this.assetManager = new MoonbeamAssetManagerGroup(this);3020 this.assetManager = new MoonbeamAssetManagerGroup(this);
2961 this.assets = new AssetsGroup(this);3021 this.assets = new AssetsGroup(this);
2962 this.xTokens = new XTokensGroup(this);3022 this.xTokens = new XTokensGroup(this);
2963 this.democracy = new MoonbeamDemocracyGroup(this);3023 this.democracy = new MoonbeamDemocracyGroup(this, options);
2964 this.collective = {3024 this.collective = {
2965 council: new MoonbeamCollectiveGroup(this, 'councilCollective'),3025 council: new MoonbeamCollectiveGroup(this, 'councilCollective'),
2966 techCommittee: new MoonbeamCollectiveGroup(this, 'techCommitteeCollective'),3026 techCommittee: new MoonbeamCollectiveGroup(this, 'techCommitteeCollective'),
modifiedtests/src/xcm/xcmOpal.test.tsdiffbeforeafterboth
31const ASSET_METADATA_DESCRIPTION = 'USDT';31const ASSET_METADATA_DESCRIPTION = 'USDT';
32const ASSET_METADATA_MINIMAL_BALANCE = 1n;32const ASSET_METADATA_MINIMAL_BALANCE = 1n;
3333
34const RELAY_DECIMALS = 12;
34const WESTMINT_DECIMALS = 12;35const WESTMINT_DECIMALS = 12;
3536
36const TRANSFER_AMOUNT = 1_000_000_000_000_000_000n;37const TRANSFER_AMOUNT = 1_000_000_000_000_000_000n;
147 };148 };
148149
149 const feeAssetItem = 0;150 const feeAssetItem = 0;
150 const weightLimit = 5_000_000_000;
151151
152 await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, weightLimit);152 await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
153 });153 });
154 154
155 });155 });
202 };202 };
203203
204 const feeAssetItem = 0;204 const feeAssetItem = 0;
205 const weightLimit = 5000000000;
206205
207 balanceStmnBefore = await helper.balance.getSubstrate(alice.address);206 balanceStmnBefore = await helper.balance.getSubstrate(alice.address);
208 await helper.xcm.limitedReserveTransferAssets(alice, dest, beneficiary, assets, feeAssetItem, weightLimit);207 await helper.xcm.limitedReserveTransferAssets(alice, dest, beneficiary, assets, feeAssetItem, 'Unlimited');
209208
210 balanceStmnAfter = await helper.balance.getSubstrate(alice.address);209 balanceStmnAfter = await helper.balance.getSubstrate(alice.address);
211210
212 // common good parachain take commission in it native token211 // common good parachain take commission in it native token
213 console.log(212 console.log(
214 'Opal to Westmint transaction fees on Westmint: %s WND',213 '[Westmint -> Opal] transaction fees on Westmint: %s WND',
215 helper.util.bigIntToDecimals(balanceStmnBefore - balanceStmnAfter, WESTMINT_DECIMALS),214 helper.util.bigIntToDecimals(balanceStmnBefore - balanceStmnAfter, WESTMINT_DECIMALS),
216 );215 );
217 expect(balanceStmnBefore > balanceStmnAfter).to.be.true;216 expect(balanceStmnBefore > balanceStmnAfter).to.be.true;
227226
228 balanceOpalAfter = await helper.balance.getSubstrate(alice.address);227 balanceOpalAfter = await helper.balance.getSubstrate(alice.address);
229228
230 // commission has not paid in USDT token229 console.log(
230 '[Westmint -> Opal] transaction fees on Opal: %s USDT',
231 expect(free == TRANSFER_AMOUNT).to.be.true;231 helper.util.bigIntToDecimals(TRANSFER_AMOUNT - free, ASSET_METADATA_DECIMALS),
232 );
232 console.log(233 console.log(
233 'Opal to Westmint transaction fees on Opal: %s USDT',234 '[Westmint -> Opal] transaction fees on Opal: %s OPL',
234 helper.util.bigIntToDecimals(TRANSFER_AMOUNT - free),235 helper.util.bigIntToDecimals(balanceOpalAfter - balanceOpalBefore),
235 );236 );
236 // ... and parachain native token237
238 // commission has not paid in USDT token
237 expect(balanceOpalAfter == balanceOpalBefore).to.be.true;239 expect(free == TRANSFER_AMOUNT).to.be.true;
238 console.log(240 // ... and parachain native token
239 'Opal to Westmint transaction fees on Opal: %s WND',
240 helper.util.bigIntToDecimals(balanceOpalAfter - balanceOpalBefore, WESTMINT_DECIMALS),241 expect(balanceOpalAfter == balanceOpalBefore).to.be.true;
241 );
242 });242 });
243243
244 itSub('Should connect and send USDT from Unique to Statemine back', async ({helper}) => {244 itSub('Should connect and send USDT from Unique to Statemine back', async ({helper}) => {
276 ];276 ];
277277
278 const feeItem = 1;278 const feeItem = 1;
279 const destWeight = 500000000000;
280279
281 await helper.xTokens.transferMulticurrencies(alice, currencies, feeItem, destination, destWeight);280 await helper.xTokens.transferMulticurrencies(alice, currencies, feeItem, destination, 'Unlimited');
282 281
283 // the commission has been paid in parachain native token282 // the commission has been paid in parachain native token
284 balanceOpalFinal = await helper.balance.getSubstrate(alice.address);283 balanceOpalFinal = await helper.balance.getSubstrate(alice.address);
339 };338 };
340339
341 const feeAssetItem = 0;340 const feeAssetItem = 0;
342 const weightLimit = 5_000_000_000;
343341
344 await helper.xcm.limitedReserveTransferAssets(bob, destination, beneficiary, assets, feeAssetItem, weightLimit);342 await helper.xcm.limitedReserveTransferAssets(bob, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
345 });343 });
346 344
347 await helper.wait.newBlocks(3);345 await helper.wait.newBlocks(3);
363 });361 });
364362
365 itSub('Should connect and send Relay token back', async ({helper}) => {363 itSub('Should connect and send Relay token back', async ({helper}) => {
364 let relayTokenBalanceBefore: bigint;
365 let relayTokenBalanceAfter: bigint;
366 await usingRelayPlaygrounds(relayUrl, async (helper) => {
367 relayTokenBalanceBefore = await helper.balance.getSubstrate(bob.address);
368 });
369
366 const destination = {370 const destination = {
367 V1: {371 V1: {
368 parents: 1,372 parents: 1,
369 interior: {X2: [373 interior: {
370 {
371 Parachain: STATEMINE_CHAIN,
372 },
373 {374 X1:{
374 AccountId32: {375 AccountId32: {
375 network: 'Any',376 network: 'Any',
376 id: bob.addressRaw,377 id: bob.addressRaw,
377 },378 },
378 },379 },
379 ]},380 },
380 },381 },
381 };382 };
382383
390 ];391 ];
391392
392 const feeItem = 0;393 const feeItem = 0;
393 const destWeight = 500000000000;
394394
395 await helper.xTokens.transferMulticurrencies(bob, currencies, feeItem, destination, destWeight);395 await helper.xTokens.transferMulticurrencies(bob, currencies, feeItem, destination, 'Unlimited');
396396
397 balanceBobFinal = await helper.balance.getSubstrate(bob.address);397 balanceBobFinal = await helper.balance.getSubstrate(bob.address);
398 console.log('Relay (Westend) to Opal transaction fees: %s OPL', balanceBobAfter - balanceBobFinal);398 console.log('[Opal -> Relay (Westend)] transaction fees: %s OPL', helper.util.bigIntToDecimals(balanceBobAfter - balanceBobFinal));
399
400 await usingRelayPlaygrounds(relayUrl, async (helper) => {
401 await helper.wait.newBlocks(10);
402 relayTokenBalanceAfter = await helper.balance.getSubstrate(bob.address);
403
404 const diff = relayTokenBalanceAfter - relayTokenBalanceBefore;
405 console.log('[Opal -> Relay (Westend)] actually delivered: %s WND', helper.util.bigIntToDecimals(diff, RELAY_DECIMALS));
406 expect(diff > 0, 'Relay tokens was not delivered back').to.be.true;
407 });
399 });408 });
400});409});
401410
modifiedtests/src/xcm/xcmQuartz.test.tsdiffbeforeafterboth
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {blake2AsHex} from '@polkadot/util-crypto';18import {blake2AsHex} from '@polkadot/util-crypto';
19import config from '../config';19import config from '../config';
20import {XcmV2TraitsOutcome, XcmV2TraitsError} from '../interfaces';20import {XcmV2TraitsError} from '../interfaces';
21import {itSub, expect, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds, usingRelayPlaygrounds, usingMoonriverPlaygrounds} from '../util';21import {itSub, expect, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds, usingRelayPlaygrounds, usingMoonriverPlaygrounds, usingStateminePlaygrounds} from '../util';
2222
23const QUARTZ_CHAIN = 2095;23const QUARTZ_CHAIN = 2095;
24const STATEMINE_CHAIN = 1000;
24const KARURA_CHAIN = 2000;25const KARURA_CHAIN = 2000;
25const MOONRIVER_CHAIN = 2023;26const MOONRIVER_CHAIN = 2023;
2627
28const STATEMINE_PALLET_INSTANCE = 50;
29
27const relayUrl = config.relayUrl;30const relayUrl = config.relayUrl;
31const statemineUrl = config.statemineUrl;
28const karuraUrl = config.karuraUrl;32const karuraUrl = config.karuraUrl;
29const moonriverUrl = config.moonriverUrl;33const moonriverUrl = config.moonriverUrl;
3034
35const RELAY_DECIMALS = 12;
36const STATEMINE_DECIMALS = 12;
31const KARURA_DECIMALS = 12;37const KARURA_DECIMALS = 12;
3238
33const TRANSFER_AMOUNT = 2000000000000000000000000n;39const TRANSFER_AMOUNT = 2000000000000000000000000n;
3440
41const FUNDING_AMOUNT = 3_500_000_0000_000_000n;
42
43const TRANSFER_AMOUNT_RELAY = 50_000_000_000_000_000n;
44
45const USDT_ASSET_ID = 100;
46const USDT_ASSET_METADATA_DECIMALS = 18;
47const USDT_ASSET_METADATA_NAME = 'USDT';
48const USDT_ASSET_METADATA_DESCRIPTION = 'USDT';
49const USDT_ASSET_METADATA_MINIMAL_BALANCE = 1n;
50const USDT_ASSET_AMOUNT = 10_000_000_000_000_000_000_000_000n;
51
52describeXCM('[XCM] Integration test: Exchanging USDT with Statemine', () => {
53 let alice: IKeyringPair;
54 let bob: IKeyringPair;
55
56 let balanceStmnBefore: bigint;
57 let balanceStmnAfter: bigint;
58
59 let balanceQuartzBefore: bigint;
60 let balanceQuartzAfter: bigint;
61 let balanceQuartzFinal: bigint;
62
63 let balanceBobBefore: bigint;
64 let balanceBobAfter: bigint;
65 let balanceBobFinal: bigint;
66
67 let balanceBobRelayTokenBefore: bigint;
68 let balanceBobRelayTokenAfter: bigint;
69
70
71 before(async () => {
72 await usingPlaygrounds(async (_helper, privateKey) => {
73 alice = await privateKey('//Alice');
74 bob = await privateKey('//Bob'); // sovereign account on Statemine(t) funds donor
75 });
76
77 await usingRelayPlaygrounds(relayUrl, async (helper) => {
78 // Fund accounts on Statemine(t)
79 await helper.xcm.teleportNativeAsset(alice, STATEMINE_CHAIN, alice.addressRaw, FUNDING_AMOUNT);
80 await helper.xcm.teleportNativeAsset(alice, STATEMINE_CHAIN, bob.addressRaw, FUNDING_AMOUNT);
81 });
82
83 await usingStateminePlaygrounds(statemineUrl, async (helper) => {
84 const sovereignFundingAmount = 3_500_000_000n;
85
86 await helper.assets.create(
87 alice,
88 USDT_ASSET_ID,
89 alice.address,
90 USDT_ASSET_METADATA_MINIMAL_BALANCE,
91 );
92 await helper.assets.setMetadata(
93 alice,
94 USDT_ASSET_ID,
95 USDT_ASSET_METADATA_NAME,
96 USDT_ASSET_METADATA_DESCRIPTION,
97 USDT_ASSET_METADATA_DECIMALS,
98 );
99 await helper.assets.mint(
100 alice,
101 USDT_ASSET_ID,
102 alice.address,
103 USDT_ASSET_AMOUNT,
104 );
105
106 // funding parachain sovereing account on Statemine(t).
107 // The sovereign account should be created before any action
108 // (the assets pallet on Statemine(t) check if the sovereign account exists)
109 const parachainSovereingAccount = helper.address.paraSiblingSovereignAccount(QUARTZ_CHAIN);
110 await helper.balance.transferToSubstrate(bob, parachainSovereingAccount, sovereignFundingAmount);
111 });
112
113
114 await usingPlaygrounds(async (helper) => {
115 const location = {
116 V1: {
117 parents: 1,
118 interior: {X3: [
119 {
120 Parachain: STATEMINE_CHAIN,
121 },
122 {
123 PalletInstance: STATEMINE_PALLET_INSTANCE,
124 },
125 {
126 GeneralIndex: USDT_ASSET_ID,
127 },
128 ]},
129 },
130 };
131
132 const metadata =
133 {
134 name: USDT_ASSET_ID,
135 symbol: USDT_ASSET_METADATA_NAME,
136 decimals: USDT_ASSET_METADATA_DECIMALS,
137 minimalBalance: USDT_ASSET_METADATA_MINIMAL_BALANCE,
138 };
139 await helper.getSudo().foreignAssets.register(alice, alice.address, location, metadata);
140 balanceQuartzBefore = await helper.balance.getSubstrate(alice.address);
141 });
142
143
144 // Providing the relay currency to the quartz sender account
145 // (fee for USDT XCM are paid in relay tokens)
146 await usingRelayPlaygrounds(relayUrl, async (helper) => {
147 const destination = {
148 V1: {
149 parents: 0,
150 interior: {X1: {
151 Parachain: QUARTZ_CHAIN,
152 },
153 },
154 }};
155
156 const beneficiary = {
157 V1: {
158 parents: 0,
159 interior: {X1: {
160 AccountId32: {
161 network: 'Any',
162 id: alice.addressRaw,
163 },
164 }},
165 },
166 };
167
168 const assets = {
169 V1: [
170 {
171 id: {
172 Concrete: {
173 parents: 0,
174 interior: 'Here',
175 },
176 },
177 fun: {
178 Fungible: TRANSFER_AMOUNT_RELAY,
179 },
180 },
181 ],
182 };
183
184 const feeAssetItem = 0;
185
186 await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
187 });
188
189 });
190
191 itSub('Should connect and send USDT from Statemine to Quartz', async ({helper}) => {
192 await usingStateminePlaygrounds(statemineUrl, async (helper) => {
193 const dest = {
194 V1: {
195 parents: 1,
196 interior: {X1: {
197 Parachain: QUARTZ_CHAIN,
198 },
199 },
200 }};
201
202 const beneficiary = {
203 V1: {
204 parents: 0,
205 interior: {X1: {
206 AccountId32: {
207 network: 'Any',
208 id: alice.addressRaw,
209 },
210 }},
211 },
212 };
213
214 const assets = {
215 V1: [
216 {
217 id: {
218 Concrete: {
219 parents: 0,
220 interior: {
221 X2: [
222 {
223 PalletInstance: STATEMINE_PALLET_INSTANCE,
224 },
225 {
226 GeneralIndex: USDT_ASSET_ID,
227 },
228 ]},
229 },
230 },
231 fun: {
232 Fungible: TRANSFER_AMOUNT,
233 },
234 },
235 ],
236 };
237
238 const feeAssetItem = 0;
239
240 balanceStmnBefore = await helper.balance.getSubstrate(alice.address);
241 await helper.xcm.limitedReserveTransferAssets(alice, dest, beneficiary, assets, feeAssetItem, 'Unlimited');
242
243 balanceStmnAfter = await helper.balance.getSubstrate(alice.address);
244
245 // common good parachain take commission in it native token
246 console.log(
247 '[Statemine -> Quartz] transaction fees on Statemine: %s WND',
248 helper.util.bigIntToDecimals(balanceStmnBefore - balanceStmnAfter, STATEMINE_DECIMALS),
249 );
250 expect(balanceStmnBefore > balanceStmnAfter).to.be.true;
251
252 });
253
254
255 // ensure that asset has been delivered
256 await helper.wait.newBlocks(3);
257
258 // expext collection id will be with id 1
259 const free = await helper.ft.getBalance(1, {Substrate: alice.address});
260
261 balanceQuartzAfter = await helper.balance.getSubstrate(alice.address);
262
263 console.log(
264 '[Statemine -> Quartz] transaction fees on Quartz: %s USDT',
265 helper.util.bigIntToDecimals(TRANSFER_AMOUNT - free, USDT_ASSET_METADATA_DECIMALS),
266 );
267 console.log(
268 '[Statemine -> Quartz] transaction fees on Quartz: %s QTZ',
269 helper.util.bigIntToDecimals(balanceQuartzAfter - balanceQuartzBefore),
270 );
271 // commission has not paid in USDT token
272 expect(free).to.be.equal(TRANSFER_AMOUNT);
273 // ... and parachain native token
274 expect(balanceQuartzAfter == balanceQuartzBefore).to.be.true;
275 });
276
277 itSub('Should connect and send USDT from Quartz to Statemine back', async ({helper}) => {
278 const destination = {
279 V1: {
280 parents: 1,
281 interior: {X2: [
282 {
283 Parachain: STATEMINE_CHAIN,
284 },
285 {
286 AccountId32: {
287 network: 'Any',
288 id: alice.addressRaw,
289 },
290 },
291 ]},
292 },
293 };
294
295 const relayFee = 400_000_000_000_000n;
296 const currencies: [any, bigint][] = [
297 [
298 {
299 ForeignAssetId: 0,
300 },
301 TRANSFER_AMOUNT,
302 ],
303 [
304 {
305 NativeAssetId: 'Parent',
306 },
307 relayFee,
308 ],
309 ];
310
311 const feeItem = 1;
312
313 await helper.xTokens.transferMulticurrencies(alice, currencies, feeItem, destination, 'Unlimited');
314
315 // the commission has been paid in parachain native token
316 balanceQuartzFinal = await helper.balance.getSubstrate(alice.address);
317 console.log('[Quartz -> Statemine] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(balanceQuartzFinal - balanceQuartzAfter));
318 expect(balanceQuartzAfter > balanceQuartzFinal).to.be.true;
319
320 await usingStateminePlaygrounds(statemineUrl, async (helper) => {
321 await helper.wait.newBlocks(3);
322
323 // The USDT token never paid fees. Its amount not changed from begin value.
324 // Also check that xcm transfer has been succeeded
325 expect((await helper.assets.account(USDT_ASSET_ID, alice.address))! == USDT_ASSET_AMOUNT).to.be.true;
326 });
327 });
328
329 itSub('Should connect and send Relay token to Quartz', async ({helper}) => {
330 balanceBobBefore = await helper.balance.getSubstrate(bob.address);
331 balanceBobRelayTokenBefore = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});
332
333 await usingRelayPlaygrounds(relayUrl, async (helper) => {
334 const destination = {
335 V1: {
336 parents: 0,
337 interior: {X1: {
338 Parachain: QUARTZ_CHAIN,
339 },
340 },
341 }};
342
343 const beneficiary = {
344 V1: {
345 parents: 0,
346 interior: {X1: {
347 AccountId32: {
348 network: 'Any',
349 id: bob.addressRaw,
350 },
351 }},
352 },
353 };
354
355 const assets = {
356 V1: [
357 {
358 id: {
359 Concrete: {
360 parents: 0,
361 interior: 'Here',
362 },
363 },
364 fun: {
365 Fungible: TRANSFER_AMOUNT_RELAY,
366 },
367 },
368 ],
369 };
370
371 const feeAssetItem = 0;
372
373 await helper.xcm.limitedReserveTransferAssets(bob, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
374 });
375
376 await helper.wait.newBlocks(3);
377
378 balanceBobAfter = await helper.balance.getSubstrate(bob.address);
379 balanceBobRelayTokenAfter = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});
380
381 const wndFeeOnQuartz = balanceBobRelayTokenAfter - TRANSFER_AMOUNT_RELAY - balanceBobRelayTokenBefore;
382 const wndDiffOnQuartz = balanceBobRelayTokenAfter - balanceBobRelayTokenBefore;
383 console.log(
384 '[Relay (Westend) -> Quartz] transaction fees: %s QTZ',
385 helper.util.bigIntToDecimals(balanceBobAfter - balanceBobBefore),
386 );
387 console.log(
388 '[Relay (Westend) -> Quartz] transaction fees: %s WND',
389 helper.util.bigIntToDecimals(wndFeeOnQuartz, STATEMINE_DECIMALS),
390 );
391 console.log('[Relay (Westend) -> Quartz] actually delivered: %s WND', wndDiffOnQuartz);
392 expect(wndFeeOnQuartz == 0n, 'No incoming WND fees should be taken').to.be.true;
393 expect(balanceBobBefore == balanceBobAfter, 'No incoming QTZ fees should be taken').to.be.true;
394 });
395
396 itSub('Should connect and send Relay token back', async ({helper}) => {
397 let relayTokenBalanceBefore: bigint;
398 let relayTokenBalanceAfter: bigint;
399 await usingRelayPlaygrounds(relayUrl, async (helper) => {
400 relayTokenBalanceBefore = await helper.balance.getSubstrate(bob.address);
401 });
402
403 const destination = {
404 V1: {
405 parents: 1,
406 interior: {
407 X1:{
408 AccountId32: {
409 network: 'Any',
410 id: bob.addressRaw,
411 },
412 },
413 },
414 },
415 };
416
417 const currencies: any = [
418 [
419 {
420 NativeAssetId: 'Parent',
421 },
422 TRANSFER_AMOUNT_RELAY,
423 ],
424 ];
425
426 const feeItem = 0;
427
428 await helper.xTokens.transferMulticurrencies(bob, currencies, feeItem, destination, 'Unlimited');
429
430 balanceBobFinal = await helper.balance.getSubstrate(bob.address);
431 console.log('[Quartz -> Relay (Westend)] transaction fees: %s QTZ', helper.util.bigIntToDecimals(balanceBobAfter - balanceBobFinal));
432
433 await usingRelayPlaygrounds(relayUrl, async (helper) => {
434 await helper.wait.newBlocks(10);
435 relayTokenBalanceAfter = await helper.balance.getSubstrate(bob.address);
436
437 const diff = relayTokenBalanceAfter - relayTokenBalanceBefore;
438 console.log('[Quartz -> Relay (Westend)] actually delivered: %s WND', helper.util.bigIntToDecimals(diff, RELAY_DECIMALS));
439 expect(diff > 0, 'Relay tokens was not delivered back').to.be.true;
440 });
441 });
442});
443
35describeXCM('[XCM] Integration test: Exchanging tokens with Karura', () => {444describeXCM('[XCM] Integration test: Exchanging tokens with Karura', () => {
36 let alice: IKeyringPair;445 let alice: IKeyringPair;
123 };532 };
124533
125 const feeAssetItem = 0;534 const feeAssetItem = 0;
126 const weightLimit = 5000000000;
127535
128 await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, weightLimit);536 await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
129 balanceQuartzTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);537 balanceQuartzTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);
130538
131 const qtzFees = balanceQuartzTokenInit - balanceQuartzTokenMiddle - TRANSFER_AMOUNT;539 const qtzFees = balanceQuartzTokenInit - balanceQuartzTokenMiddle - TRANSFER_AMOUNT;
540 expect(qtzFees > 0n, 'Negative fees QTZ, looks like nothing was transferred').to.be.true;
132 console.log('[Quartz -> Karura] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(qtzFees));541 console.log('[Quartz -> Karura] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(qtzFees));
133 expect(qtzFees > 0n).to.be.true;
134542
135 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {543 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
136 await helper.wait.newBlocks(3);544 await helper.wait.newBlocks(3);
173 ForeignAsset: 0,581 ForeignAsset: 0,
174 };582 };
175583
176 const destWeight = 50000000;584 await helper.xTokens.transfer(randomAccount, id, TRANSFER_AMOUNT, destination, 'Unlimited');
177
178 await helper.xTokens.transfer(randomAccount, id, TRANSFER_AMOUNT, destination, destWeight);
179 balanceKaruraTokenFinal = await helper.balance.getSubstrate(randomAccount.address);585 balanceKaruraTokenFinal = await helper.balance.getSubstrate(randomAccount.address);
180 balanceQuartzForeignTokenFinal = await helper.tokens.accounts(randomAccount.address, id);586 balanceQuartzForeignTokenFinal = await helper.tokens.accounts(randomAccount.address, id);
181587
188 );594 );
189 console.log('[Karura -> Quartz] outcome %s QTZ', helper.util.bigIntToDecimals(qtzOutcomeTransfer));595 console.log('[Karura -> Quartz] outcome %s QTZ', helper.util.bigIntToDecimals(qtzOutcomeTransfer));
190596
191 expect(karFees > 0).to.be.true;597 expect(karFees > 0, 'Negative fees KAR, looks like nothing was transferred').to.be.true;
192 expect(qtzOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;598 expect(qtzOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;
193 });599 });
194600
216 });622 });
217 });623 });
218624
219 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 }};
229
230 const beneficiary = {
231 V1: {
232 parents: 0,
233 interior: {X1: {
234 AccountId32: {
235 network: 'Any',
236 id: alice.addressRaw,
237 },
238 }},
239 },
240 };
241
242 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 };
257
258 const feeAssetItem = 0;
259 const weightLimit = 5_000_000_000;
260
261 await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, weightLimit);
262 });
263
264 const maxWaitBlocks = 3;
265
266 const dmpQueueExecutedDownward = await helper.wait.event(maxWaitBlocks, 'dmpQueue', 'ExecutedDownward');
267
268 expect(
269 dmpQueueExecutedDownward != null,
270 '[Relay] dmpQueue.ExecutedDownward event is expected',
271 ).to.be.true;
272
273 const event = dmpQueueExecutedDownward!.event;
274 const outcome = event.data[1] as XcmV2TraitsOutcome;
275
276 expect(
277 outcome.isIncomplete,
278 '[Relay] The outcome of the XCM should be `Incomplete`',
279 ).to.be.true;
280
281 const incomplete = outcome.asIncomplete;
282 expect(
283 incomplete[1].toString() == 'AssetNotFound',
284 '[Relay] The XCM error should be `AssetNotFound`',
285 ).to.be.true;
286 });
287
288 itSub('Quartz rejects KAR tokens from Karura', async ({helper}) => {625 itSub('Quartz rejects KAR tokens from Karura', async ({helper}) => {
289 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {626 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
290 const destination = {627 const destination = {
308 Token: 'KAR',645 Token: 'KAR',
309 };646 };
310647
311 const destWeight = 50000000;648 await helper.xTokens.transfer(alice, id, 100_000_000_000n, destination, 'Unlimited');
312
313 await helper.xTokens.transfer(alice, id, 100_000_000_000n, destination, destWeight);
314 });649 });
315650
316 const maxWaitBlocks = 3;651 const maxWaitBlocks = 3;
326 const outcome = event.data[1] as XcmV2TraitsError;661 const outcome = event.data[1] as XcmV2TraitsError;
327662
328 expect(663 expect(
329 outcome.isUntrustedReserveLocation,664 outcome.isFailedToTransactAsset,
330 '[Karura] The XCM error should be `UntrustedReserveLocation`',665 '[Karura] The XCM error should be `FailedToTransactAsset`',
331 ).to.be.true;666 ).to.be.true;
332 });667 });
333});668});
420755
421 // >>> Propose external motion through council >>>756 // >>> Propose external motion through council >>>
422 console.log('Propose external motion through council.......');757 console.log('Propose external motion through council.......');
423 const externalMotion = helper.democracy.externalProposeMajority(proposalHash);758 const externalMotion = helper.democracy.externalProposeMajority({Legacy: proposalHash});
424 const encodedMotion = externalMotion?.method.toHex() || '';759 const encodedMotion = externalMotion?.method.toHex() || '';
425 const motionHash = blake2AsHex(encodedMotion);760 const motionHash = blake2AsHex(encodedMotion);
426 console.log('Motion hash is %s', motionHash);761 console.log('Motion hash is %s', motionHash);
431 await helper.collective.council.vote(dorothyAccount, motionHash, councilProposalIdx, true);766 await helper.collective.council.vote(dorothyAccount, motionHash, councilProposalIdx, true);
432 await helper.collective.council.vote(baltatharAccount, motionHash, councilProposalIdx, true);767 await helper.collective.council.vote(baltatharAccount, motionHash, councilProposalIdx, true);
433768
434 await helper.collective.council.close(dorothyAccount, motionHash, councilProposalIdx, 1_000_000_000, externalMotion.encodedLength);769 await helper.collective.council.close(
770 dorothyAccount,
771 motionHash,
772 councilProposalIdx,
773 {
774 refTime: 1_000_000_000,
775 proofSize: 1_000_000,
776 },
777 externalMotion.encodedLength,
778 );
435 console.log('Propose external motion through council.......DONE');779 console.log('Propose external motion through council.......DONE');
436 // <<< Propose external motion through council <<<780 // <<< Propose external motion through council <<<
437781
448 await helper.collective.techCommittee.vote(baltatharAccount, fastTrackHash, techProposalIdx, true);792 await helper.collective.techCommittee.vote(baltatharAccount, fastTrackHash, techProposalIdx, true);
449 await helper.collective.techCommittee.vote(alithAccount, fastTrackHash, techProposalIdx, true);793 await helper.collective.techCommittee.vote(alithAccount, fastTrackHash, techProposalIdx, true);
450794
451 await helper.collective.techCommittee.close(baltatharAccount, fastTrackHash, techProposalIdx, 1_000_000_000, fastTrack.encodedLength);795 await helper.collective.techCommittee.close(
796 baltatharAccount,
797 fastTrackHash,
798 techProposalIdx,
799 {
800 refTime: 1_000_000_000,
801 proofSize: 1_000_000,
802 },
803 fastTrack.encodedLength,
804 );
452 console.log('Fast track proposal through technical committee.......DONE');805 console.log('Fast track proposal through technical committee.......DONE');
453 // <<< Fast track proposal through technical committee <<<806 // <<< Fast track proposal through technical committee <<<
454807
504 },857 },
505 };858 };
506 const amount = TRANSFER_AMOUNT;859 const amount = TRANSFER_AMOUNT;
507 const destWeight = 850000000;
508860
509 await helper.xTokens.transfer(randomAccountQuartz, currencyId, amount, dest, destWeight);861 await helper.xTokens.transfer(randomAccountQuartz, currencyId, amount, dest, 'Unlimited');
510862
511 balanceQuartzTokenMiddle = await helper.balance.getSubstrate(randomAccountQuartz.address);863 balanceQuartzTokenMiddle = await helper.balance.getSubstrate(randomAccountQuartz.address);
512 expect(balanceQuartzTokenMiddle < balanceQuartzTokenInit).to.be.true;864 expect(balanceQuartzTokenMiddle < balanceQuartzTokenInit).to.be.true;
513865
514 const transactionFees = balanceQuartzTokenInit - balanceQuartzTokenMiddle - TRANSFER_AMOUNT;866 const transactionFees = balanceQuartzTokenInit - balanceQuartzTokenMiddle - TRANSFER_AMOUNT;
515 console.log('[Quartz -> Moonriver] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(transactionFees));867 console.log('[Quartz -> Moonriver] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(transactionFees));
516 expect(transactionFees > 0).to.be.true;868 expect(transactionFees > 0, 'Negative fees QTZ, looks like nothing was transferred').to.be.true;
517869
518 await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {870 await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
519 await helper.wait.newBlocks(3);871 await helper.wait.newBlocks(3);
559 },911 },
560 },912 },
561 };913 };
562 const destWeight = 50000000;
563914
564 await helper.xTokens.transferMultiasset(randomAccountMoonriver, asset, destination, destWeight);915 await helper.xTokens.transferMultiasset(randomAccountMoonriver, asset, destination, 'Unlimited');
565916
566 balanceMovrTokenFinal = await helper.balance.getEthereum(randomAccountMoonriver.address);917 balanceMovrTokenFinal = await helper.balance.getEthereum(randomAccountMoonriver.address);
567918
568 const movrFees = balanceMovrTokenMiddle - balanceMovrTokenFinal;919 const movrFees = balanceMovrTokenMiddle - balanceMovrTokenFinal;
569 console.log('[Moonriver -> Quartz] transaction fees on Moonriver: %s MOVR', helper.util.bigIntToDecimals(movrFees));920 console.log('[Moonriver -> Quartz] transaction fees on Moonriver: %s MOVR', helper.util.bigIntToDecimals(movrFees));
570 expect(movrFees > 0).to.be.true;921 expect(movrFees > 0, 'Negative fees MOVR, looks like nothing was transferred').to.be.true;
571922
572 const qtzRandomAccountAsset = await helper.assets.account(assetId, randomAccountMoonriver.address);923 const qtzRandomAccountAsset = await helper.assets.account(assetId, randomAccountMoonriver.address);
573924
modifiedtests/src/xcm/xcmUnique.test.tsdiffbeforeafterboth
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {blake2AsHex} from '@polkadot/util-crypto';18import {blake2AsHex} from '@polkadot/util-crypto';
19import config from '../config';19import config from '../config';
20import {XcmV2TraitsError, XcmV2TraitsOutcome} from '../interfaces';20import {XcmV2TraitsError} from '../interfaces';
21import {itSub, expect, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingRelayPlaygrounds, usingMoonbeamPlaygrounds} from '../util';21import {itSub, expect, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingRelayPlaygrounds, usingMoonbeamPlaygrounds, usingStatemintPlaygrounds} from '../util';
2222
23const UNIQUE_CHAIN = 2037;23const UNIQUE_CHAIN = 2037;
24const STATEMINT_CHAIN = 1000;
24const ACALA_CHAIN = 2000;25const ACALA_CHAIN = 2000;
25const MOONBEAM_CHAIN = 2004;26const MOONBEAM_CHAIN = 2004;
2627
28const STATEMINT_PALLET_INSTANCE = 50;
29
27const relayUrl = config.relayUrl;30const relayUrl = config.relayUrl;
31const statemintUrl = config.statemintUrl;
28const acalaUrl = config.acalaUrl;32const acalaUrl = config.acalaUrl;
29const moonbeamUrl = config.moonbeamUrl;33const moonbeamUrl = config.moonbeamUrl;
3034
35const RELAY_DECIMALS = 12;
36const STATEMINT_DECIMALS = 12;
31const ACALA_DECIMALS = 12;37const ACALA_DECIMALS = 12;
3238
33const TRANSFER_AMOUNT = 2000000000000000000000000n;39const TRANSFER_AMOUNT = 2000000000000000000000000n;
3440
41const FUNDING_AMOUNT = 3_500_000_0000_000_000n;
42
43const TRANSFER_AMOUNT_RELAY = 50_000_000_000_000_000n;
44
45const USDT_ASSET_ID = 100;
46const USDT_ASSET_METADATA_DECIMALS = 18;
47const USDT_ASSET_METADATA_NAME = 'USDT';
48const USDT_ASSET_METADATA_DESCRIPTION = 'USDT';
49const USDT_ASSET_METADATA_MINIMAL_BALANCE = 1n;
50const USDT_ASSET_AMOUNT = 10_000_000_000_000_000_000_000_000n;
51
52describeXCM('[XCM] Integration test: Exchanging USDT with Statemint', () => {
53 let alice: IKeyringPair;
54 let bob: IKeyringPair;
55
56 let balanceStmnBefore: bigint;
57 let balanceStmnAfter: bigint;
58
59 let balanceUniqueBefore: bigint;
60 let balanceUniqueAfter: bigint;
61 let balanceUniqueFinal: bigint;
62
63 let balanceBobBefore: bigint;
64 let balanceBobAfter: bigint;
65 let balanceBobFinal: bigint;
66
67 let balanceBobRelayTokenBefore: bigint;
68 let balanceBobRelayTokenAfter: bigint;
69
70
71 before(async () => {
72 await usingPlaygrounds(async (_helper, privateKey) => {
73 alice = await privateKey('//Alice');
74 bob = await privateKey('//Bob'); // sovereign account on Statemint funds donor
75 });
76
77 await usingRelayPlaygrounds(relayUrl, async (helper) => {
78 // Fund accounts on Statemint
79 await helper.xcm.teleportNativeAsset(alice, STATEMINT_CHAIN, alice.addressRaw, FUNDING_AMOUNT);
80 await helper.xcm.teleportNativeAsset(alice, STATEMINT_CHAIN, bob.addressRaw, FUNDING_AMOUNT);
81 });
82
83 await usingStatemintPlaygrounds(statemintUrl, async (helper) => {
84 const sovereignFundingAmount = 3_500_000_000n;
85
86 await helper.assets.create(
87 alice,
88 USDT_ASSET_ID,
89 alice.address,
90 USDT_ASSET_METADATA_MINIMAL_BALANCE,
91 );
92 await helper.assets.setMetadata(
93 alice,
94 USDT_ASSET_ID,
95 USDT_ASSET_METADATA_NAME,
96 USDT_ASSET_METADATA_DESCRIPTION,
97 USDT_ASSET_METADATA_DECIMALS,
98 );
99 await helper.assets.mint(
100 alice,
101 USDT_ASSET_ID,
102 alice.address,
103 USDT_ASSET_AMOUNT,
104 );
105
106 // funding parachain sovereing account on Statemint.
107 // The sovereign account should be created before any action
108 // (the assets pallet on Statemint check if the sovereign account exists)
109 const parachainSovereingAccount = helper.address.paraSiblingSovereignAccount(UNIQUE_CHAIN);
110 await helper.balance.transferToSubstrate(bob, parachainSovereingAccount, sovereignFundingAmount);
111 });
112
113
114 await usingPlaygrounds(async (helper) => {
115 const location = {
116 V1: {
117 parents: 1,
118 interior: {X3: [
119 {
120 Parachain: STATEMINT_CHAIN,
121 },
122 {
123 PalletInstance: STATEMINT_PALLET_INSTANCE,
124 },
125 {
126 GeneralIndex: USDT_ASSET_ID,
127 },
128 ]},
129 },
130 };
131
132 const metadata =
133 {
134 name: USDT_ASSET_ID,
135 symbol: USDT_ASSET_METADATA_NAME,
136 decimals: USDT_ASSET_METADATA_DECIMALS,
137 minimalBalance: USDT_ASSET_METADATA_MINIMAL_BALANCE,
138 };
139 await helper.getSudo().foreignAssets.register(alice, alice.address, location, metadata);
140 balanceUniqueBefore = await helper.balance.getSubstrate(alice.address);
141 });
142
143
144 // Providing the relay currency to the unique sender account
145 // (fee for USDT XCM are paid in relay tokens)
146 await usingRelayPlaygrounds(relayUrl, async (helper) => {
147 const destination = {
148 V1: {
149 parents: 0,
150 interior: {X1: {
151 Parachain: UNIQUE_CHAIN,
152 },
153 },
154 }};
155
156 const beneficiary = {
157 V1: {
158 parents: 0,
159 interior: {X1: {
160 AccountId32: {
161 network: 'Any',
162 id: alice.addressRaw,
163 },
164 }},
165 },
166 };
167
168 const assets = {
169 V1: [
170 {
171 id: {
172 Concrete: {
173 parents: 0,
174 interior: 'Here',
175 },
176 },
177 fun: {
178 Fungible: TRANSFER_AMOUNT_RELAY,
179 },
180 },
181 ],
182 };
183
184 const feeAssetItem = 0;
185
186 await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
187 });
188
189 });
190
191 itSub('Should connect and send USDT from Statemint to Unique', async ({helper}) => {
192 await usingStatemintPlaygrounds(statemintUrl, async (helper) => {
193 const dest = {
194 V1: {
195 parents: 1,
196 interior: {X1: {
197 Parachain: UNIQUE_CHAIN,
198 },
199 },
200 }};
201
202 const beneficiary = {
203 V1: {
204 parents: 0,
205 interior: {X1: {
206 AccountId32: {
207 network: 'Any',
208 id: alice.addressRaw,
209 },
210 }},
211 },
212 };
213
214 const assets = {
215 V1: [
216 {
217 id: {
218 Concrete: {
219 parents: 0,
220 interior: {
221 X2: [
222 {
223 PalletInstance: STATEMINT_PALLET_INSTANCE,
224 },
225 {
226 GeneralIndex: USDT_ASSET_ID,
227 },
228 ]},
229 },
230 },
231 fun: {
232 Fungible: TRANSFER_AMOUNT,
233 },
234 },
235 ],
236 };
237
238 const feeAssetItem = 0;
239
240 balanceStmnBefore = await helper.balance.getSubstrate(alice.address);
241 await helper.xcm.limitedReserveTransferAssets(alice, dest, beneficiary, assets, feeAssetItem, 'Unlimited');
242
243 balanceStmnAfter = await helper.balance.getSubstrate(alice.address);
244
245 // common good parachain take commission in it native token
246 console.log(
247 '[Statemint -> Unique] transaction fees on Statemint: %s WND',
248 helper.util.bigIntToDecimals(balanceStmnBefore - balanceStmnAfter, STATEMINT_DECIMALS),
249 );
250 expect(balanceStmnBefore > balanceStmnAfter).to.be.true;
251
252 });
253
254
255 // ensure that asset has been delivered
256 await helper.wait.newBlocks(3);
257
258 // expext collection id will be with id 1
259 const free = await helper.ft.getBalance(1, {Substrate: alice.address});
260
261 balanceUniqueAfter = await helper.balance.getSubstrate(alice.address);
262
263 console.log(
264 '[Statemint -> Unique] transaction fees on Unique: %s USDT',
265 helper.util.bigIntToDecimals(TRANSFER_AMOUNT - free, USDT_ASSET_METADATA_DECIMALS),
266 );
267 console.log(
268 '[Statemint -> Unique] transaction fees on Unique: %s UNQ',
269 helper.util.bigIntToDecimals(balanceUniqueAfter - balanceUniqueBefore),
270 );
271 // commission has not paid in USDT token
272 expect(free).to.be.equal(TRANSFER_AMOUNT);
273 // ... and parachain native token
274 expect(balanceUniqueAfter == balanceUniqueBefore).to.be.true;
275 });
276
277 itSub('Should connect and send USDT from Unique to Statemint back', async ({helper}) => {
278 const destination = {
279 V1: {
280 parents: 1,
281 interior: {X2: [
282 {
283 Parachain: STATEMINT_CHAIN,
284 },
285 {
286 AccountId32: {
287 network: 'Any',
288 id: alice.addressRaw,
289 },
290 },
291 ]},
292 },
293 };
294
295 const relayFee = 400_000_000_000_000n;
296 const currencies: [any, bigint][] = [
297 [
298 {
299 ForeignAssetId: 0,
300 },
301 TRANSFER_AMOUNT,
302 ],
303 [
304 {
305 NativeAssetId: 'Parent',
306 },
307 relayFee,
308 ],
309 ];
310
311 const feeItem = 1;
312
313 await helper.xTokens.transferMulticurrencies(alice, currencies, feeItem, destination, 'Unlimited');
314
315 // the commission has been paid in parachain native token
316 balanceUniqueFinal = await helper.balance.getSubstrate(alice.address);
317 console.log('[Unique -> Statemint] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(balanceUniqueFinal - balanceUniqueAfter));
318 expect(balanceUniqueAfter > balanceUniqueFinal).to.be.true;
319
320 await usingStatemintPlaygrounds(statemintUrl, async (helper) => {
321 await helper.wait.newBlocks(3);
322
323 // The USDT token never paid fees. Its amount not changed from begin value.
324 // Also check that xcm transfer has been succeeded
325 expect((await helper.assets.account(USDT_ASSET_ID, alice.address))! == USDT_ASSET_AMOUNT).to.be.true;
326 });
327 });
328
329 itSub('Should connect and send Relay token to Unique', async ({helper}) => {
330 balanceBobBefore = await helper.balance.getSubstrate(bob.address);
331 balanceBobRelayTokenBefore = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});
332
333 await usingRelayPlaygrounds(relayUrl, async (helper) => {
334 const destination = {
335 V1: {
336 parents: 0,
337 interior: {X1: {
338 Parachain: UNIQUE_CHAIN,
339 },
340 },
341 }};
342
343 const beneficiary = {
344 V1: {
345 parents: 0,
346 interior: {X1: {
347 AccountId32: {
348 network: 'Any',
349 id: bob.addressRaw,
350 },
351 }},
352 },
353 };
354
355 const assets = {
356 V1: [
357 {
358 id: {
359 Concrete: {
360 parents: 0,
361 interior: 'Here',
362 },
363 },
364 fun: {
365 Fungible: TRANSFER_AMOUNT_RELAY,
366 },
367 },
368 ],
369 };
370
371 const feeAssetItem = 0;
372
373 await helper.xcm.limitedReserveTransferAssets(bob, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
374 });
375
376 await helper.wait.newBlocks(3);
377
378 balanceBobAfter = await helper.balance.getSubstrate(bob.address);
379 balanceBobRelayTokenAfter = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});
380
381 const wndFeeOnUnique = balanceBobRelayTokenAfter - TRANSFER_AMOUNT_RELAY - balanceBobRelayTokenBefore;
382 const wndDiffOnUnique = balanceBobRelayTokenAfter - balanceBobRelayTokenBefore;
383 console.log(
384 '[Relay (Westend) -> Unique] transaction fees: %s UNQ',
385 helper.util.bigIntToDecimals(balanceBobAfter - balanceBobBefore),
386 );
387 console.log(
388 '[Relay (Westend) -> Unique] transaction fees: %s WND',
389 helper.util.bigIntToDecimals(wndFeeOnUnique, STATEMINT_DECIMALS),
390 );
391 console.log('[Relay (Westend) -> Unique] actually delivered: %s WND', wndDiffOnUnique);
392 expect(wndFeeOnUnique == 0n, 'No incoming WND fees should be taken').to.be.true;
393 expect(balanceBobBefore == balanceBobAfter, 'No incoming UNQ fees should be taken').to.be.true;
394 });
395
396 itSub('Should connect and send Relay token back', async ({helper}) => {
397 let relayTokenBalanceBefore: bigint;
398 let relayTokenBalanceAfter: bigint;
399 await usingRelayPlaygrounds(relayUrl, async (helper) => {
400 relayTokenBalanceBefore = await helper.balance.getSubstrate(bob.address);
401 });
402
403 const destination = {
404 V1: {
405 parents: 1,
406 interior: {
407 X1:{
408 AccountId32: {
409 network: 'Any',
410 id: bob.addressRaw,
411 },
412 },
413 },
414 },
415 };
416
417 const currencies: any = [
418 [
419 {
420 NativeAssetId: 'Parent',
421 },
422 TRANSFER_AMOUNT_RELAY,
423 ],
424 ];
425
426 const feeItem = 0;
427
428 await helper.xTokens.transferMulticurrencies(bob, currencies, feeItem, destination, 'Unlimited');
429
430 balanceBobFinal = await helper.balance.getSubstrate(bob.address);
431 console.log('[Unique -> Relay (Westend)] transaction fees: %s UNQ', helper.util.bigIntToDecimals(balanceBobAfter - balanceBobFinal));
432
433 await usingRelayPlaygrounds(relayUrl, async (helper) => {
434 await helper.wait.newBlocks(10);
435 relayTokenBalanceAfter = await helper.balance.getSubstrate(bob.address);
436
437 const diff = relayTokenBalanceAfter - relayTokenBalanceBefore;
438 console.log('[Unique -> Relay (Westend)] actually delivered: %s WND', helper.util.bigIntToDecimals(diff, RELAY_DECIMALS));
439 expect(diff > 0, 'Relay tokens was not delivered back').to.be.true;
440 });
441 });
442});
443
35describeXCM('[XCM] Integration test: Exchanging tokens with Acala', () => {444describeXCM('[XCM] Integration test: Exchanging tokens with Acala', () => {
36 let alice: IKeyringPair;445 let alice: IKeyringPair;
124 };533 };
125534
126 const feeAssetItem = 0;535 const feeAssetItem = 0;
127 const weightLimit = 5000000000;
128536
129 await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, weightLimit);537 await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
130
131 balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);538 balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);
132539
133 const unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;540 const unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;
134 console.log('[Unique -> Acala] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));541 console.log('[Unique -> Acala] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));
135 expect(unqFees > 0n).to.be.true;542 expect(unqFees > 0n, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;
136543
137 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {544 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
138 await helper.wait.newBlocks(3);545 await helper.wait.newBlocks(3);
176 ForeignAsset: 0,583 ForeignAsset: 0,
177 };584 };
178585
179 const destWeight = 50000000;586 await helper.xTokens.transfer(randomAccount, id, TRANSFER_AMOUNT, destination, 'Unlimited');
180
181 await helper.xTokens.transfer(randomAccount, id, TRANSFER_AMOUNT, destination, destWeight);
182
183 balanceAcalaTokenFinal = await helper.balance.getSubstrate(randomAccount.address);587 balanceAcalaTokenFinal = await helper.balance.getSubstrate(randomAccount.address);
184 balanceUniqueForeignTokenFinal = await helper.tokens.accounts(randomAccount.address, id);588 balanceUniqueForeignTokenFinal = await helper.tokens.accounts(randomAccount.address, id);
192 );596 );
193 console.log('[Acala -> Unique] outcome %s UNQ', helper.util.bigIntToDecimals(unqOutcomeTransfer));597 console.log('[Acala -> Unique] outcome %s UNQ', helper.util.bigIntToDecimals(unqOutcomeTransfer));
194598
195 expect(acaFees > 0).to.be.true;599 expect(acaFees > 0, 'Negative fees ACA, looks like nothing was transferred').to.be.true;
196 expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;600 expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;
197 });601 });
198602
220 });624 });
221 });625 });
222626
223 itSub('Unique rejects tokens from the Relay', async ({helper}) => {
224 await usingRelayPlaygrounds(relayUrl, async (helper) => {
225 const destination = {
226 V1: {
227 parents: 0,
228 interior: {X1: {
229 Parachain: UNIQUE_CHAIN,
230 },
231 },
232 }};
233
234 const beneficiary = {
235 V1: {
236 parents: 0,
237 interior: {X1: {
238 AccountId32: {
239 network: 'Any',
240 id: alice.addressRaw,
241 },
242 }},
243 },
244 };
245
246 const assets = {
247 V1: [
248 {
249 id: {
250 Concrete: {
251 parents: 0,
252 interior: 'Here',
253 },
254 },
255 fun: {
256 Fungible: 50_000_000_000_000_000n,
257 },
258 },
259 ],
260 };
261
262 const feeAssetItem = 0;
263 const weightLimit = 5_000_000_000;
264
265 await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, weightLimit);
266 });
267
268 const maxWaitBlocks = 3;
269
270 const dmpQueueExecutedDownward = await helper.wait.event(maxWaitBlocks, 'dmpQueue', 'ExecutedDownward');
271
272 expect(
273 dmpQueueExecutedDownward != null,
274 '[Relay] dmpQueue.ExecutedDownward event is expected',
275 ).to.be.true;
276
277 const event = dmpQueueExecutedDownward!.event;
278 const outcome = event.data[1] as XcmV2TraitsOutcome;
279
280 expect(
281 outcome.isIncomplete,
282 '[Relay] The outcome of the XCM should be `Incomplete`',
283 ).to.be.true;
284
285 const incomplete = outcome.asIncomplete;
286 expect(
287 incomplete[1].toString() == 'AssetNotFound',
288 '[Relay] The XCM error should be `AssetNotFound`',
289 ).to.be.true;
290 });
291
292 itSub('Unique rejects ACA tokens from Acala', async ({helper}) => {627 itSub('Unique rejects ACA tokens from Acala', async ({helper}) => {
293 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {628 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
294 const destination = {629 const destination = {
311 const id = {646 const id = {
312 Token: 'ACA',647 Token: 'ACA',
313 };648 };
314
315 const destWeight = 50000000;
316649
317 await helper.xTokens.transfer(alice, id, 100_000_000_000n, destination, destWeight);650 await helper.xTokens.transfer(alice, id, 100_000_000_000n, destination, 'Unlimited');
318 });651 });
319652
320 const maxWaitBlocks = 3;653 const maxWaitBlocks = 3;
330 const outcome = event.data[1] as XcmV2TraitsError;663 const outcome = event.data[1] as XcmV2TraitsError;
331664
332 expect(665 expect(
333 outcome.isUntrustedReserveLocation,666 outcome.isFailedToTransactAsset,
334 '[Acala] The XCM error should be `UntrustedReserveLocation`',667 '[Acala] The XCM error should be `FailedToTransactAsset`',
335 ).to.be.true;668 ).to.be.true;
336 });669 });
337});670});
508 },841 },
509 };842 };
510 const amount = TRANSFER_AMOUNT;843 const amount = TRANSFER_AMOUNT;
511 const destWeight = 850000000;
512844
513 await helper.xTokens.transfer(randomAccountUnique, currencyId, amount, dest, destWeight);845 await helper.xTokens.transfer(randomAccountUnique, currencyId, amount, dest, 'Unlimited');
514846
515 balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccountUnique.address);847 balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccountUnique.address);
516 expect(balanceUniqueTokenMiddle < balanceUniqueTokenInit).to.be.true;848 expect(balanceUniqueTokenMiddle < balanceUniqueTokenInit).to.be.true;
517849
518 const transactionFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;850 const transactionFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;
519 console.log('[Unique -> Moonbeam] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(transactionFees));851 console.log('[Unique -> Moonbeam] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(transactionFees));
520 expect(transactionFees > 0).to.be.true;852 expect(transactionFees > 0, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;
521853
522 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {854 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
523 await helper.wait.newBlocks(3);855 await helper.wait.newBlocks(3);
572904
573 const glmrFees = balanceGlmrTokenMiddle - balanceGlmrTokenFinal;905 const glmrFees = balanceGlmrTokenMiddle - balanceGlmrTokenFinal;
574 console.log('[Moonbeam -> Unique] transaction fees on Moonbeam: %s GLMR', helper.util.bigIntToDecimals(glmrFees));906 console.log('[Moonbeam -> Unique] transaction fees on Moonbeam: %s GLMR', helper.util.bigIntToDecimals(glmrFees));
575 expect(glmrFees > 0).to.be.true;907 expect(glmrFees > 0, 'Negative fees GLMR, looks like nothing was transferred').to.be.true;
576908
577 const unqRandomAccountAsset = await helper.assets.account(assetId, randomAccountMoonbeam.address);909 const unqRandomAccountAsset = await helper.assets.account(assetId, randomAccountMoonbeam.address);
578910