1234567891011121314151617import {IKeyringPair} from '@polkadot/types/types';18import config from '../config';19import {itSub, expect, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingMoonbeamPlaygrounds, usingAstarPlaygrounds, usingPolkadexPlaygrounds, usingRelayPlaygrounds, requirePalletsOrSkip, Pallets} from '../util';20import {Event} from '../util/playgrounds/unique.dev';21import {nToBigInt} from '@polkadot/util';22import {hexToString} from '@polkadot/util';23import {ASTAR_DECIMALS, NETWORKS, SAFE_XCM_VERSION, UNIQUE_CHAIN, UNQ_DECIMALS, XcmTestHelper, acalaUrl, astarUrl, expectFailedToTransact, expectUntrustedReserveLocationFail, getDevPlayground, mapToChainId, mapToChainUrl, maxWaitBlocks, moonbeamUrl, polkadexUrl, relayUrl, uniqueAssetId, uniqueVersionedMultilocation} from './xcm.types';242526const TRANSFER_AMOUNT = 2000000_000_000_000_000_000_000n;27const SENDER_BUDGET = 2n * TRANSFER_AMOUNT;28const SENDBACK_AMOUNT = TRANSFER_AMOUNT / 2n;29const STAYED_ON_TARGET_CHAIN = TRANSFER_AMOUNT - SENDBACK_AMOUNT;30const TARGET_CHAIN_TOKEN_TRANSFER_AMOUNT = 100_000_000_000n;3132let balanceUniqueTokenInit: bigint;33let balanceUniqueTokenMiddle: bigint;34let balanceUniqueTokenFinal: bigint;35let unqFees: bigint;3637const testHelper = new XcmTestHelper('unique');3839async function genericSendUnqTo(40 networkName: keyof typeof NETWORKS,41 randomAccount: IKeyringPair,42 randomAccountOnTargetChain = randomAccount,43) {44 const networkUrl = mapToChainUrl(networkName);45 const targetPlayground = getDevPlayground(networkName);46 await usingPlaygrounds(async (helper) => {47 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);48 const destination = {49 V2: {50 parents: 1,51 interior: {52 X1: {53 Parachain: mapToChainId(networkName),54 },55 },56 },57 };5859 const beneficiary = {60 V2: {61 parents: 0,62 interior: {63 X1: (64 networkName == 'moonbeam' ?65 {66 AccountKey20: {67 network: 'Any',68 key: randomAccountOnTargetChain.address,69 },70 }71 :72 {73 AccountId32: {74 network: 'Any',75 id: randomAccountOnTargetChain.addressRaw,76 },77 }78 ),79 },80 },81 };8283 const assets = {84 V2: [85 {86 id: {87 Concrete: {88 parents: 0,89 interior: 'Here',90 },91 },92 fun: {93 Fungible: TRANSFER_AMOUNT,94 },95 },96 ],97 };98 const feeAssetItem = 0;99100 await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');101 const messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);102 balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);103104 unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;105 console.log('[Unique -> %s] transaction fees on Unique: %s UNQ', networkName, helper.util.bigIntToDecimals(unqFees));106 expect(unqFees > 0n, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;107108 await targetPlayground(networkUrl, async (helper) => {109 110111112113114115116117118119 if(networkName == 'polkadex') {120 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == messageSent.messageHash);121 } else {122 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Success, event => event.messageHash == messageSent.messageHash);123 }124 });125126 });127}128129async function genericSendUnqBack(130 networkName: keyof typeof NETWORKS,131 sudoer: IKeyringPair,132 randomAccountOnUnq: IKeyringPair,133) {134 const networkUrl = mapToChainUrl(networkName);135136 const targetPlayground = getDevPlayground(networkName);137 await usingPlaygrounds(async (helper) => {138139 const xcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(140 randomAccountOnUnq.addressRaw,141 uniqueAssetId,142 SENDBACK_AMOUNT,143 );144145 let xcmProgramSent: any;146147148 await targetPlayground(networkUrl, async (helper) => {149 if('getSudo' in helper) {150 await helper.getSudo().xcm.send(sudoer, uniqueVersionedMultilocation, xcmProgram);151 xcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);152 } else if('fastDemocracy' in helper) {153 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, xcmProgram]);154 155 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);156 await helper.fastDemocracy.executeProposal(`sending ${networkName} -> Unique via XCM program`, batchCall);157 xcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);158 }159 });160161 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Success, event => event.messageHash == xcmProgramSent.messageHash);162163 balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccountOnUnq.address);164165 expect(balanceUniqueTokenFinal).to.be.equal(balanceUniqueTokenInit - unqFees - STAYED_ON_TARGET_CHAIN);166167 });168}169170async function genericSendOnlyOwnedBalance(171 networkName: keyof typeof NETWORKS,172 sudoer: IKeyringPair,173) {174 const networkUrl = mapToChainUrl(networkName);175 const targetPlayground = getDevPlayground(networkName);176177 const targetChainBalance = 10000n * (10n ** UNQ_DECIMALS);178179 await usingPlaygrounds(async (helper) => {180 const targetChainSovereignAccount = helper.address.paraSiblingSovereignAccount(mapToChainId(networkName));181 await helper.getSudo().balance.setBalanceSubstrate(sudoer, targetChainSovereignAccount, targetChainBalance);182 const moreThanTargetChainHas = 2n * targetChainBalance;183184 const targetAccount = helper.arrange.createEmptyAccount();185186 const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(187 targetAccount.addressRaw,188 {189 Concrete: {190 parents: 0,191 interior: 'Here',192 },193 },194 moreThanTargetChainHas,195 );196197 let maliciousXcmProgramSent: any;198199200 await targetPlayground(networkUrl, async (helper) => {201 if('getSudo' in helper) {202 await helper.getSudo().xcm.send(sudoer, uniqueVersionedMultilocation, maliciousXcmProgram);203 maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);204 } else if('fastDemocracy' in helper) {205 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgram]);206 207 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);208 await helper.fastDemocracy.executeProposal(`sending ${networkName} -> Unique via XCM program`, batchCall);209 maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);210 }211 });212213 await expectFailedToTransact(helper, maliciousXcmProgramSent);214215 const targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);216 expect(targetAccountBalance).to.be.equal(0n);217 });218}219220async function genericReserveTransferUNQfrom(netwokrName: keyof typeof NETWORKS, sudoer: IKeyringPair) {221 const networkUrl = mapToChainUrl(netwokrName);222 const targetPlayground = getDevPlayground(netwokrName);223224 await usingPlaygrounds(async (helper) => {225 const testAmount = 10_000n * (10n ** UNQ_DECIMALS);226 const targetAccount = helper.arrange.createEmptyAccount();227228 const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(229 targetAccount.addressRaw,230 uniqueAssetId,231 testAmount,232 );233234 const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(235 targetAccount.addressRaw,236 {237 Concrete: {238 parents: 0,239 interior: 'Here',240 },241 },242 testAmount,243 );244245 let maliciousXcmProgramFullIdSent: any;246 let maliciousXcmProgramHereIdSent: any;247 const maxWaitBlocks = 3;248249 250 await targetPlayground(networkUrl, async (helper) => {251 if('getSudo' in helper) {252 await helper.getSudo().xcm.send(sudoer, uniqueVersionedMultilocation, maliciousXcmProgramFullId);253 maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);254 }255 256 else if('fastDemocracy' in helper) {257 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramFullId]);258 259 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);260 await helper.fastDemocracy.executeProposal(`${netwokrName} try to act like a reserve location for UNQ using path asset identification`,batchCall);261262 maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);263 }264 });265266267 await expectUntrustedReserveLocationFail(helper, maliciousXcmProgramFullIdSent);268269 let accountBalance = await helper.balance.getSubstrate(targetAccount.address);270 expect(accountBalance).to.be.equal(0n);271272 273 await targetPlayground(networkUrl, async (helper) => {274 if('getSudo' in helper) {275 await helper.getSudo().xcm.send(sudoer, uniqueVersionedMultilocation, maliciousXcmProgramHereId);276 maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);277 }278 else if('fastDemocracy' in helper) {279 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramHereId]);280 281 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);282 await helper.fastDemocracy.executeProposal(`${netwokrName} try to act like a reserve location for UNQ using "here" asset identification`, batchCall);283284 maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);285 }286 });287288 await expectUntrustedReserveLocationFail(helper, maliciousXcmProgramHereIdSent);289290 accountBalance = await helper.balance.getSubstrate(targetAccount.address);291 expect(accountBalance).to.be.equal(0n);292 });293}294295async function genericRejectNativeTokensFrom(networkName: keyof typeof NETWORKS, sudoerOnTargetChain: IKeyringPair) {296 const networkUrl = mapToChainUrl(networkName);297 const targetPlayground = getDevPlayground(networkName);298 let messageSent: any;299300 await usingPlaygrounds(async (helper) => {301 const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(302 helper.arrange.createEmptyAccount().addressRaw,303 {304 Concrete: {305 parents: 1,306 interior: {307 X1: {308 Parachain: mapToChainId(networkName),309 },310 },311 },312 },313 TARGET_CHAIN_TOKEN_TRANSFER_AMOUNT,314 );315 await targetPlayground(networkUrl, async (helper) => {316 if('getSudo' in helper) {317 await helper.getSudo().xcm.send(sudoerOnTargetChain, uniqueVersionedMultilocation, maliciousXcmProgramFullId);318 messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);319 } else if('fastDemocracy' in helper) {320 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramFullId]);321 322 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);323 await helper.fastDemocracy.executeProposal(`${networkName} sending native tokens to the Unique via fast democracy`, batchCall);324325 messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);326 }327 });328 await expectFailedToTransact(helper, messageSent);329 });330}331332333describeXCM('[XCMLL] Integration test: Exchanging tokens with Acala', () => {334 let alice: IKeyringPair;335 let randomAccount: IKeyringPair;336337 before(async () => {338 await usingPlaygrounds(async (helper, privateKey) => {339 alice = await privateKey('//Alice');340 console.log(config.acalaUrl);341 randomAccount = helper.arrange.createEmptyAccount();342343 344 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);345 });346347 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {348 const destination = {349 V2: {350 parents: 1,351 interior: {352 X1: {353 Parachain: UNIQUE_CHAIN,354 },355 },356 },357 };358359 const metadata = {360 name: 'Unique Network',361 symbol: 'UNQ',362 decimals: 18,363 minimalBalance: 1250_000_000_000_000_000n,364 };365 const assets = (await (helper.callRpc('api.query.assetRegistry.assetMetadatas.entries'))).map(([_k, v] : [any, any]) =>366 hexToString(v.toJSON()['symbol'])) as string[];367368 if(!assets.includes('UNQ')) {369 await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);370 } else {371 console.log('UNQ token already registered on Acala assetRegistry pallet');372 }373 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);374 });375376 await usingPlaygrounds(async (helper) => {377 await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);378 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);379 });380 });381382 itSub('Should connect and send UNQ to Acala', async () => {383 await genericSendUnqTo('acala', randomAccount);384 });385386 itSub('Should connect to Acala and send UNQ back', async () => {387 await genericSendUnqBack('acala', alice, randomAccount);388 });389390 itSub('Acala can send only up to its balance', async () => {391 await genericSendOnlyOwnedBalance('acala', alice);392 });393394 itSub('Should not accept reserve transfer of UNQ from Acala', async () => {395 await genericReserveTransferUNQfrom('acala', alice);396 });397});398399describeXCM('[XCMLL] Integration test: Exchanging tokens with Polkadex', () => {400 let alice: IKeyringPair;401 let randomAccount: IKeyringPair;402403 before(async () => {404 await usingPlaygrounds(async (helper, privateKey) => {405 alice = await privateKey('//Alice');406 randomAccount = helper.arrange.createEmptyAccount();407408 409 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);410 });411412 await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {413 const isWhitelisted = ((await helper.callRpc('api.query.xcmHelper.whitelistedTokens', []))414 .toJSON() as [])415 .map(nToBigInt).length != 0;416 417418419420421422 if(isWhitelisted) {423 console.log('UNQ token is already whitelisted on Polkadex');424 } else {425 await helper.getSudo().xcmHelper.whitelistToken(alice, uniqueAssetId);426 }427428 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);429 });430431 await usingPlaygrounds(async (helper) => {432 await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);433 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);434 });435 });436437 itSub('Should connect and send UNQ to Polkadex', async () => {438 await testHelper.sendUnqTo('polkadex', randomAccount);439 });440441442 itSub('Should connect to Polkadex and send UNQ back', async () => {443 await testHelper.sendUnqBack('polkadex', alice, randomAccount);444 });445446 itSub('Polkadex can send only up to its balance', async () => {447 await testHelper.sendOnlyOwnedBalance('polkadex', alice);448 });449450 itSub('Should not accept reserve transfer of UNQ from Polkadex', async () => {451 await testHelper.reserveTransferUNQfrom('polkadex', alice);452 });453});454455456457describeXCM('[XCMLL] Integration test: Unique rejects non-native tokens', () => {458 let alice: IKeyringPair;459460 before(async () => {461 await usingPlaygrounds(async (helper, privateKey) => {462 alice = await privateKey('//Alice');463464 465 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);466 });467 });468469 itSub('Unique rejects ACA tokens from Acala', async () => {470 await genericRejectNativeTokensFrom('acala', alice);471 });472473 itSub('Unique rejects GLMR tokens from Moonbeam', async () => {474 await genericRejectNativeTokensFrom('moonbeam', alice);475 });476477 itSub('Unique rejects ASTR tokens from Astar', async () => {478 await genericRejectNativeTokensFrom('astar', alice);479 });480481 itSub('Unique rejects PDX tokens from Polkadex', async () => {482 await genericRejectNativeTokensFrom('polkadex', alice);483 });484});485486describeXCM('[XCMLL] Integration test: Exchanging UNQ with Moonbeam', () => {487 488 let alice: IKeyringPair;489 let uniqueAssetLocation;490491 let randomAccountUnique: IKeyringPair;492 let randomAccountMoonbeam: IKeyringPair;493494 495 let assetId: string;496497 const uniqueAssetMetadata = {498 name: 'xcUnique',499 symbol: 'xcUNQ',500 decimals: 18,501 isFrozen: false,502 minimalBalance: 1n,503 };504505506 before(async () => {507 await usingPlaygrounds(async (helper, privateKey) => {508 alice = await privateKey('//Alice');509 [randomAccountUnique] = await helper.arrange.createAccounts([0n], alice);510511512 513 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);514 });515516 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {517 const alithAccount = helper.account.alithAccount();518 const baltatharAccount = helper.account.baltatharAccount();519 const dorothyAccount = helper.account.dorothyAccount();520521 randomAccountMoonbeam = helper.account.create();522523 524 console.log('Sponsoring Dorothy.......');525 await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);526 console.log('Sponsoring Dorothy.......DONE');527 528 uniqueAssetLocation = {529 XCM: {530 parents: 1,531 interior: {X1: {Parachain: UNIQUE_CHAIN}},532 },533 };534 const existentialDeposit = 1n;535 const isSufficient = true;536 const unitsPerSecond = 1n;537 const numAssetsWeightHint = 0;538539 if((await helper.assetManager.assetTypeId(uniqueAssetLocation)).toJSON()) {540 console.log('Unique asset already registered on Moonbeam');541 } else {542 const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({543 location: uniqueAssetLocation,544 metadata: uniqueAssetMetadata,545 existentialDeposit,546 isSufficient,547 unitsPerSecond,548 numAssetsWeightHint,549 });550551 console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);552553 await helper.fastDemocracy.executeProposal('register UNQ foreign asset', encodedProposal);554 }555556 557 console.log('Acquire Unique AssetId Info on Moonbeam.......');558559 assetId = (await helper.assetManager.assetTypeId(uniqueAssetLocation)).toString();560561 console.log('UNQ asset ID is %s', assetId);562 console.log('Acquire Unique AssetId Info on Moonbeam.......DONE');563564 565 console.log('Sponsoring random Account.......');566 await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonbeam.address, 11_000_000_000_000_000_000n);567 console.log('Sponsoring random Account.......DONE');568 569 });570571 await usingPlaygrounds(async (helper) => {572 await helper.balance.transferToSubstrate(alice, randomAccountUnique.address, SENDER_BUDGET);573 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccountUnique.address);574 });575 });576577 itSub('Should connect and send UNQ to Moonbeam', async () => {578 await testHelper.sendUnqTo('moonbeam', randomAccountUnique, randomAccountMoonbeam);579 });580581 itSub('Should connect to Moonbeam and send UNQ back', async () => {582 await testHelper.sendUnqBack('moonbeam', alice, randomAccountUnique);583 });584585 itSub('Moonbeam can send only up to its balance', async () => {586 await testHelper.sendOnlyOwnedBalance('moonbeam', alice);587 });588589 itSub('Should not accept reserve transfer of UNQ from Moonbeam', async () => {590 await testHelper.reserveTransferUNQfrom('moonbeam', alice);591 });592});593594describeXCM('[XCMLL] Integration test: Exchanging tokens with Astar', () => {595 let alice: IKeyringPair;596 let randomAccount: IKeyringPair;597598 const UNQ_ASSET_ID_ON_ASTAR = 1;599 const UNQ_MINIMAL_BALANCE_ON_ASTAR = 1n;600601 602 const astarInitialBalance = 1n * (10n ** ASTAR_DECIMALS); 603 const unitsPerSecond = 228_000_000_000n; 604605 before(async () => {606 await usingPlaygrounds(async (helper, privateKey) => {607 alice = await privateKey('//Alice');608 randomAccount = helper.arrange.createEmptyAccount();609 await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);610 console.log('randomAccount', randomAccount.address);611612 613 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);614 });615616 await usingAstarPlaygrounds(astarUrl, async (helper) => {617 if(!(await helper.callRpc('api.query.assets.asset', [UNQ_ASSET_ID_ON_ASTAR])).toJSON()) {618 console.log('1. Create foreign asset and metadata');619 620 await helper.assets.create(621 alice,622 UNQ_ASSET_ID_ON_ASTAR,623 alice.address,624 UNQ_MINIMAL_BALANCE_ON_ASTAR,625 );626627 await helper.assets.setMetadata(628 alice,629 UNQ_ASSET_ID_ON_ASTAR,630 'Cross chain UNQ',631 'xcUNQ',632 Number(UNQ_DECIMALS),633 );634635 console.log('2. Register asset location on Astar');636 const assetLocation = {637 V2: {638 parents: 1,639 interior: {640 X1: {641 Parachain: UNIQUE_CHAIN,642 },643 },644 },645 };646647 await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, UNQ_ASSET_ID_ON_ASTAR]);648649 console.log('3. Set UNQ payment for XCM execution on Astar');650 await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);651 } else {652 console.log('UNQ is already registered on Astar');653 }654 console.log('4. Transfer 1 ASTR to recipient to create the account (needed due to existential balance)');655 await helper.balance.transferToSubstrate(alice, randomAccount.address, astarInitialBalance);656 });657 });658659 itSub('Should connect and send UNQ to Astar', async () => {660 await genericSendUnqTo('astar', randomAccount);661 });662663 itSub('Should connect to Astar and send UNQ back', async () => {664 await genericSendUnqBack('astar', alice, randomAccount);665 });666667 itSub('Astar can send only up to its balance', async () => {668 await genericSendOnlyOwnedBalance('astar', alice);669 });670671 itSub('Should not accept reserve transfer of UNQ from Astar', async () => {672 await genericReserveTransferUNQfrom('astar', alice);673 });674});675676describeXCM('[XCMLL] Integration test: The relay can do some root ops', () => {677 let sudoer: IKeyringPair;678679 before(async function () {680 await usingRelayPlaygrounds(relayUrl, async (_, privateKey) => {681 sudoer = await privateKey('//Alice');682 });683 });684685 686 687 688 689 690 691 692 693 694 695 696 697 afterEach(async () => {698 await usingPlaygrounds(async (helper) => {699 await helper.wait.newBlocks(3);700 });701 });702703 itSub('The relay can set storage', async () => {704 await testHelper.relayIsPermittedToSetStorage(sudoer, 'plain');705 });706707 itSub('The relay can batch set storage', async () => {708 await testHelper.relayIsPermittedToSetStorage(sudoer, 'batch');709 });710711 itSub('The relay can batchAll set storage', async () => {712 await testHelper.relayIsPermittedToSetStorage(sudoer, 'batchAll');713 });714715 itSub('The relay can forceBatch set storage', async () => {716 await testHelper.relayIsPermittedToSetStorage(sudoer, 'forceBatch');717 });718719 itSub('[negative] The relay cannot set balance', async () => {720 await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'plain');721 });722723 itSub('[negative] The relay cannot set balance via batch', async () => {724 await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'batch');725 });726727 itSub('[negative] The relay cannot set balance via batchAll', async () => {728 await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'batchAll');729 });730731 itSub('[negative] The relay cannot set balance via forceBatch', async () => {732 await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'forceBatch');733 });734735 itSub('[negative] The relay cannot set balance via dispatchAs', async () => {736 await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'dispatchAs');737 });738});