difftreelog
Merge pull request #908 from UniqueNetwork/fix/xcmv3-tests
in: master
Fix/xcmv3 tests
8 files changed
.docker/additional/xcm-rococo/Dockerfile-xcm-opal-rococo.tempdiffbeforeafterboth--- a/.docker/additional/xcm-rococo/Dockerfile-xcm-opal-rococo.temp
+++ b/.docker/additional/xcm-rococo/Dockerfile-xcm-opal-rococo.temp
@@ -1,5 +1,5 @@
-FROM uniquenetwork/builder-polkadot:{{ POLKADOT_BUILD_BRANCH }} as polkadot
-FROM uniquenetwork/builder-cumulus:{{ STATEMINE_BUILD_BRANCH }} as cumulus
+FROM uniquenetwork/builder-polkadot:{{ UNIQUEWEST_MAINNET_BRANCH }} as polkadot
+FROM uniquenetwork/builder-cumulus:{{ WESTMINT_BUILD_BRANCH }} as cumulus
# ===== Rust builder =====
FROM ubuntu:22.04 as rust-builder
@@ -60,6 +60,7 @@
yarn install
COPY --from=builder-unique /unique_parachain/.docker/additional/xcm-rococo/launch-config-xcm-opal-rococo.json /polkadot-launch/launch-config.json
+COPY --from=builder-unique /unique_parachain/.docker/xcm-config/5validators.jsonnet /polkadot-launch/5validators.jsonnet
COPY --from=builder-unique /unique_parachain/target/release/unique-collator /unique-chain/target/release/
COPY --from=polkadot /unique_parachain/polkadot/target/release/polkadot /polkadot/target/release/
.docker/additional/xcm-rococo/Dockerfile-xcm-quartz-rococo.tempdiffbeforeafterboth--- a/.docker/additional/xcm-rococo/Dockerfile-xcm-quartz-rococo.temp
+++ b/.docker/additional/xcm-rococo/Dockerfile-xcm-quartz-rococo.temp
@@ -1,4 +1,4 @@
-FROM uniquenetwork/builder-polkadot:{{ POLKADOT_BUILD_BRANCH }} as polkadot
+FROM uniquenetwork/builder-polkadot:{{ KUSAMA_MAINNET_BRANCH }} as polkadot
FROM uniquenetwork/builder-moonbeam:{{ MOONRIVER_BUILD_BRANCH }} as moonbeam
FROM uniquenetwork/builder-cumulus:{{ STATEMINE_BUILD_BRANCH }} as cumulus
FROM uniquenetwork/builder-acala:{{ KARURA_BUILD_BRANCH }} as acala
.docker/additional/xcm-rococo/Dockerfile-xcm-unique-rococo.tempdiffbeforeafterboth--- a/.docker/additional/xcm-rococo/Dockerfile-xcm-unique-rococo.temp
+++ b/.docker/additional/xcm-rococo/Dockerfile-xcm-unique-rococo.temp
@@ -1,4 +1,4 @@
-FROM uniquenetwork/builder-polkadot:{{ POLKADOT_BUILD_BRANCH }} as polkadot
+FROM uniquenetwork/builder-polkadot:{{ POLKADOT_MAINNET_BRANCH }} as polkadot
FROM uniquenetwork/builder-moonbeam:{{ MOONBEAM_BUILD_BRANCH }} as moonbeam
FROM uniquenetwork/builder-cumulus:{{ STATEMINT_BUILD_BRANCH }} as cumulus
FROM uniquenetwork/builder-acala:{{ ACALA_BUILD_BRANCH }} as acala
.envdiffbeforeafterboth--- a/.env
+++ b/.env
@@ -3,22 +3,22 @@
POLKADOT_LAUNCH_BRANCH=unique-network
RELAY_CHAIN_TYPE=westend
-POLKADOT_MAINNET_BRANCH=release-v0.9.36
-STATEMINT_BUILD_BRANCH=release-parachains-v9360
+POLKADOT_MAINNET_BRANCH=release-v0.9.37
+STATEMINT_BUILD_BRANCH=release-parachains-v9370
ACALA_BUILD_BRANCH=2.12.0
-MOONBEAM_BUILD_BRANCH=runtime-2000
+MOONBEAM_BUILD_BRANCH=runtime-2100
UNIQUE_MAINNET_BRANCH=release-v930033-fix-gas-price
UNIQUE_REPLICA_FROM=wss://ws.unique.network:443
KUSAMA_MAINNET_BRANCH=release-v0.9.37
-STATEMINE_BUILD_BRANCH=release-parachains-v9360
-KARURA_BUILD_BRANCH=release-karura-2.12.0
-MOONRIVER_BUILD_BRANCH=runtime-2100
+STATEMINE_BUILD_BRANCH=release-parachains-v9370
+KARURA_BUILD_BRANCH=release-karura-2.15.0
+MOONRIVER_BUILD_BRANCH=runtime-2201
QUARTZ_MAINNET_BRANCH=release-v930034-fix-gas-price
QUARTZ_REPLICA_FROM=wss://ws-quartz.unique.network:443
-UNIQUEWEST_MAINNET_BRANCH=release-v0.9.36
-WESTMINT_BUILD_BRANCH=parachains-v9370
+UNIQUEWEST_MAINNET_BRANCH=release-v0.9.40
+WESTMINT_BUILD_BRANCH=release-parachains-v9382
OPAL_MAINNET_BRANCH=release-v937052
OPAL_REPLICA_FROM=wss://ws-opal.unique.network:443
.github/workflows/xcm.ymldiffbeforeafterboth--- a/.github/workflows/xcm.yml
+++ b/.github/workflows/xcm.yml
@@ -40,9 +40,9 @@
id: create_matrix
with:
matrix: |
- network {opal}, acala_version {${{ env.ACALA_BUILD_BRANCH }}}, moonbeam_version {${{ env.MOONBEAM_BUILD_BRANCH }}}, cumulus_version {${{ env.WESTMINT_BUILD_BRANCH }}}, runtest {testXcmOpal}
- network {quartz}, acala_version {${{ env.KARURA_BUILD_BRANCH }}}, moonbeam_version {${{ env.MOONRIVER_BUILD_BRANCH }}}, cumulus_version {${{ env.STATEMINE_BUILD_BRANCH }}}, runtest {testXcmQuartz}
- network {unique}, acala_version {${{ env.ACALA_BUILD_BRANCH }}}, moonbeam_version {${{ env.MOONBEAM_BUILD_BRANCH }}}, cumulus_version {${{ env.STATEMINT_BUILD_BRANCH }}}, runtest {testXcmUnique}
+ network {opal}, relay_branch {${{ env.UNIQUEWEST_MAINNET_BRANCH }}}, acala_version {${{ env.ACALA_BUILD_BRANCH }}}, moonbeam_version {${{ env.MOONBEAM_BUILD_BRANCH }}}, cumulus_version {${{ env.WESTMINT_BUILD_BRANCH }}}, runtest {testXcmOpal}
+ network {quartz}, relay_branch {${{ env.KUSAMA_MAINNET_BRANCH }}}, acala_version {${{ env.KARURA_BUILD_BRANCH }}}, moonbeam_version {${{ env.MOONRIVER_BUILD_BRANCH }}}, cumulus_version {${{ env.STATEMINE_BUILD_BRANCH }}}, runtest {testXcmQuartz}
+ network {unique}, relay_branch {${{ env.POLKADOT_MAINNET_BRANCH }}}, acala_version {${{ env.ACALA_BUILD_BRANCH }}}, moonbeam_version {${{ env.MOONBEAM_BUILD_BRANCH }}}, cumulus_version {${{ env.STATEMINT_BUILD_BRANCH }}}, runtest {testXcmUnique}
xcm-build:
@@ -90,10 +90,10 @@
uses: cuchi/jinja2-action@v1.2.0
with:
template: .docker/Dockerfile-polkadot.j2
- output_file: .docker/Dockerfile-polkadot.${{ env.POLKADOT_BUILD_BRANCH }}.yml
+ output_file: .docker/Dockerfile-polkadot.${{ matrix.relay_branch }}.yml
variables: |
RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }}
- POLKADOT_BUILD_BRANCH=${{ env.POLKADOT_BUILD_BRANCH }}
+ POLKADOT_BUILD_BRANCH=${{ matrix.relay_branch }}
- name: Check if the dockerhub repository contains the needed version POLKADOT
run: |
@@ -107,14 +107,14 @@
echo "POLKADOT TAGS:"
echo $POLKADOT_TAGS
# Check correct version POLKADOT and build it if it doesn't exist in POLKADOT TAGS
- if [[ ${POLKADOT_TAGS[*]} =~ (^|[[:space:]])"${{ env.POLKADOT_BUILD_BRANCH }}"($|[[:space:]]) ]]; then
+ if [[ ${POLKADOT_TAGS[*]} =~ (^|[[:space:]])"${{ matrix.relay_branch }}"($|[[:space:]]) ]]; then
echo "Repository has needed POLKADOT version";
- docker pull uniquenetwork/builder-polkadot:${{ env.POLKADOT_BUILD_BRANCH }}
+ docker pull uniquenetwork/builder-polkadot:${{ matrix.relay_branch }}
else
echo "Repository has not needed POLKADOT version, so build it";
- cd .docker/ && docker build --no-cache --file ./Dockerfile-polkadot.${{ env.POLKADOT_BUILD_BRANCH }}.yml --tag uniquenetwork/builder-polkadot:${{ env.POLKADOT_BUILD_BRANCH }} .
+ cd .docker/ && docker build --no-cache --file ./Dockerfile-polkadot.${{ matrix.relay_branch }}.yml --tag uniquenetwork/builder-polkadot:${{ matrix.relay_branch }} .
echo "Push needed POLKADOT version to the repository";
- docker push uniquenetwork/builder-polkadot:${{ env.POLKADOT_BUILD_BRANCH }}
+ docker push uniquenetwork/builder-polkadot:${{ matrix.relay_branch }}
fi
shell: bash
@@ -238,7 +238,7 @@
variables: |
RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }}
NETWORK=${{ matrix.network }}
- POLKADOT_BUILD_BRANCH=${{ env.POLKADOT_BUILD_BRANCH }}
+ POLKADOT_BUILD_BRANCH=${{ matrix.relay_branch }}
POLKADOT_LAUNCH_BRANCH=${{ env.POLKADOT_LAUNCH_BRANCH }}
BRANCH=${{ github.head_ref }}
ACALA_BUILD_BRANCH=${{ matrix.acala_version }}
tests/src/util/playgrounds/unique.tsdiffbeforeafterboth--- a/tests/src/util/playgrounds/unique.ts
+++ b/tests/src/util/playgrounds/unique.ts
@@ -2951,6 +2951,10 @@
await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.limitedReserveTransferAssets`, [destination, beneficiary, assets, feeAssetItem, weightLimit], true);
}
+ async setSafeXcmVersion(signer: TSigner, version: number) {
+ await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.forceDefaultXcmVersion`, [version], true);
+ }
+
async teleportAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number) {
await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.teleportAssets`, [destination, beneficiary, assets, feeAssetItem], true);
}
tests/src/xcm/xcmQuartz.test.tsdiffbeforeafterboth--- a/tests/src/xcm/xcmQuartz.test.ts
+++ b/tests/src/xcm/xcmQuartz.test.ts
@@ -49,6 +49,8 @@
const USDT_ASSET_METADATA_MINIMAL_BALANCE = 1n;
const USDT_ASSET_AMOUNT = 10_000_000_000_000_000_000_000_000n;
+const SAFE_XCM_VERSION = 2;
+
describeXCM('[XCM] Integration test: Exchanging USDT with Statemine', () => {
let alice: IKeyringPair;
let bob: IKeyringPair;
@@ -69,9 +71,12 @@
before(async () => {
- await usingPlaygrounds(async (_helper, privateKey) => {
+ await usingPlaygrounds(async (helper, privateKey) => {
alice = await privateKey('//Alice');
bob = await privateKey('//Bob'); // sovereign account on Statemine(t) funds donor
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
});
await usingRelayPlaygrounds(relayUrl, async (helper) => {
@@ -145,7 +150,7 @@
// (fee for USDT XCM are paid in relay tokens)
await usingRelayPlaygrounds(relayUrl, async (helper) => {
const destination = {
- V2: {
+ V1: {
parents: 0,
interior: {X1: {
Parachain: QUARTZ_CHAIN,
@@ -154,7 +159,7 @@
}};
const beneficiary = {
- V2: {
+ V1: {
parents: 0,
interior: {X1: {
AccountId32: {
@@ -166,7 +171,7 @@
};
const assets = {
- V2: [
+ V1: [
{
id: {
Concrete: {
@@ -191,7 +196,7 @@
itSub('Should connect and send USDT from Statemine to Quartz', async ({helper}) => {
await usingStateminePlaygrounds(statemineUrl, async (helper) => {
const dest = {
- V2: {
+ V1: {
parents: 1,
interior: {X1: {
Parachain: QUARTZ_CHAIN,
@@ -200,7 +205,7 @@
}};
const beneficiary = {
- V2: {
+ V1: {
parents: 0,
interior: {X1: {
AccountId32: {
@@ -212,7 +217,7 @@
};
const assets = {
- V2: [
+ V1: [
{
id: {
Concrete: {
@@ -314,7 +319,7 @@
// the commission has been paid in parachain native token
balanceQuartzFinal = await helper.balance.getSubstrate(alice.address);
- console.log('[Quartz -> Statemine] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(balanceQuartzFinal - balanceQuartzAfter));
+ console.log('[Quartz -> Statemine] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(balanceQuartzAfter - balanceQuartzFinal));
expect(balanceQuartzAfter > balanceQuartzFinal).to.be.true;
await usingStateminePlaygrounds(statemineUrl, async (helper) => {
@@ -332,7 +337,7 @@
await usingRelayPlaygrounds(relayUrl, async (helper) => {
const destination = {
- V2: {
+ V1: {
parents: 0,
interior: {X1: {
Parachain: QUARTZ_CHAIN,
@@ -341,7 +346,7 @@
}};
const beneficiary = {
- V2: {
+ V1: {
parents: 0,
interior: {X1: {
AccountId32: {
@@ -353,7 +358,7 @@
};
const assets = {
- V2: [
+ V1: [
{
id: {
Concrete: {
@@ -466,11 +471,14 @@
await usingPlaygrounds(async (helper, privateKey) => {
alice = await privateKey('//Alice');
[randomAccount] = await helper.arrange.createAccounts([0n], alice);
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
});
await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
const destination = {
- V2: {
+ V1: {
parents: 1,
interior: {
X1: {
@@ -580,7 +588,7 @@
itSub('Should connect to Karura and send QTZ back', async ({helper}) => {
await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
const destination = {
- V2: {
+ V1: {
parents: 1,
interior: {
X2: [
@@ -636,15 +644,18 @@
let alice: IKeyringPair;
before(async () => {
- await usingPlaygrounds(async (_helper, privateKey) => {
+ await usingPlaygrounds(async (helper, privateKey) => {
alice = await privateKey('//Alice');
+
+ // Set the default version to wrap the first message to other chains.
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
});
});
itSub('Quartz rejects KAR tokens from Karura', async ({helper}) => {
await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
const destination = {
- V2: {
+ V1: {
parents: 1,
interior: {
X2: [
@@ -726,6 +737,10 @@
[randomAccountQuartz] = await helper.arrange.createAccounts([0n], quartzDonor);
balanceForeignQtzTokenInit = 0n;
+
+ // Set the default version to wrap the first message to other chains.
+ const alice = quartzDonor;
+ await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
});
await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
@@ -905,7 +920,7 @@
itSub('Should connect to Moonriver and send QTZ back', async ({helper}) => {
await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
const asset = {
- V2: {
+ V1: {
id: {
Concrete: {
parents: 1,
@@ -920,7 +935,7 @@
},
};
const destination = {
- V2: {
+ V1: {
parents: 1,
interior: {
X2: [
tests/src/xcm/xcmUnique.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 {XcmV2TraitsError} from '../interfaces';21import {itSub, expect, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingRelayPlaygrounds, usingMoonbeamPlaygrounds, usingStatemintPlaygrounds} from '../util';2223const UNIQUE_CHAIN = 2037;24const STATEMINT_CHAIN = 1000;25const ACALA_CHAIN = 2000;26const MOONBEAM_CHAIN = 2004;2728const STATEMINT_PALLET_INSTANCE = 50;2930const relayUrl = config.relayUrl;31const statemintUrl = config.statemintUrl;32const acalaUrl = config.acalaUrl;33const moonbeamUrl = config.moonbeamUrl;3435const RELAY_DECIMALS = 12;36const STATEMINT_DECIMALS = 12;37const ACALA_DECIMALS = 12;3839const TRANSFER_AMOUNT = 2000000000000000000000000n;4041const FUNDING_AMOUNT = 3_500_000_0000_000_000n;4243const TRANSFER_AMOUNT_RELAY = 50_000_000_000_000_000n;4445const 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;5152describeXCM('[XCM] Integration test: Exchanging USDT with Statemint', () => {53 let alice: IKeyringPair;54 let bob: IKeyringPair;5556 let balanceStmnBefore: bigint;57 let balanceStmnAfter: bigint;5859 let balanceUniqueBefore: bigint;60 let balanceUniqueAfter: bigint;61 let balanceUniqueFinal: bigint;6263 let balanceBobBefore: bigint;64 let balanceBobAfter: bigint;65 let balanceBobFinal: bigint;6667 let balanceBobRelayTokenBefore: bigint;68 let balanceBobRelayTokenAfter: bigint;697071 before(async () => {72 await usingPlaygrounds(async (_helper, privateKey) => {73 alice = await privateKey('//Alice');74 bob = await privateKey('//Bob'); // sovereign account on Statemint funds donor75 });7677 await usingRelayPlaygrounds(relayUrl, async (helper) => {78 // Fund accounts on Statemint79 await helper.xcm.teleportNativeAsset(alice, STATEMINT_CHAIN, alice.addressRaw, FUNDING_AMOUNT);80 await helper.xcm.teleportNativeAsset(alice, STATEMINT_CHAIN, bob.addressRaw, FUNDING_AMOUNT);81 });8283 await usingStatemintPlaygrounds(statemintUrl, async (helper) => {84 const sovereignFundingAmount = 3_500_000_000n;8586 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 );105106 // funding parachain sovereing account on Statemint.107 // The sovereign account should be created before any action108 // (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 });112113114 await usingPlaygrounds(async (helper) => {115 const location = {116 V2: {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 };131132 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 });142143144 // Providing the relay currency to the unique sender account145 // (fee for USDT XCM are paid in relay tokens)146 await usingRelayPlaygrounds(relayUrl, async (helper) => {147 const destination = {148 V2: {149 parents: 0,150 interior: {X1: {151 Parachain: UNIQUE_CHAIN,152 },153 },154 }};155156 const beneficiary = {157 V2: {158 parents: 0,159 interior: {X1: {160 AccountId32: {161 network: 'Any',162 id: alice.addressRaw,163 },164 }},165 },166 };167168 const assets = {169 V2: [170 {171 id: {172 Concrete: {173 parents: 0,174 interior: 'Here',175 },176 },177 fun: {178 Fungible: TRANSFER_AMOUNT_RELAY,179 },180 },181 ],182 };183184 const feeAssetItem = 0;185186 await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, 'Unlimited');187 });188189 });190191 itSub('Should connect and send USDT from Statemint to Unique', async ({helper}) => {192 await usingStatemintPlaygrounds(statemintUrl, async (helper) => {193 const dest = {194 V2: {195 parents: 1,196 interior: {X1: {197 Parachain: UNIQUE_CHAIN,198 },199 },200 }};201202 const beneficiary = {203 V2: {204 parents: 0,205 interior: {X1: {206 AccountId32: {207 network: 'Any',208 id: alice.addressRaw,209 },210 }},211 },212 };213214 const assets = {215 V2: [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 };237238 const feeAssetItem = 0;239240 balanceStmnBefore = await helper.balance.getSubstrate(alice.address);241 await helper.xcm.limitedReserveTransferAssets(alice, dest, beneficiary, assets, feeAssetItem, 'Unlimited');242243 balanceStmnAfter = await helper.balance.getSubstrate(alice.address);244245 // common good parachain take commission in it native token246 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;251252 });253254255 // ensure that asset has been delivered256 await helper.wait.newBlocks(3);257258 // expext collection id will be with id 1259 const free = await helper.ft.getBalance(1, {Substrate: alice.address});260261 balanceUniqueAfter = await helper.balance.getSubstrate(alice.address);262263 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 token272 expect(free).to.be.equal(TRANSFER_AMOUNT);273 // ... and parachain native token274 expect(balanceUniqueAfter == balanceUniqueBefore).to.be.true;275 });276277 itSub('Should connect and send USDT from Unique to Statemint back', async ({helper}) => {278 const destination = {279 V2: {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 };294295 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 ];310311 const feeItem = 1;312313 await helper.xTokens.transferMulticurrencies(alice, currencies, feeItem, destination, 'Unlimited');314315 // the commission has been paid in parachain native token316 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;319320 await usingStatemintPlaygrounds(statemintUrl, async (helper) => {321 await helper.wait.newBlocks(3);322323 // The USDT token never paid fees. Its amount not changed from begin value.324 // Also check that xcm transfer has been succeeded325 expect((await helper.assets.account(USDT_ASSET_ID, alice.address))! == USDT_ASSET_AMOUNT).to.be.true;326 });327 });328329 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'});332333 await usingRelayPlaygrounds(relayUrl, async (helper) => {334 const destination = {335 V2: {336 parents: 0,337 interior: {X1: {338 Parachain: UNIQUE_CHAIN,339 },340 },341 }};342343 const beneficiary = {344 V2: {345 parents: 0,346 interior: {X1: {347 AccountId32: {348 network: 'Any',349 id: bob.addressRaw,350 },351 }},352 },353 };354355 const assets = {356 V2: [357 {358 id: {359 Concrete: {360 parents: 0,361 interior: 'Here',362 },363 },364 fun: {365 Fungible: TRANSFER_AMOUNT_RELAY,366 },367 },368 ],369 };370371 const feeAssetItem = 0;372373 await helper.xcm.limitedReserveTransferAssets(bob, destination, beneficiary, assets, feeAssetItem, 'Unlimited');374 });375376 await helper.wait.newBlocks(3);377378 balanceBobAfter = await helper.balance.getSubstrate(bob.address);379 balanceBobRelayTokenAfter = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});380381 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 });395396 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 });402403 const destination = {404 V2: {405 parents: 1,406 interior: {407 X1:{408 AccountId32: {409 network: 'Any',410 id: bob.addressRaw,411 },412 },413 },414 },415 };416417 const currencies: any = [418 [419 {420 NativeAssetId: 'Parent',421 },422 TRANSFER_AMOUNT_RELAY,423 ],424 ];425426 const feeItem = 0;427428 await helper.xTokens.transferMulticurrencies(bob, currencies, feeItem, destination, 'Unlimited');429430 balanceBobFinal = await helper.balance.getSubstrate(bob.address);431 console.log('[Unique -> Relay (Westend)] transaction fees: %s UNQ', helper.util.bigIntToDecimals(balanceBobAfter - balanceBobFinal));432433 await usingRelayPlaygrounds(relayUrl, async (helper) => {434 await helper.wait.newBlocks(10);435 relayTokenBalanceAfter = await helper.balance.getSubstrate(bob.address);436437 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});443444describeXCM('[XCM] Integration test: Exchanging tokens with Acala', () => {445 let alice: IKeyringPair;446 let randomAccount: IKeyringPair;447448 let balanceUniqueTokenInit: bigint;449 let balanceUniqueTokenMiddle: bigint;450 let balanceUniqueTokenFinal: bigint;451 let balanceAcalaTokenInit: bigint;452 let balanceAcalaTokenMiddle: bigint;453 let balanceAcalaTokenFinal: bigint;454 let balanceUniqueForeignTokenInit: bigint;455 let balanceUniqueForeignTokenMiddle: bigint;456 let balanceUniqueForeignTokenFinal: bigint;457458 // computed by a test transfer from prod Unique to prod Acala.459 // 2 UNQ sent https://unique.subscan.io/xcm_message/polkadot-bad0b68847e2398af25d482e9ee6f9c1f9ec2a48460 // 1.898970000000000000 UNQ received (you can check Acala's chain state in the corresponding block)461 const expectedAcalaIncomeFee = 2000000000000000000n - 1898970000000000000n;462463 const ACALA_BACKWARD_TRANSFER_AMOUNT = TRANSFER_AMOUNT - expectedAcalaIncomeFee;464465 before(async () => {466 await usingPlaygrounds(async (helper, privateKey) => {467 alice = await privateKey('//Alice');468 [randomAccount] = await helper.arrange.createAccounts([0n], alice);469 });470471 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {472 const destination = {473 V2: {474 parents: 1,475 interior: {476 X1: {477 Parachain: UNIQUE_CHAIN,478 },479 },480 },481 };482483 const metadata = {484 name: 'Unique Network',485 symbol: 'UNQ',486 decimals: 18,487 minimalBalance: 1250000000000000000n,488 };489490 await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);491 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);492 balanceAcalaTokenInit = await helper.balance.getSubstrate(randomAccount.address);493 balanceUniqueForeignTokenInit = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});494 });495496 await usingPlaygrounds(async (helper) => {497 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10n * TRANSFER_AMOUNT);498 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);499 });500 });501502 itSub('Should connect and send UNQ to Acala', async ({helper}) => {503504 const destination = {505 V2: {506 parents: 1,507 interior: {508 X1: {509 Parachain: ACALA_CHAIN,510 },511 },512 },513 };514515 const beneficiary = {516 V2: {517 parents: 0,518 interior: {519 X1: {520 AccountId32: {521 network: 'Any',522 id: randomAccount.addressRaw,523 },524 },525 },526 },527 };528529 const assets = {530 V2: [531 {532 id: {533 Concrete: {534 parents: 0,535 interior: 'Here',536 },537 },538 fun: {539 Fungible: TRANSFER_AMOUNT,540 },541 },542 ],543 };544545 const feeAssetItem = 0;546547 await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');548 balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);549550 const unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;551 console.log('[Unique -> Acala] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));552 expect(unqFees > 0n, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;553554 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {555 await helper.wait.newBlocks(3);556557 balanceUniqueForeignTokenMiddle = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});558 balanceAcalaTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);559560 const acaFees = balanceAcalaTokenInit - balanceAcalaTokenMiddle;561 const unqIncomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenInit;562 const acaUnqFees = TRANSFER_AMOUNT - unqIncomeTransfer;563564 console.log(565 '[Unique -> Acala] transaction fees on Acala: %s ACA',566 helper.util.bigIntToDecimals(acaFees, ACALA_DECIMALS),567 );568 console.log(569 '[Unique -> Acala] transaction fees on Acala: %s UNQ',570 helper.util.bigIntToDecimals(acaUnqFees),571 );572 console.log('[Unique -> Acala] income %s UNQ', helper.util.bigIntToDecimals(unqIncomeTransfer));573 expect(acaFees == 0n).to.be.true;574 expect(575 acaUnqFees == expectedAcalaIncomeFee,576 'Acala took different income fee, check the Acala foreign asset config',577 ).to.be.true;578 });579 });580581 itSub('Should connect to Acala and send UNQ back', async ({helper}) => {582 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {583 const destination = {584 V2: {585 parents: 1,586 interior: {587 X2: [588 {Parachain: UNIQUE_CHAIN},589 {590 AccountId32: {591 network: 'Any',592 id: randomAccount.addressRaw,593 },594 },595 ],596 },597 },598 };599600 const id = {601 ForeignAsset: 0,602 };603604 await helper.xTokens.transfer(randomAccount, id, ACALA_BACKWARD_TRANSFER_AMOUNT, destination, 'Unlimited');605 balanceAcalaTokenFinal = await helper.balance.getSubstrate(randomAccount.address);606 balanceUniqueForeignTokenFinal = await helper.tokens.accounts(randomAccount.address, id);607608 const acaFees = balanceAcalaTokenMiddle - balanceAcalaTokenFinal;609 const unqOutcomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenFinal;610611 console.log(612 '[Acala -> Unique] transaction fees on Acala: %s ACA',613 helper.util.bigIntToDecimals(acaFees, ACALA_DECIMALS),614 );615 console.log('[Acala -> Unique] outcome %s UNQ', helper.util.bigIntToDecimals(unqOutcomeTransfer));616617 expect(acaFees > 0, 'Negative fees ACA, looks like nothing was transferred').to.be.true;618 expect(unqOutcomeTransfer == ACALA_BACKWARD_TRANSFER_AMOUNT).to.be.true;619 });620621 await helper.wait.newBlocks(3);622623 balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccount.address);624 const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;625 expect(actuallyDelivered > 0).to.be.true;626627 console.log('[Acala -> Unique] actually delivered %s UNQ', helper.util.bigIntToDecimals(actuallyDelivered));628629 const unqFees = ACALA_BACKWARD_TRANSFER_AMOUNT - actuallyDelivered;630 console.log('[Acala -> Unique] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));631 expect(unqFees == 0n).to.be.true;632 });633});634635// These tests are relevant only when the foreign asset pallet is disabled636describeXCM('[XCM] Integration test: Unique rejects non-native tokens', () => {637 let alice: IKeyringPair;638639 before(async () => {640 await usingPlaygrounds(async (_helper, privateKey) => {641 alice = await privateKey('//Alice');642 });643 });644645 itSub('Unique rejects ACA tokens from Acala', async ({helper}) => {646 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {647 const destination = {648 V2: {649 parents: 1,650 interior: {651 X2: [652 {Parachain: UNIQUE_CHAIN},653 {654 AccountId32: {655 network: 'Any',656 id: alice.addressRaw,657 },658 },659 ],660 },661 },662 };663664 const id = {665 Token: 'ACA',666 };667668 await helper.xTokens.transfer(alice, id, 100_000_000_000n, destination, 'Unlimited');669 });670671 const maxWaitBlocks = 3;672673 const xcmpQueueFailEvent = await helper.wait.event(maxWaitBlocks, 'xcmpQueue', 'Fail');674675 expect(676 xcmpQueueFailEvent != null,677 '[Acala] xcmpQueue.FailEvent event is expected',678 ).to.be.true;679680 const event = xcmpQueueFailEvent!.event;681 const outcome = event.data[1] as XcmV2TraitsError;682683 expect(684 outcome.isFailedToTransactAsset,685 '[Acala] The XCM error should be `FailedToTransactAsset`',686 ).to.be.true;687 });688});689690describeXCM('[XCM] Integration test: Exchanging UNQ with Moonbeam', () => {691 // Unique constants692 let uniqueDonor: IKeyringPair;693 let uniqueAssetLocation;694695 let randomAccountUnique: IKeyringPair;696 let randomAccountMoonbeam: IKeyringPair;697698 // Moonbeam constants699 let assetId: string;700701 const councilVotingThreshold = 2;702 const technicalCommitteeThreshold = 2;703 const votingPeriod = 3;704 const delayPeriod = 0;705706 const uniqueAssetMetadata = {707 name: 'xcUnique',708 symbol: 'xcUNQ',709 decimals: 18,710 isFrozen: false,711 minimalBalance: 1n,712 };713714 let balanceUniqueTokenInit: bigint;715 let balanceUniqueTokenMiddle: bigint;716 let balanceUniqueTokenFinal: bigint;717 let balanceForeignUnqTokenInit: bigint;718 let balanceForeignUnqTokenMiddle: bigint;719 let balanceForeignUnqTokenFinal: bigint;720 let balanceGlmrTokenInit: bigint;721 let balanceGlmrTokenMiddle: bigint;722 let balanceGlmrTokenFinal: bigint;723724 before(async () => {725 await usingPlaygrounds(async (helper, privateKey) => {726 uniqueDonor = await privateKey('//Alice');727 [randomAccountUnique] = await helper.arrange.createAccounts([0n], uniqueDonor);728729 balanceForeignUnqTokenInit = 0n;730 });731732 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {733 const alithAccount = helper.account.alithAccount();734 const baltatharAccount = helper.account.baltatharAccount();735 const dorothyAccount = helper.account.dorothyAccount();736737 randomAccountMoonbeam = helper.account.create();738739 // >>> Sponsoring Dorothy >>>740 console.log('Sponsoring Dorothy.......');741 await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);742 console.log('Sponsoring Dorothy.......DONE');743 // <<< Sponsoring Dorothy <<<744745 uniqueAssetLocation = {746 XCM: {747 parents: 1,748 interior: {X1: {Parachain: UNIQUE_CHAIN}},749 },750 };751 const existentialDeposit = 1n;752 const isSufficient = true;753 const unitsPerSecond = 1n;754 const numAssetsWeightHint = 0;755756 const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({757 location: uniqueAssetLocation,758 metadata: uniqueAssetMetadata,759 existentialDeposit,760 isSufficient,761 unitsPerSecond,762 numAssetsWeightHint,763 });764 const proposalHash = blake2AsHex(encodedProposal);765766 console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);767 console.log('Encoded length %d', encodedProposal.length);768 console.log('Encoded proposal hash for batch utility after schedule is %s', proposalHash);769770 // >>> Note motion preimage >>>771 console.log('Note motion preimage.......');772 await helper.democracy.notePreimage(baltatharAccount, encodedProposal);773 console.log('Note motion preimage.......DONE');774 // <<< Note motion preimage <<<775776 // >>> Propose external motion through council >>>777 console.log('Propose external motion through council.......');778 const externalMotion = helper.democracy.externalProposeMajority({Legacy: proposalHash});779 const encodedMotion = externalMotion?.method.toHex() || '';780 const motionHash = blake2AsHex(encodedMotion);781 console.log('Motion hash is %s', motionHash);782783 await helper.collective.council.propose(baltatharAccount, councilVotingThreshold, externalMotion, externalMotion.encodedLength);784785 const councilProposalIdx = await helper.collective.council.proposalCount() - 1;786 await helper.collective.council.vote(dorothyAccount, motionHash, councilProposalIdx, true);787 await helper.collective.council.vote(baltatharAccount, motionHash, councilProposalIdx, true);788789 await helper.collective.council.close(790 dorothyAccount,791 motionHash,792 councilProposalIdx,793 {794 refTime: 1_000_000_000,795 proofSize: 1_000_000,796 },797 externalMotion.encodedLength,798 );799 console.log('Propose external motion through council.......DONE');800 // <<< Propose external motion through council <<<801802 // >>> Fast track proposal through technical committee >>>803 console.log('Fast track proposal through technical committee.......');804 const fastTrack = helper.democracy.fastTrack(proposalHash, votingPeriod, delayPeriod);805 const encodedFastTrack = fastTrack?.method.toHex() || '';806 const fastTrackHash = blake2AsHex(encodedFastTrack);807 console.log('FastTrack hash is %s', fastTrackHash);808809 await helper.collective.techCommittee.propose(alithAccount, technicalCommitteeThreshold, fastTrack, fastTrack.encodedLength);810811 const techProposalIdx = await helper.collective.techCommittee.proposalCount() - 1;812 await helper.collective.techCommittee.vote(baltatharAccount, fastTrackHash, techProposalIdx, true);813 await helper.collective.techCommittee.vote(alithAccount, fastTrackHash, techProposalIdx, true);814815 await helper.collective.techCommittee.close(816 baltatharAccount,817 fastTrackHash,818 techProposalIdx,819 {820 refTime: 1_000_000_000,821 proofSize: 1_000_000,822 },823 fastTrack.encodedLength,824 );825 console.log('Fast track proposal through technical committee.......DONE');826 // <<< Fast track proposal through technical committee <<<827828 // >>> Referendum voting >>>829 console.log('Referendum voting.......');830 await helper.democracy.referendumVote(dorothyAccount, 0, {831 balance: 10_000_000_000_000_000_000n,832 vote: {aye: true, conviction: 1},833 });834 console.log('Referendum voting.......DONE');835 // <<< Referendum voting <<<836837 // >>> Acquire Unique AssetId Info on Moonbeam >>>838 console.log('Acquire Unique AssetId Info on Moonbeam.......');839840 // Wait for the democracy execute841 await helper.wait.newBlocks(5);842843 assetId = (await helper.assetManager.assetTypeId(uniqueAssetLocation)).toString();844845 console.log('UNQ asset ID is %s', assetId);846 console.log('Acquire Unique AssetId Info on Moonbeam.......DONE');847 // >>> Acquire Unique AssetId Info on Moonbeam >>>848849 // >>> Sponsoring random Account >>>850 console.log('Sponsoring random Account.......');851 await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonbeam.address, 11_000_000_000_000_000_000n);852 console.log('Sponsoring random Account.......DONE');853 // <<< Sponsoring random Account <<<854855 balanceGlmrTokenInit = await helper.balance.getEthereum(randomAccountMoonbeam.address);856 });857858 await usingPlaygrounds(async (helper) => {859 await helper.balance.transferToSubstrate(uniqueDonor, randomAccountUnique.address, 10n * TRANSFER_AMOUNT);860 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccountUnique.address);861 });862 });863864 itSub('Should connect and send UNQ to Moonbeam', async ({helper}) => {865 const currencyId = {866 NativeAssetId: 'Here',867 };868 const dest = {869 V2: {870 parents: 1,871 interior: {872 X2: [873 {Parachain: MOONBEAM_CHAIN},874 {AccountKey20: {network: 'Any', key: randomAccountMoonbeam.address}},875 ],876 },877 },878 };879 const amount = TRANSFER_AMOUNT;880881 await helper.xTokens.transfer(randomAccountUnique, currencyId, amount, dest, 'Unlimited');882883 balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccountUnique.address);884 expect(balanceUniqueTokenMiddle < balanceUniqueTokenInit).to.be.true;885886 const transactionFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;887 console.log('[Unique -> Moonbeam] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(transactionFees));888 expect(transactionFees > 0, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;889890 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {891 await helper.wait.newBlocks(3);892893 balanceGlmrTokenMiddle = await helper.balance.getEthereum(randomAccountMoonbeam.address);894895 const glmrFees = balanceGlmrTokenInit - balanceGlmrTokenMiddle;896 console.log('[Unique -> Moonbeam] transaction fees on Moonbeam: %s GLMR', helper.util.bigIntToDecimals(glmrFees));897 expect(glmrFees == 0n).to.be.true;898899 balanceForeignUnqTokenMiddle = (await helper.assets.account(assetId, randomAccountMoonbeam.address))!;900901 const unqIncomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenInit;902 console.log('[Unique -> Moonbeam] income %s UNQ', helper.util.bigIntToDecimals(unqIncomeTransfer));903 expect(unqIncomeTransfer == TRANSFER_AMOUNT).to.be.true;904 });905 });906907 itSub('Should connect to Moonbeam and send UNQ back', async ({helper}) => {908 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {909 const asset = {910 V2: {911 id: {912 Concrete: {913 parents: 1,914 interior: {915 X1: {Parachain: UNIQUE_CHAIN},916 },917 },918 },919 fun: {920 Fungible: TRANSFER_AMOUNT,921 },922 },923 };924 const destination = {925 V2: {926 parents: 1,927 interior: {928 X2: [929 {Parachain: UNIQUE_CHAIN},930 {AccountId32: {network: 'Any', id: randomAccountUnique.addressRaw}},931 ],932 },933 },934 };935936 await helper.xTokens.transferMultiasset(randomAccountMoonbeam, asset, destination, 'Unlimited');937938 balanceGlmrTokenFinal = await helper.balance.getEthereum(randomAccountMoonbeam.address);939940 const glmrFees = balanceGlmrTokenMiddle - balanceGlmrTokenFinal;941 console.log('[Moonbeam -> Unique] transaction fees on Moonbeam: %s GLMR', helper.util.bigIntToDecimals(glmrFees));942 expect(glmrFees > 0, 'Negative fees GLMR, looks like nothing was transferred').to.be.true;943944 const unqRandomAccountAsset = await helper.assets.account(assetId, randomAccountMoonbeam.address);945946 expect(unqRandomAccountAsset).to.be.null;947948 balanceForeignUnqTokenFinal = 0n;949950 const unqOutcomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenFinal;951 console.log('[Unique -> Moonbeam] outcome %s UNQ', helper.util.bigIntToDecimals(unqOutcomeTransfer));952 expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;953 });954955 await helper.wait.newBlocks(3);956957 balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccountUnique.address);958 const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;959 expect(actuallyDelivered > 0).to.be.true;960961 console.log('[Moonbeam -> Unique] actually delivered %s UNQ', helper.util.bigIntToDecimals(actuallyDelivered));962963 const unqFees = TRANSFER_AMOUNT - actuallyDelivered;964 console.log('[Moonbeam -> Unique] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));965 expect(unqFees == 0n).to.be.true;966 });967});