1234567891011121314151617import {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 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});848586describeXCM('[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 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 116 let alice: IKeyringPair;117 let quartzAssetLocation;118119 let randomAccountQuartz: IKeyringPair;120 let randomAccountMoonriver: IKeyringPair;121122 123 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 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 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 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 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 191192 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 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.reserveTransferUNQfrom('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 = 1;226 const QTZ_MINIMAL_BALANCE_ON_SHIDEN = 1n;227228 229 const shidenInitialBalance = 1n * (10n ** SHIDEN_DECIMALS); 230 const unitsPerSecond = 228_000_000_000n; 231232233234 before(async () => {235 await usingPlaygrounds(async (helper, privateKey) => {236 alice = await privateKey('//Alice');237 randomAccount = helper.arrange.createEmptyAccount();238 await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);239 console.log('sender: ', randomAccount.address);240241 242 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);243 });244245 await usingShidenPlaygrounds(shidenUrl, async (helper) => {246 if(!(await helper.callRpc('api.query.assets.asset', [QTZ_ASSET_ID_ON_SHIDEN])).toJSON()) {247 console.log('1. Create foreign asset and metadata');248 249 await helper.assets.create(250 alice,251 QTZ_ASSET_ID_ON_SHIDEN,252 alice.address,253 QTZ_MINIMAL_BALANCE_ON_SHIDEN,254 );255256 await helper.assets.setMetadata(257 alice,258 QTZ_ASSET_ID_ON_SHIDEN,259 'Cross chain QTZ',260 'xcQTZ',261 Number(QTZ_DECIMALS),262 );263264 console.log('2. Register asset location on Shiden');265 const assetLocation = {266 V2: {267 parents: 1,268 interior: {269 X1: {270 Parachain: QUARTZ_CHAIN,271 },272 },273 },274 };275276 await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, QTZ_ASSET_ID_ON_SHIDEN]);277278 console.log('3. Set QTZ payment for XCM execution on Shiden');279 await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);280 } else {281 console.log('QTZ is already registered on Shiden');282 }283 console.log('4. Transfer 1 SDN to recipient to create the account (needed due to existential balance)');284 await helper.balance.transferToSubstrate(alice, randomAccount.address, shidenInitialBalance);285 });286 });287288 itSub('Should connect and send QTZ to Shiden', async () => {289 await testHelper.sendUnqTo('shiden', randomAccount);290 });291292 itSub('Should connect to Shiden and send QTZ back', async () => {293 await testHelper.sendUnqBack('shiden', alice, randomAccount);294 });295296 itSub('Shiden can send only up to its balance', async () => {297 await testHelper.sendOnlyOwnedBalance('shiden', alice);298 });299300 itSub('Should not accept reserve transfer of QTZ from Shiden', async () => {301 await testHelper.reserveTransferUNQfrom('shiden', alice);302 });303});304305describeXCM('[XCMLL] Integration test: The relay can do some root ops', () => {306 let sudoer: IKeyringPair;307308 before(async function () {309 await usingRelayPlaygrounds(relayUrl, async (_, privateKey) => {310 sudoer = await privateKey('//Alice');311 });312 });313314 315 316 317 318 319 320 321 322 323 324 325 326 afterEach(async () => {327 await usingPlaygrounds(async (helper) => {328 await helper.wait.newBlocks(3);329 });330 });331332 itSub('The relay can set storage', async () => {333 await testHelper.relayIsPermittedToSetStorage(sudoer, 'plain');334 });335336 itSub('The relay can batch set storage', async () => {337 await testHelper.relayIsPermittedToSetStorage(sudoer, 'batch');338 });339340 itSub('The relay can batchAll set storage', async () => {341 await testHelper.relayIsPermittedToSetStorage(sudoer, 'batchAll');342 });343344 itSub('The relay can forceBatch set storage', async () => {345 await testHelper.relayIsPermittedToSetStorage(sudoer, 'forceBatch');346 });347348 itSub('[negative] The relay cannot set balance', async () => {349 await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'plain');350 });351352 itSub('[negative] The relay cannot set balance via batch', async () => {353 await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'batch');354 });355356 itSub('[negative] The relay cannot set balance via batchAll', async () => {357 await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'batchAll');358 });359360 itSub('[negative] The relay cannot set balance via forceBatch', async () => {361 await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'forceBatch');362 });363364 itSub('[negative] The relay cannot set balance via dispatchAs', async () => {365 await testHelper.relayIsNotPermittedToSetBalance(sudoer, 'dispatchAs');366 });367});