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

difftreelog

fix(xcm test) hooks for `Astar`\`Shiden`

PraetorP2023-10-03parent: #f5ed3da.patch.diff
in: master

5 files changed

modifiedtests/src/util/playgrounds/unique.xcm.tsdiffbeforeafterboth
--- a/tests/src/util/playgrounds/unique.xcm.ts
+++ b/tests/src/util/playgrounds/unique.xcm.ts
@@ -244,6 +244,10 @@
     await this.helper.executeExtrinsic(signer, 'api.tx.assets.create', [assetId, admin, minimalBalance], true);
   }
 
+  async forceCreate(signer: TSigner, assetId: number | bigint, admin: string, minimalBalance: bigint, isSufficient = true) {
+    await this.helper.executeExtrinsic(signer, 'api.tx.assets.forceCreate', [assetId, admin, isSufficient, minimalBalance], true);
+  }
+
   async setMetadata(signer: TSigner, assetId: number | bigint, name: string, symbol: string, decimals: number) {
     await this.helper.executeExtrinsic(signer, 'api.tx.assets.setMetadata', [assetId, name, symbol, decimals], true);
   }
modifiedtests/src/xcm/lowLevelXcmQuartz.test.tsdiffbeforeafterboth
before · tests/src/xcm/lowLevelXcmQuartz.test.ts
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import {IKeyringPair} from '@polkadot/types/types';18import {itSub, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds,  usingMoonriverPlaygrounds, usingShidenPlaygrounds, usingRelayPlaygrounds} from '../util';19import {QUARTZ_CHAIN,  QTZ_DECIMALS,  SHIDEN_DECIMALS, karuraUrl, moonriverUrl,  shidenUrl,  SAFE_XCM_VERSION, XcmTestHelper, TRANSFER_AMOUNT, SENDER_BUDGET, relayUrl} from './xcm.types';20import {hexToString} from '@polkadot/util';2122const testHelper = new XcmTestHelper('quartz');2324describeXCM('[XCMLL] Integration test: Exchanging tokens with Karura', () => {25  let alice: IKeyringPair;26  let randomAccount: IKeyringPair;2728  before(async () => {29    await usingPlaygrounds(async (helper, privateKey) => {30      alice = await privateKey('//Alice');31      [randomAccount] = await helper.arrange.createAccounts([0n], alice);3233      // Set the default version to wrap the first message to other chains.34      await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);35    });3637    await usingKaruraPlaygrounds(karuraUrl, async (helper) => {38      const destination = {39        V2: {40          parents: 1,41          interior: {42            X1: {43              Parachain: QUARTZ_CHAIN,44            },45          },46        },47      };4849      const metadata = {50        name: 'Quartz',51        symbol: 'QTZ',52        decimals: 18,53        minimalBalance: 1000000000000000000n,54      };5556      const assets = (await (helper.callRpc('api.query.assetRegistry.assetMetadatas.entries'))).map(([_k, v]: [any, any]) =>57        hexToString(v.toJSON()['symbol'])) as string[];5859      if(!assets.includes('QTZ')) {60        await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);61      } else {62        console.log('QTZ token already registered on Karura assetRegistry pallet');63      }64      await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);65    });6667    await usingPlaygrounds(async (helper) => {68      await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);69    });70  });7172  itSub('Should connect and send QTZ to Karura', async () => {73    await testHelper.sendUnqTo('karura', randomAccount);74  });7576  itSub('Should connect to Karura and send QTZ back', async () => {77    await testHelper.sendUnqBack('karura', alice, randomAccount);78  });7980  itSub('Karura can send only up to its balance', async () => {81    await testHelper.sendOnlyOwnedBalance('karura', alice);82  });83});84// These tests are relevant only when85// the the corresponding foreign assets are not registered86describeXCM('[XCMLL] Integration test: Quartz rejects non-native tokens', () => {87  let alice: IKeyringPair;888990  before(async () => {91    await usingPlaygrounds(async (helper, privateKey) => {92      alice = await privateKey('//Alice');93949596      // Set the default version to wrap the first message to other chains.97      await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);98    });99  });100101  itSub('Quartz rejects KAR tokens from Karura', async () => {102    await testHelper.rejectNativeTokensFrom('karura', alice);103  });104105  itSub('Quartz rejects MOVR tokens from Moonriver', async () => {106    await testHelper.rejectNativeTokensFrom('moonriver', alice);107  });108109  itSub('Quartz rejects SDN tokens from Shiden', async () => {110    await testHelper.rejectNativeTokensFrom('shiden', alice);111  });112});113114describeXCM('[XCMLL] Integration test: Exchanging QTZ with Moonriver', () => {115  // Quartz constants116  let alice: IKeyringPair;117  let quartzAssetLocation;118119  let randomAccountQuartz: IKeyringPair;120  let randomAccountMoonriver: IKeyringPair;121122  // Moonriver constants123  let assetId: string;124125  const quartzAssetMetadata = {126    name: 'xcQuartz',127    symbol: 'xcQTZ',128    decimals: 18,129    isFrozen: false,130    minimalBalance: 1n,131  };132133134  before(async () => {135    await usingPlaygrounds(async (helper, privateKey) => {136      alice = await privateKey('//Alice');137      [randomAccountQuartz] = await helper.arrange.createAccounts([0n], alice);138139140      // Set the default version to wrap the first message to other chains.141      await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);142    });143144    await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {145      const alithAccount = helper.account.alithAccount();146      const baltatharAccount = helper.account.baltatharAccount();147      const dorothyAccount = helper.account.dorothyAccount();148149      randomAccountMoonriver = helper.account.create();150151      // >>> Sponsoring Dorothy >>>152      console.log('Sponsoring Dorothy.......');153      await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);154      console.log('Sponsoring Dorothy.......DONE');155      // <<< Sponsoring Dorothy <<<156157      quartzAssetLocation = {158        XCM: {159          parents: 1,160          interior: {X1: {Parachain: QUARTZ_CHAIN}},161        },162      };163      const existentialDeposit = 1n;164      const isSufficient = true;165      const unitsPerSecond = 1n;166      const numAssetsWeightHint = 0;167      if((await helper.assetManager.assetTypeId(quartzAssetLocation)).toJSON()) {168        console.log('Quartz asset already registered on Moonriver');169      } else {170        const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({171          location: quartzAssetLocation,172          metadata: quartzAssetMetadata,173          existentialDeposit,174          isSufficient,175          unitsPerSecond,176          numAssetsWeightHint,177        });178179        console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);180181        await helper.fastDemocracy.executeProposal('register QTZ foreign asset', encodedProposal);182      }183      // >>> Acquire Quartz AssetId Info on Moonriver >>>184      console.log('Acquire Quartz AssetId Info on Moonriver.......');185186      assetId = (await helper.assetManager.assetTypeId(quartzAssetLocation)).toString();187188      console.log('QTZ asset ID is %s', assetId);189      console.log('Acquire Quartz AssetId Info on Moonriver.......DONE');190      // >>> Acquire Quartz AssetId Info on Moonriver >>>191192      // >>> Sponsoring random Account >>>193      console.log('Sponsoring random Account.......');194      await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonriver.address, 11_000_000_000_000_000_000n);195      console.log('Sponsoring random Account.......DONE');196      // <<< Sponsoring random Account <<<197    });198199    await usingPlaygrounds(async (helper) => {200      await helper.balance.transferToSubstrate(alice, randomAccountQuartz.address, 10n * TRANSFER_AMOUNT);201    });202  });203204  itSub('Should connect and send QTZ to Moonriver', async () => {205    await testHelper.sendUnqTo('moonriver', randomAccountQuartz, randomAccountMoonriver);206  });207208  itSub('Should connect to Moonriver and send QTZ back', async () => {209    await testHelper.sendUnqBack('moonriver', alice, randomAccountQuartz);210  });211212  itSub('Moonriver can send only up to its balance', async () => {213    await testHelper.sendOnlyOwnedBalance('moonriver', alice);214  });215216  itSub('Should not accept reserve transfer of QTZ from Moonriver', async () => {217    await testHelper.rejectReserveTransferUNQfrom('moonriver', alice);218  });219});220221describeXCM('[XCMLL] Integration test: Exchanging tokens with Shiden', () => {222  let alice: IKeyringPair;223  let randomAccount: IKeyringPair;224225  const QTZ_ASSET_ID_ON_SHIDEN = 18_446_744_073_709_551_633n; // The value is taken from the live Shiden226  const QTZ_MINIMAL_BALANCE_ON_SHIDEN = 1n; // The value is taken from the live Shiden227228  // Quartz -> Shiden229  const shidenInitialBalance = 1n * (10n ** SHIDEN_DECIMALS); // 1 SHD, existential deposit required to actually create the account on Shiden230  const unitsPerSecond = 500_451_000_000_000_000_000n; // The value is taken from the live Shiden231232  before(async () => {233    await usingPlaygrounds(async (helper, privateKey) => {234      alice = await privateKey('//Alice');235      randomAccount = helper.arrange.createEmptyAccount();236      await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);237      console.log('sender: ', randomAccount.address);238239      // Set the default version to wrap the first message to other chains.240      await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);241    });242243    await usingShidenPlaygrounds(shidenUrl, async (helper) => {244      if(!(await helper.callRpc('api.query.assets.asset', [QTZ_ASSET_ID_ON_SHIDEN])).toJSON()) {245        console.log('1. Create foreign asset and metadata');246        await helper.assets.create(247          alice,248          QTZ_ASSET_ID_ON_SHIDEN,249          alice.address,250          QTZ_MINIMAL_BALANCE_ON_SHIDEN,251        );252253        await helper.assets.setMetadata(254          alice,255          QTZ_ASSET_ID_ON_SHIDEN,256          'Quartz',257          'QTZ',258          Number(QTZ_DECIMALS),259        );260261        console.log('2. Register asset location on Shiden');262        const assetLocation = {263          V2: {264            parents: 1,265            interior: {266              X1: {267                Parachain: QUARTZ_CHAIN,268              },269            },270          },271        };272273        await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, QTZ_ASSET_ID_ON_SHIDEN]);274275        console.log('3. Set QTZ payment for XCM execution on Shiden');276        await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);277      } else {278        console.log('QTZ is already registered on Shiden');279      }280      console.log('4. Transfer 1 SDN to recipient to create the account (needed due to existential balance)');281      await helper.balance.transferToSubstrate(alice, randomAccount.address, shidenInitialBalance);282    });283  });284285  itSub('Should connect and send QTZ to Shiden', async () => {286    await testHelper.sendUnqTo('shiden', randomAccount);287  });288289  itSub('Should connect to Shiden and send QTZ back', async () => {290    await testHelper.sendUnqBack('shiden', alice, randomAccount);291  });292293  itSub('Shiden can send only up to its balance', async () => {294    await testHelper.sendOnlyOwnedBalance('shiden', alice);295  });296297  itSub('Should not accept reserve transfer of QTZ from Shiden', async () => {298    await testHelper.rejectReserveTransferUNQfrom('shiden', alice);299  });300});301302describeXCM('[XCMLL] Integration test: The relay can do some root ops', () => {303  let sudoer: IKeyringPair;304305  before(async function () {306    await usingRelayPlaygrounds(relayUrl, async (_, privateKey) => {307      sudoer = await privateKey('//Alice');308    });309  });310311  // At the moment there is no reliable way312  // to establish the correspondence between the `ExecutedDownward` event313  // and the relay's sent message due to `SetTopic` instruction314  // containing an unpredictable topic silently added by the relay's messages on the router level.315  // This changes the message hash on arrival to our chain.316  //317  // See:318  // * The relay's router: https://github.com/paritytech/polkadot-sdk/blob/f60318f68687e601c47de5ad5ca88e2c3f8139a7/polkadot/runtime/westend/src/xcm_config.rs#L83319  // * The `WithUniqueTopic` helper: https://github.com/paritytech/polkadot-sdk/blob/945ebbbcf66646be13d5b1d1bc26c8b0d3296d9e/polkadot/xcm/xcm-builder/src/routing.rs#L36320  //321  // Because of this, we insert time gaps between tests so322  // different `ExecutedDownward` events won't interfere with each other.323  afterEach(async () => {324    await usingPlaygrounds(async (helper) => {325      await helper.wait.newBlocks(3);326    });327  });328329  itSub('The relay can set storage', async () => {330    await testHelper.relayIsPermittedToSetStorage(sudoer, 'plain');331  });332333  itSub('The relay can batch set storage', async () => {334    await testHelper.relayIsPermittedToSetStorage(sudoer, 'batch');335  });336337  itSub('The relay can batchAll set storage', async () => {338    await testHelper.relayIsPermittedToSetStorage(sudoer, 'batchAll');339  });340341  itSub('The relay can forceBatch set storage', async () => {342    await testHelper.relayIsPermittedToSetStorage(sudoer, 'forceBatch');343  });344345  itSub('[negative] The relay cannot set balance', async () => {346    await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'plain');347  });348349  itSub('[negative] The relay cannot set balance via batch', async () => {350    await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'batch');351  });352353  itSub('[negative] The relay cannot set balance via batchAll', async () => {354    await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'batchAll');355  });356357  itSub('[negative] The relay cannot set balance via forceBatch', async () => {358    await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'forceBatch');359  });360361  itSub('[negative] The relay cannot set balance via dispatchAs', async () => {362    await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'dispatchAs');363  });364});
after · tests/src/xcm/lowLevelXcmQuartz.test.ts
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import {IKeyringPair} from '@polkadot/types/types';18import {itSub, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds,  usingMoonriverPlaygrounds, usingShidenPlaygrounds, usingRelayPlaygrounds} from '../util';19import {QUARTZ_CHAIN,  QTZ_DECIMALS,  SHIDEN_DECIMALS, karuraUrl, moonriverUrl,  shidenUrl,  SAFE_XCM_VERSION, XcmTestHelper, TRANSFER_AMOUNT, SENDER_BUDGET, relayUrl} from './xcm.types';20import {hexToString} from '@polkadot/util';2122const testHelper = new XcmTestHelper('quartz');2324describeXCM('[XCMLL] Integration test: Exchanging tokens with Karura', () => {25  let alice: IKeyringPair;26  let randomAccount: IKeyringPair;2728  before(async () => {29    await usingPlaygrounds(async (helper, privateKey) => {30      alice = await privateKey('//Alice');31      [randomAccount] = await helper.arrange.createAccounts([0n], alice);3233      // Set the default version to wrap the first message to other chains.34      await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);35    });3637    await usingKaruraPlaygrounds(karuraUrl, async (helper) => {38      const destination = {39        V2: {40          parents: 1,41          interior: {42            X1: {43              Parachain: QUARTZ_CHAIN,44            },45          },46        },47      };4849      const metadata = {50        name: 'Quartz',51        symbol: 'QTZ',52        decimals: 18,53        minimalBalance: 1000000000000000000n,54      };5556      const assets = (await (helper.callRpc('api.query.assetRegistry.assetMetadatas.entries'))).map(([_k, v]: [any, any]) =>57        hexToString(v.toJSON()['symbol'])) as string[];5859      if(!assets.includes('QTZ')) {60        await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);61      } else {62        console.log('QTZ token already registered on Karura assetRegistry pallet');63      }64      await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);65    });6667    await usingPlaygrounds(async (helper) => {68      await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);69    });70  });7172  itSub('Should connect and send QTZ to Karura', async () => {73    await testHelper.sendUnqTo('karura', randomAccount);74  });7576  itSub('Should connect to Karura and send QTZ back', async () => {77    await testHelper.sendUnqBack('karura', alice, randomAccount);78  });7980  itSub('Karura can send only up to its balance', async () => {81    await testHelper.sendOnlyOwnedBalance('karura', alice);82  });83});84// These tests are relevant only when85// the the corresponding foreign assets are not registered86describeXCM('[XCMLL] Integration test: Quartz rejects non-native tokens', () => {87  let alice: IKeyringPair;888990  before(async () => {91    await usingPlaygrounds(async (helper, privateKey) => {92      alice = await privateKey('//Alice');93949596      // Set the default version to wrap the first message to other chains.97      await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);98    });99  });100101  itSub('Quartz rejects KAR tokens from Karura', async () => {102    await testHelper.rejectNativeTokensFrom('karura', alice);103  });104105  itSub('Quartz rejects MOVR tokens from Moonriver', async () => {106    await testHelper.rejectNativeTokensFrom('moonriver', alice);107  });108109  itSub('Quartz rejects SDN tokens from Shiden', async () => {110    await testHelper.rejectNativeTokensFrom('shiden', alice);111  });112});113114describeXCM('[XCMLL] Integration test: Exchanging QTZ with Moonriver', () => {115  // Quartz constants116  let alice: IKeyringPair;117  let quartzAssetLocation;118119  let randomAccountQuartz: IKeyringPair;120  let randomAccountMoonriver: IKeyringPair;121122  // Moonriver constants123  let assetId: string;124125  const quartzAssetMetadata = {126    name: 'xcQuartz',127    symbol: 'xcQTZ',128    decimals: 18,129    isFrozen: false,130    minimalBalance: 1n,131  };132133134  before(async () => {135    await usingPlaygrounds(async (helper, privateKey) => {136      alice = await privateKey('//Alice');137      [randomAccountQuartz] = await helper.arrange.createAccounts([0n], alice);138139140      // Set the default version to wrap the first message to other chains.141      await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);142    });143144    await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {145      const alithAccount = helper.account.alithAccount();146      const baltatharAccount = helper.account.baltatharAccount();147      const dorothyAccount = helper.account.dorothyAccount();148149      randomAccountMoonriver = helper.account.create();150151      // >>> Sponsoring Dorothy >>>152      console.log('Sponsoring Dorothy.......');153      await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);154      console.log('Sponsoring Dorothy.......DONE');155      // <<< Sponsoring Dorothy <<<156157      quartzAssetLocation = {158        XCM: {159          parents: 1,160          interior: {X1: {Parachain: QUARTZ_CHAIN}},161        },162      };163      const existentialDeposit = 1n;164      const isSufficient = true;165      const unitsPerSecond = 1n;166      const numAssetsWeightHint = 0;167      if((await helper.assetManager.assetTypeId(quartzAssetLocation)).toJSON()) {168        console.log('Quartz asset already registered on Moonriver');169      } else {170        const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({171          location: quartzAssetLocation,172          metadata: quartzAssetMetadata,173          existentialDeposit,174          isSufficient,175          unitsPerSecond,176          numAssetsWeightHint,177        });178179        console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);180181        await helper.fastDemocracy.executeProposal('register QTZ foreign asset', encodedProposal);182      }183      // >>> Acquire Quartz AssetId Info on Moonriver >>>184      console.log('Acquire Quartz AssetId Info on Moonriver.......');185186      assetId = (await helper.assetManager.assetTypeId(quartzAssetLocation)).toString();187188      console.log('QTZ asset ID is %s', assetId);189      console.log('Acquire Quartz AssetId Info on Moonriver.......DONE');190      // >>> Acquire Quartz AssetId Info on Moonriver >>>191192      // >>> Sponsoring random Account >>>193      console.log('Sponsoring random Account.......');194      await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonriver.address, 11_000_000_000_000_000_000n);195      console.log('Sponsoring random Account.......DONE');196      // <<< Sponsoring random Account <<<197    });198199    await usingPlaygrounds(async (helper) => {200      await helper.balance.transferToSubstrate(alice, randomAccountQuartz.address, 10n * TRANSFER_AMOUNT);201    });202  });203204  itSub('Should connect and send QTZ to Moonriver', async () => {205    await testHelper.sendUnqTo('moonriver', randomAccountQuartz, randomAccountMoonriver);206  });207208  itSub('Should connect to Moonriver and send QTZ back', async () => {209    await testHelper.sendUnqBack('moonriver', alice, randomAccountQuartz);210  });211212  itSub('Moonriver can send only up to its balance', async () => {213    await testHelper.sendOnlyOwnedBalance('moonriver', alice);214  });215216  itSub('Should not accept reserve transfer of QTZ from Moonriver', async () => {217    await testHelper.rejectReserveTransferUNQfrom('moonriver', alice);218  });219});220221describeXCM('[XCMLL] Integration test: Exchanging tokens with Shiden', () => {222  let alice: IKeyringPair;223  let randomAccount: IKeyringPair;224225  const QTZ_ASSET_ID_ON_SHIDEN = 18_446_744_073_709_551_633n; // The value is taken from the live Shiden226  const QTZ_MINIMAL_BALANCE_ON_SHIDEN = 1n; // The value is taken from the live Shiden227228  // Quartz -> Shiden229  const shidenInitialBalance = 1n * (10n ** SHIDEN_DECIMALS); // 1 SHD, existential deposit required to actually create the account on Shiden230  const unitsPerSecond = 500_451_000_000_000_000_000n; // The value is taken from the live Shiden231232  before(async () => {233    await usingPlaygrounds(async (helper, privateKey) => {234      alice = await privateKey('//Alice');235      randomAccount = helper.arrange.createEmptyAccount();236      await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);237      console.log('sender: ', randomAccount.address);238239      // Set the default version to wrap the first message to other chains.240      await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);241    });242243    await usingShidenPlaygrounds(shidenUrl, async (helper) => {244      if(!(await helper.callRpc('api.query.assets.asset', [QTZ_ASSET_ID_ON_SHIDEN])).toJSON()) {245        console.log('1. Create foreign asset and metadata');246        await helper.getSudo().assets.forceCreate(247          alice,248          QTZ_ASSET_ID_ON_SHIDEN,249          alice.address,250          QTZ_MINIMAL_BALANCE_ON_SHIDEN,251        );252253        await helper.assets.setMetadata(254          alice,255          QTZ_ASSET_ID_ON_SHIDEN,256          'Quartz',257          'QTZ',258          Number(QTZ_DECIMALS),259        );260261        console.log('2. Register asset location on Shiden');262        const assetLocation = {263          V2: {264            parents: 1,265            interior: {266              X1: {267                Parachain: QUARTZ_CHAIN,268              },269            },270          },271        };272273        await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, QTZ_ASSET_ID_ON_SHIDEN]);274275        console.log('3. Set QTZ payment for XCM execution on Shiden');276        await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);277      } else {278        console.log('QTZ is already registered on Shiden');279      }280      console.log('4. Transfer 1 SDN to recipient to create the account (needed due to existential balance)');281      await helper.balance.transferToSubstrate(alice, randomAccount.address, shidenInitialBalance);282    });283  });284285  itSub('Should connect and send QTZ to Shiden', async () => {286    await testHelper.sendUnqTo('shiden', randomAccount);287  });288289  itSub('Should connect to Shiden and send QTZ back', async () => {290    await testHelper.sendUnqBack('shiden', alice, randomAccount);291  });292293  itSub('Shiden can send only up to its balance', async () => {294    await testHelper.sendOnlyOwnedBalance('shiden', alice);295  });296297  itSub('Should not accept reserve transfer of QTZ from Shiden', async () => {298    await testHelper.rejectReserveTransferUNQfrom('shiden', alice);299  });300});301302describeXCM('[XCMLL] Integration test: The relay can do some root ops', () => {303  let sudoer: IKeyringPair;304305  before(async function () {306    await usingRelayPlaygrounds(relayUrl, async (_, privateKey) => {307      sudoer = await privateKey('//Alice');308    });309  });310311  // At the moment there is no reliable way312  // to establish the correspondence between the `ExecutedDownward` event313  // and the relay's sent message due to `SetTopic` instruction314  // containing an unpredictable topic silently added by the relay's messages on the router level.315  // This changes the message hash on arrival to our chain.316  //317  // See:318  // * The relay's router: https://github.com/paritytech/polkadot-sdk/blob/f60318f68687e601c47de5ad5ca88e2c3f8139a7/polkadot/runtime/westend/src/xcm_config.rs#L83319  // * The `WithUniqueTopic` helper: https://github.com/paritytech/polkadot-sdk/blob/945ebbbcf66646be13d5b1d1bc26c8b0d3296d9e/polkadot/xcm/xcm-builder/src/routing.rs#L36320  //321  // Because of this, we insert time gaps between tests so322  // different `ExecutedDownward` events won't interfere with each other.323  afterEach(async () => {324    await usingPlaygrounds(async (helper) => {325      await helper.wait.newBlocks(3);326    });327  });328329  itSub('The relay can set storage', async () => {330    await testHelper.relayIsPermittedToSetStorage(sudoer, 'plain');331  });332333  itSub('The relay can batch set storage', async () => {334    await testHelper.relayIsPermittedToSetStorage(sudoer, 'batch');335  });336337  itSub('The relay can batchAll set storage', async () => {338    await testHelper.relayIsPermittedToSetStorage(sudoer, 'batchAll');339  });340341  itSub('The relay can forceBatch set storage', async () => {342    await testHelper.relayIsPermittedToSetStorage(sudoer, 'forceBatch');343  });344345  itSub('[negative] The relay cannot set balance', async () => {346    await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'plain');347  });348349  itSub('[negative] The relay cannot set balance via batch', async () => {350    await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'batch');351  });352353  itSub('[negative] The relay cannot set balance via batchAll', async () => {354    await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'batchAll');355  });356357  itSub('[negative] The relay cannot set balance via forceBatch', async () => {358    await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'forceBatch');359  });360361  itSub('[negative] The relay cannot set balance via dispatchAs', async () => {362    await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'dispatchAs');363  });364});
modifiedtests/src/xcm/lowLevelXcmUnique.test.tsdiffbeforeafterboth
--- a/tests/src/xcm/lowLevelXcmUnique.test.ts
+++ b/tests/src/xcm/lowLevelXcmUnique.test.ts
@@ -309,7 +309,7 @@
     await usingAstarPlaygrounds(astarUrl, async (helper) => {
       if(!(await helper.callRpc('api.query.assets.asset', [UNQ_ASSET_ID_ON_ASTAR])).toJSON()) {
         console.log('1. Create foreign asset and metadata');
-        await helper.assets.create(
+        await helper.getSudo().assets.forceCreate(
           alice,
           UNQ_ASSET_ID_ON_ASTAR,
           alice.address,
modifiedtests/src/xcm/xcmQuartz.test.tsdiffbeforeafterboth
--- a/tests/src/xcm/xcmQuartz.test.ts
+++ b/tests/src/xcm/xcmQuartz.test.ts
@@ -1290,11 +1290,11 @@
   const shidenInitialBalance = 1n * (10n ** SHIDEN_DECIMALS); // 1 SHD, existential deposit required to actually create the account on Shiden
   const unitsPerSecond = 500_451_000_000_000_000_000n; // The value is taken from the live Shiden
   const qtzToShidenTransferred = 10n * (10n ** QTZ_DECIMALS); // 10 QTZ
-  const qtzToShidenArrived = 9_999_999_999_088_000_000n; // 9.999 ... QTZ, Shiden takes a commision in foreign tokens
+  const qtzToShidenArrived = 7_998_196_000_000_000_000n; // 7.99 ... QTZ, Shiden takes a commision in foreign tokens
 
   // Shiden -> Quartz
   const qtzFromShidenTransfered = 5n * (10n ** QTZ_DECIMALS); // 5 QTZ
-  const qtzOnShidenLeft = qtzToShidenArrived - qtzFromShidenTransfered; // 4.999_999_999_088_000_000n QTZ
+  const qtzOnShidenLeft = qtzToShidenArrived - qtzFromShidenTransfered; // 2.99 ... QTZ
 
   let balanceAfterQuartzToShidenXCM: bigint;
 
@@ -1311,7 +1311,7 @@
     await usingShidenPlaygrounds(shidenUrl, async (helper) => {
       if(!(await helper.callRpc('api.query.assets.asset', [QTZ_ASSET_ID_ON_SHIDEN])).toJSON()) {
         console.log('1. Create foreign asset and metadata');
-        await helper.assets.create(
+        await helper.getSudo().assets.forceCreate(
           alice,
           QTZ_ASSET_ID_ON_SHIDEN,
           alice.address,
modifiedtests/src/xcm/xcmUnique.test.tsdiffbeforeafterboth
--- a/tests/src/xcm/xcmUnique.test.ts
+++ b/tests/src/xcm/xcmUnique.test.ts
@@ -1518,11 +1518,11 @@
   const astarInitialBalance = 1n * (10n ** ASTAR_DECIMALS); // 1 ASTR, existential deposit required to actually create the account on Astar.
   const unitsPerSecond = 9_451_000_000_000_000_000n; // The value is taken from the live Astar
   const unqToAstarTransferred = 10n * (10n ** UNQ_DECIMALS); // 10 UNQ
-  const unqToAstarArrived = 9_999_999_999_088_000_000n; // 9.999 ... UNQ, Astar takes a commision in foreign tokens
+  const unqToAstarArrived = 9_962_196_000_000_000_000n; // 9.962 ... UNQ, Astar takes a commision in foreign tokens
 
   // Astar -> Unique
   const unqFromAstarTransfered = 5n * (10n ** UNQ_DECIMALS); // 5 UNQ
-  const unqOnAstarLeft = unqToAstarArrived - unqFromAstarTransfered; // 4.999_999_999_088_000_000n UNQ
+  const unqOnAstarLeft = unqToAstarArrived - unqFromAstarTransfered; // 4.962_219_600_000_000_000n UNQ
 
   let balanceAfterUniqueToAstarXCM: bigint;
 
@@ -1539,7 +1539,7 @@
     await usingAstarPlaygrounds(astarUrl, async (helper) => {
       if(!(await helper.callRpc('api.query.assets.asset', [UNQ_ASSET_ID_ON_ASTAR])).toJSON()) {
         console.log('1. Create foreign asset and metadata');
-        await helper.assets.create(
+        await helper.getSudo().assets.forceCreate(
           alice,
           UNQ_ASSET_ID_ON_ASTAR,
           alice.address,