1234567891011121314151617import {IKeyringPair} from '@polkadot/types/types';18import config from '../config';19import {itSub, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingMoonbeamPlaygrounds, usingAstarPlaygrounds, usingPolkadexPlaygrounds, usingRelayPlaygrounds} from '../util';20import {nToBigInt} from '@polkadot/util';21import {hexToString} from '@polkadot/util';22import {ASTAR_DECIMALS, SAFE_XCM_VERSION, SENDER_BUDGET, UNIQUE_CHAIN, UNQ_DECIMALS, XcmTestHelper, acalaUrl, astarUrl, moonbeamUrl, polkadexUrl, relayUrl, uniqueAssetId} from './xcm.types';2324const testHelper = new XcmTestHelper('unique');2526272829describeXCM('[XCMLL] Integration test: Exchanging tokens with Acala', () => {30 let alice: IKeyringPair;31 let randomAccount: IKeyringPair;3233 before(async () => {34 await usingPlaygrounds(async (helper, privateKey) => {35 alice = await privateKey('//Alice');36 console.log(config.acalaUrl);37 randomAccount = helper.arrange.createEmptyAccount();3839 40 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);41 });4243 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {44 const destination = {45 V2: {46 parents: 1,47 interior: {48 X1: {49 Parachain: UNIQUE_CHAIN,50 },51 },52 },53 };5455 const metadata = {56 name: 'Unique Network',57 symbol: 'UNQ',58 decimals: 18,59 minimalBalance: 1250_000_000_000_000_000n,60 };61 const assets = (await (helper.callRpc('api.query.assetRegistry.assetMetadatas.entries'))).map(([_k, v] : [any, any]) =>62 hexToString(v.toJSON()['symbol'])) as string[];6364 if(!assets.includes('UNQ')) {65 await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);66 } else {67 console.log('UNQ token already registered on Acala assetRegistry pallet');68 }69 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);70 });7172 await usingPlaygrounds(async (helper) => {73 await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);74 });75 });7677 itSub('Should connect and send UNQ to Acala', async () => {78 await testHelper.sendUnqTo('acala', randomAccount);79 });8081 itSub('Should connect to Acala and send UNQ back', async () => {82 await testHelper.sendUnqBack('acala', alice, randomAccount);83 });8485 itSub('Acala can send only up to its balance', async () => {86 await testHelper.sendOnlyOwnedBalance('acala', alice);87 });8889 itSub('Should not accept reserve transfer of UNQ from Acala', async () => {90 await testHelper.rejectReserveTransferUNQfrom('acala', alice);91 });92});9394describeXCM('[XCMLL] Integration test: Exchanging tokens with Polkadex', () => {95 let alice: IKeyringPair;96 let randomAccount: IKeyringPair;9798 before(async () => {99 await usingPlaygrounds(async (helper, privateKey) => {100 alice = await privateKey('//Alice');101 randomAccount = helper.arrange.createEmptyAccount();102103 104 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);105 });106107 await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {108 const isWhitelisted = ((await helper.callRpc('api.query.xcmHelper.whitelistedTokens', []))109 .toJSON() as [])110 .map(nToBigInt).length != 0;111 112113114115116117 if(isWhitelisted) {118 console.log('UNQ token is already whitelisted on Polkadex');119 } else {120 await helper.getSudo().xcmHelper.whitelistToken(alice, uniqueAssetId);121 }122123 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);124 });125126 await usingPlaygrounds(async (helper) => {127 await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);128 });129 });130131 itSub('Should connect and send UNQ to Polkadex', async () => {132 await testHelper.sendUnqTo('polkadex', randomAccount);133 });134135136 itSub('Should connect to Polkadex and send UNQ back', async () => {137 await testHelper.sendUnqBack('polkadex', alice, randomAccount);138 });139140 itSub('Polkadex can send only up to its balance', async () => {141 await testHelper.sendOnlyOwnedBalance('polkadex', alice);142 });143144 itSub('Should not accept reserve transfer of UNQ from Polkadex', async () => {145 await testHelper.rejectReserveTransferUNQfrom('polkadex', alice);146 });147});148149150151describeXCM('[XCMLL] Integration test: Unique rejects non-native tokens', () => {152 let alice: IKeyringPair;153154 before(async () => {155 await usingPlaygrounds(async (helper, privateKey) => {156 alice = await privateKey('//Alice');157158 159 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);160 });161 });162163 itSub('Unique rejects ACA tokens from Acala', async () => {164 await testHelper.rejectNativeTokensFrom('acala', alice);165 });166167 itSub('Unique rejects GLMR tokens from Moonbeam', async () => {168 await testHelper.rejectNativeTokensFrom('moonbeam', alice);169 });170171 itSub('Unique rejects ASTR tokens from Astar', async () => {172 await testHelper.rejectNativeTokensFrom('astar', alice);173 });174175 itSub('Unique rejects PDX tokens from Polkadex', async () => {176 await testHelper.rejectNativeTokensFrom('polkadex', alice);177 });178});179180describeXCM('[XCMLL] Integration test: Exchanging UNQ with Moonbeam', () => {181 182 let alice: IKeyringPair;183 let uniqueAssetLocation;184185 let randomAccountUnique: IKeyringPair;186 let randomAccountMoonbeam: IKeyringPair;187188 189 let assetId: string;190191 const uniqueAssetMetadata = {192 name: 'xcUnique',193 symbol: 'xcUNQ',194 decimals: 18,195 isFrozen: false,196 minimalBalance: 1n,197 };198199200 before(async () => {201 await usingPlaygrounds(async (helper, privateKey) => {202 alice = await privateKey('//Alice');203 [randomAccountUnique] = await helper.arrange.createAccounts([0n], alice);204205206 207 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);208 });209210 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {211 const alithAccount = helper.account.alithAccount();212 const baltatharAccount = helper.account.baltatharAccount();213 const dorothyAccount = helper.account.dorothyAccount();214215 randomAccountMoonbeam = helper.account.create();216217 218 console.log('Sponsoring Dorothy.......');219 await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);220 console.log('Sponsoring Dorothy.......DONE');221 222 uniqueAssetLocation = {223 XCM: {224 parents: 1,225 interior: {X1: {Parachain: UNIQUE_CHAIN}},226 },227 };228 const existentialDeposit = 1n;229 const isSufficient = true;230 const unitsPerSecond = 1n;231 const numAssetsWeightHint = 0;232233 if((await helper.assetManager.assetTypeId(uniqueAssetLocation)).toJSON()) {234 console.log('Unique asset already registered on Moonbeam');235 } else {236 const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({237 location: uniqueAssetLocation,238 metadata: uniqueAssetMetadata,239 existentialDeposit,240 isSufficient,241 unitsPerSecond,242 numAssetsWeightHint,243 });244245 console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);246247 await helper.fastDemocracy.executeProposal('register UNQ foreign asset', encodedProposal);248 }249250 251 console.log('Acquire Unique AssetId Info on Moonbeam.......');252253 assetId = (await helper.assetManager.assetTypeId(uniqueAssetLocation)).toString();254255 console.log('UNQ asset ID is %s', assetId);256 console.log('Acquire Unique AssetId Info on Moonbeam.......DONE');257258 259 console.log('Sponsoring random Account.......');260 await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonbeam.address, 11_000_000_000_000_000_000n);261 console.log('Sponsoring random Account.......DONE');262 263 });264265 await usingPlaygrounds(async (helper) => {266 await helper.balance.transferToSubstrate(alice, randomAccountUnique.address, SENDER_BUDGET);267 });268 });269270 itSub('Should connect and send UNQ to Moonbeam', async () => {271 await testHelper.sendUnqTo('moonbeam', randomAccountUnique, randomAccountMoonbeam);272 });273274 itSub('Should connect to Moonbeam and send UNQ back', async () => {275 await testHelper.sendUnqBack('moonbeam', alice, randomAccountUnique);276 });277278 itSub('Moonbeam can send only up to its balance', async () => {279 await testHelper.sendOnlyOwnedBalance('moonbeam', alice);280 });281282 itSub('Should not accept reserve transfer of UNQ from Moonbeam', async () => {283 await testHelper.rejectReserveTransferUNQfrom('moonbeam', alice);284 });285});286287describeXCM('[XCMLL] Integration test: Exchanging tokens with Astar', () => {288 let alice: IKeyringPair;289 let randomAccount: IKeyringPair;290291 const UNQ_ASSET_ID_ON_ASTAR = 18_446_744_073_709_551_631n; 292 const UNQ_MINIMAL_BALANCE_ON_ASTAR = 1n; 293294 295 const astarInitialBalance = 1n * (10n ** ASTAR_DECIMALS); 296 const unitsPerSecond = 9_451_000_000_000_000_000n; 297298 before(async () => {299 await usingPlaygrounds(async (helper, privateKey) => {300 alice = await privateKey('//Alice');301 randomAccount = helper.arrange.createEmptyAccount();302 await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);303 console.log('randomAccount', randomAccount.address);304305 306 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);307 });308309 await usingAstarPlaygrounds(astarUrl, async (helper) => {310 if(!(await helper.callRpc('api.query.assets.asset', [UNQ_ASSET_ID_ON_ASTAR])).toJSON()) {311 console.log('1. Create foreign asset and metadata');312 await helper.assets.create(313 alice,314 UNQ_ASSET_ID_ON_ASTAR,315 alice.address,316 UNQ_MINIMAL_BALANCE_ON_ASTAR,317 );318319 await helper.assets.setMetadata(320 alice,321 UNQ_ASSET_ID_ON_ASTAR,322 'Unique Network',323 'UNQ',324 Number(UNQ_DECIMALS),325 );326327 console.log('2. Register asset location on Astar');328 const assetLocation = {329 V2: {330 parents: 1,331 interior: {332 X1: {333 Parachain: UNIQUE_CHAIN,334 },335 },336 },337 };338339 await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, UNQ_ASSET_ID_ON_ASTAR]);340341 console.log('3. Set UNQ payment for XCM execution on Astar');342 await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);343 } else {344 console.log('UNQ is already registered on Astar');345 }346 console.log('4. Transfer 1 ASTR to recipient to create the account (needed due to existential balance)');347 await helper.balance.transferToSubstrate(alice, randomAccount.address, astarInitialBalance);348 });349 });350351 itSub('Should connect and send UNQ to Astar', async () => {352 await testHelper.sendUnqTo('astar', randomAccount);353 });354355 itSub('Should connect to Astar and send UNQ back', async () => {356 await testHelper.sendUnqBack('astar', alice, randomAccount);357 });358359 itSub('Astar can send only up to its balance', async () => {360 await testHelper.sendOnlyOwnedBalance('astar', alice);361 });362363 itSub('Should not accept reserve transfer of UNQ from Astar', async () => {364 await testHelper.rejectReserveTransferUNQfrom('astar', alice);365 });366});367368describeXCM('[XCMLL] Integration test: The relay can do some root ops', () => {369 let sudoer: IKeyringPair;370371 before(async function () {372 await usingRelayPlaygrounds(relayUrl, async (_, privateKey) => {373 sudoer = await privateKey('//Alice');374 });375 });376377 378 379 380 381 382 383 384 385 386 387 388 389 afterEach(async () => {390 await usingPlaygrounds(async (helper) => {391 await helper.wait.newBlocks(3);392 });393 });394395 itSub('The relay can set storage', async () => {396 await testHelper.relayIsPermittedToSetStorage(sudoer, 'plain');397 });398399 itSub('The relay can batch set storage', async () => {400 await testHelper.relayIsPermittedToSetStorage(sudoer, 'batch');401 });402403 itSub('The relay can batchAll set storage', async () => {404 await testHelper.relayIsPermittedToSetStorage(sudoer, 'batchAll');405 });406407 itSub('The relay can forceBatch set storage', async () => {408 await testHelper.relayIsPermittedToSetStorage(sudoer, 'forceBatch');409 });410411 itSub('[negative] The relay cannot set balance', async () => {412 await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'plain');413 });414415 itSub('[negative] The relay cannot set balance via batch', async () => {416 await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'batch');417 });418419 itSub('[negative] The relay cannot set balance via batchAll', async () => {420 await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'batchAll');421 });422423 itSub('[negative] The relay cannot set balance via forceBatch', async () => {424 await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'forceBatch');425 });426427 itSub('[negative] The relay cannot set balance via dispatchAs', async () => {428 await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'dispatchAs');429 });430});