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

difftreelog

source

tests/src/xcm/xcmTransferMoonbeam.test.ts14.2 KiBsourcehistory
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 chai from 'chai';18import chaiAsPromised from 'chai-as-promised';1920import {Keyring, WsProvider} from '@polkadot/api';21import {ApiOptions} from '@polkadot/api/types';22import {IKeyringPair} from '@polkadot/types/types';23import usingApi, {submitTransactionAsync} from './substrate/substrate-api';24import {getGenericResult, generateKeyringPair} from './util/helpers';25import {MultiLocation} from '@polkadot/types/interfaces';26import {blake2AsHex} from '@polkadot/util-crypto';27import getBalance from './substrate/get-balance';28import waitNewBlocks from './substrate/wait-new-blocks';2930chai.use(chaiAsPromised);31const expect = chai.expect;323334let UNIQUE_CHAIN = 0;35let MOONBEAM_CHAIN = 0;3637// parse parachain id numbers38process.argv.forEach((val) => {3940  const ai = val.indexOf('moonbeamId=');41  const ui = val.indexOf('uniqueId=');42  if (ai != -1)43  {44    MOONBEAM_CHAIN = Number(val.substring('moonbeamId='.length));45  }46  if (ui != -1)47  {48    UNIQUE_CHAIN = Number(val.substring('uniqueId='.length));49  }50});5152const UNIQUE_PORT = '9944';53const MOONBEAM_PORT = '9946';54const TRANSFER_AMOUNT = 2000000000000000000000000n;5556describe('Integration test: Exchanging UNQ with Moonbeam', () => {5758  // Unique constants59  let uniqueAlice: IKeyringPair;60  let uniqueAssetLocation;6162  let randomAccountUnique: IKeyringPair;63  let randomAccountMoonbeam: IKeyringPair;6465  // Moonbeam constants66  let assetId: Uint8Array;6768  const moonbeamKeyring = new Keyring({type: 'ethereum'});69  const alithPrivateKey = '0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133';70  const baltatharPrivateKey = '0x8075991ce870b93a8870eca0c0f91913d12f47948ca0fd25b49c6fa7cdbeee8b';71  const dorothyPrivateKey = '0x39539ab1876910bbf3a223d84a29e28f1cb4e2e456503e7e91ed39b2e7223d68';7273  const alithAccount = moonbeamKeyring.addFromUri(alithPrivateKey, undefined, 'ethereum');74  const baltatharAccount = moonbeamKeyring.addFromUri(baltatharPrivateKey, undefined, 'ethereum');75  const dorothyAccount = moonbeamKeyring.addFromUri(dorothyPrivateKey, undefined, 'ethereum');7677  const councilVotingThreshold = 2;78  const technicalCommitteeThreshold = 2;79  const votingPeriod = 3;80  const delayPeriod = 0;8182  const uniqueAssetMetadata = {83    name: 'xcUnique',84    symbol: 'xcUNQ',85    decimals: 18,86    isFrozen: false,87    minimalBalance: 1,88  };8990  // let actuallySent1: bigint;91  // let actuallySent2: bigint;9293  // let balanceUnique1: bigint;94  // let balanceUnique2: bigint;95  // let balanceUnique3: bigint;96  97  // let balanceMoonbeamGlmr1: bigint;98  // let balanceMoonbeamGlmr2: bigint;99  // let balanceMoonbeamGlmr3: bigint;100101  let balanceUniqueTokenBefore: bigint;102  let balanceUniqueTokenAfter: bigint;103  let balanceUniqueTokenFinal: bigint;104  let balanceGlmrTokenBefore: bigint;105  let balanceGlmrTokenAfter: bigint;106  let balanceGlmrTokenFinal: bigint;107108  before(async () => {109    await usingApi(async (api, privateKeyWrapper) => {110      uniqueAlice = privateKeyWrapper('//Alice');111      randomAccountUnique = generateKeyringPair();112      randomAccountMoonbeam = generateKeyringPair('ethereum');113    });114115    const moonbeamApiOptions: ApiOptions = {116      provider: new WsProvider('ws://127.0.0.1:' + MOONBEAM_PORT),117    };118119    await usingApi(120      async (api) => {121122        // >>> Sponsoring Dorothy >>>123        const tx0 = api.tx.balances.transfer(dorothyAccount.address, 11_000_000_000_000_000_000n);124        const events0 = await submitTransactionAsync(alithAccount, tx0);125        const result0 = getGenericResult(events0);126        expect(result0.success).to.be.true;127        // <<< Sponsoring Dorothy <<<128129        const sourceLocation: MultiLocation = api.createType(130          'MultiLocation',131          {132            parents: 1,133            interior: {X1: {Parachain: UNIQUE_CHAIN}},134          },135        );136137        assetId = api.registry.hash(sourceLocation.toU8a()).slice(0, 16).reverse();138        console.log('Internal asset ID is %s', assetId);139        uniqueAssetLocation = {XCM: sourceLocation};140        const existentialDeposit = 1;141        const isSufficient = true;142        const unitsPerSecond = '1';143        const numAssetsWeightHint = 0;144145        const registerTx = api.tx.assetManager.registerForeignAsset(146          uniqueAssetLocation,147          uniqueAssetMetadata,148          existentialDeposit,149          isSufficient,150        );151        console.log('Encoded proposal for registerAsset is %s', registerTx.method.toHex() || '');152153        const setUnitsTx = api.tx.assetManager.setAssetUnitsPerSecond(154          uniqueAssetLocation,155          unitsPerSecond,156          numAssetsWeightHint,157        );158        console.log('Encoded proposal for setAssetUnitsPerSecond is %s', setUnitsTx.method.toHex() || '');159160        const batchCall = api.tx.utility.batchAll([registerTx, setUnitsTx]);161        console.log('Encoded proposal for batchCall is %s', batchCall.method.toHex() || '');162163        // >>> Note motion preimage >>>164        const encodedProposal = batchCall?.method.toHex() || '';165        const proposalHash = blake2AsHex(encodedProposal);166        console.log('Encoded proposal for batch utility after schedule is %s', encodedProposal);167        console.log('Encoded proposal hash for batch utility after schedule is %s', proposalHash);168        console.log('Encoded length %d', encodedProposal.length);169170        const tx1 = api.tx.democracy.notePreimage(encodedProposal);171        const events1 = await submitTransactionAsync(baltatharAccount, tx1);172        const result1 = getGenericResult(events1);173        expect(result1.success).to.be.true;174        // <<< Note motion preimage <<<175176        // >>> Propose external motion through council >>>177        const externalMotion = api.tx.democracy.externalProposeMajority(proposalHash);178        const tx2 = api.tx.councilCollective.propose(179          councilVotingThreshold,180          externalMotion,181          externalMotion.encodedLength,182        );183        const events2 = await submitTransactionAsync(baltatharAccount, tx2);184        const result2 = getGenericResult(events2);185        expect(result2.success).to.be.true;186187        const encodedMotion = externalMotion?.method.toHex() || '';188        const motionHash = blake2AsHex(encodedMotion);189        console.log('Motion hash is %s', motionHash);190191        const tx3 = api.tx.councilCollective.vote(motionHash, 0, true);192        {193          const events3 = await submitTransactionAsync(dorothyAccount, tx3);194          const result3 = getGenericResult(events3);195          expect(result3.success).to.be.true;196        }197        {198          const events3 = await submitTransactionAsync(baltatharAccount, tx3);199          const result3 = getGenericResult(events3);200          expect(result3.success).to.be.true;201        }202203        const tx4 = api.tx.councilCollective.close(motionHash, 0, 1_000_000_000, externalMotion.encodedLength);204        const events4 = await submitTransactionAsync(dorothyAccount, tx4);205        const result4 = getGenericResult(events4);206        expect(result4.success).to.be.true;207        // <<< Propose external motion through council <<<208209        // >>> Fast track proposal through technical committee >>>210        const fastTrack = api.tx.democracy.fastTrack(proposalHash, votingPeriod, delayPeriod);211        const tx5 = api.tx.techCommitteeCollective.propose(212          technicalCommitteeThreshold,213          fastTrack,214          fastTrack.encodedLength,215        );216        const events5 = await submitTransactionAsync(alithAccount, tx5);217        const result5 = getGenericResult(events5);218        expect(result5.success).to.be.true;219220        const encodedFastTrack = fastTrack?.method.toHex() || '';221        const fastTrackHash = blake2AsHex(encodedFastTrack);222        console.log('FastTrack hash is %s', fastTrackHash);223224        const proposalIdx = Number(await api.query.techCommitteeCollective.proposalCount()) - 1;225        const tx6 = api.tx.techCommitteeCollective.vote(fastTrackHash, proposalIdx, true);226        {227          const events6 = await submitTransactionAsync(baltatharAccount, tx6);228          const result6 = getGenericResult(events6);229          expect(result6.success).to.be.true;230        }231        {232          const events6 = await submitTransactionAsync(alithAccount, tx6);233          const result6 = getGenericResult(events6);234          expect(result6.success).to.be.true;235        }236237        const tx7 = api.tx.techCommitteeCollective238          .close(fastTrackHash, proposalIdx, 1_000_000_000, fastTrack.encodedLength);239        const events7 = await submitTransactionAsync(baltatharAccount, tx7);240        const result7 = getGenericResult(events7);241        expect(result7.success).to.be.true;242        // <<< Fast track proposal through technical committee <<<243244        // >>> Referendum voting >>>245        const tx8 = api.tx.democracy.vote(246          0,247          {Standard: {balance: 10_000_000_000_000_000_000n, vote: {aye: true, conviction: 1}}},248        );249        const events8 = await submitTransactionAsync(dorothyAccount, tx8);250        const result8 = getGenericResult(events8);251        expect(result8.success).to.be.true;252        // <<< Referendum voting <<<253254        // >>> Sponsoring random Account >>>255        const tx9 = api.tx.balances.transfer(randomAccountMoonbeam.address, 11_000_000_000_000_000_000n);256        const events9 = await submitTransactionAsync(baltatharAccount, tx9);257        const result9 = getGenericResult(events9);258        expect(result9.success).to.be.true;259        // <<< Sponsoring random Account <<<260261        [balanceGlmrTokenBefore] = await getBalance(api, [randomAccountMoonbeam.address]);262      },263      moonbeamApiOptions,264    );265266    await usingApi(async (api) => {267      const tx0 = api.tx.balances.transfer(randomAccountUnique.address, 10n * TRANSFER_AMOUNT);268      const events0 = await submitTransactionAsync(uniqueAlice, tx0);269      const result0 = getGenericResult(events0);270      expect(result0.success).to.be.true;271272      [balanceUniqueTokenBefore] = await getBalance(api, [randomAccountUnique.address]);273    });274  });275276  it('Should connect and send UNQ to Moonbeam', async () => {277    await usingApi(async (api) => {278      const currencyId = {279        NativeAssetId: 'Here',280      };281      const dest = {282        V1: {283          parents: 1,284          interior: {285            X2: [286              {Parachain: MOONBEAM_CHAIN},287              {AccountKey20: {network: 'Any', key: randomAccountMoonbeam.address}},288            ],289          },290        },291      };292      const amount = TRANSFER_AMOUNT;293      const destWeight = 50000000;294295      const tx = api.tx.xTokens.transfer(currencyId, amount, dest, destWeight);296      const events = await submitTransactionAsync(uniqueAlice, tx);297      const result = getGenericResult(events);298      expect(result.success).to.be.true;299300      [balanceUniqueTokenAfter] = await getBalance(api, [randomAccountUnique.address]);301      expect(balanceUniqueTokenAfter < balanceUniqueTokenBefore).to.be.true;302303      const transactionFees = balanceUniqueTokenBefore - balanceUniqueTokenAfter - TRANSFER_AMOUNT;304      console.log('Unique to Moonbeam transaction fees on Unique: %s UNQ', transactionFees);305      expect(transactionFees > 0).to.be.true;306    });307308    await usingApi(309      async (api) => {310        // todo do something about instant sealing, where there might not be any new blocks311        await waitNewBlocks(api, 3);312313        [balanceGlmrTokenAfter] = await getBalance(api, [randomAccountMoonbeam.address]);314315        const glmrFees = balanceGlmrTokenBefore - balanceGlmrTokenAfter;316        console.log('Unique to Moonbeam transaction fees on Moonbeam: %s GLMR', glmrFees);317        expect(glmrFees == 0n).to.be.true;318      },319      {provider: new WsProvider('ws://127.0.0.1:' + MOONBEAM_PORT)},320    );321  });322323  it('Should connect to Moonbeam and send UNQ back', async () => {324    await usingApi(325      async (api) => {326        const amount = TRANSFER_AMOUNT / 2n;327        const asset = {328          V1: {329            id: {330              Concrete: {331                parents: 1,332                interior: {333                  X1: {Parachain: UNIQUE_CHAIN},334                },335              },336            },337            fun: {338              Fungible: amount,339            },340          },341        };342        const destination = {343          V1: {344            parents: 1,345            interior: {346              X2: [347                {Parachain: UNIQUE_CHAIN},348                {AccountId32: {network: 'Any', id: randomAccountUnique.addressRaw}},349              ],350            },351          },352        };353        const destWeight = 50000000;354355        const tx = api.tx.xTokens.transferMultiasset(asset, destination, destWeight);356        const events = await submitTransactionAsync(randomAccountMoonbeam, tx);357        const result = getGenericResult(events);358        expect(result.success).to.be.true;359360        [balanceGlmrTokenFinal] = await getBalance(api, [randomAccountMoonbeam.address]);361362        const glmrFees = balanceGlmrTokenAfter - balanceGlmrTokenFinal;363        console.log('Moonbeam to Unique transaction fees on Moonbeam: %s GLMR', glmrFees);364        expect(glmrFees > 0).to.be.true;365      },366      {provider: new WsProvider('ws://127.0.0.1:' + MOONBEAM_PORT)},367    );368369    await usingApi(async (api) => {370      // todo do something about instant sealing, where there might not be any new blocks371      await waitNewBlocks(api, 3);372373      [balanceUniqueTokenFinal] = await getBalance(api, [randomAccountUnique.address]);374      const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenAfter;375      expect(actuallyDelivered > 0).to.be.true;376377      const unqFees = TRANSFER_AMOUNT - actuallyDelivered;378      console.log('Moonbeam to Unique transaction fees on Unique: %s UNQ', unqFees);379      expect(unqFees > 0).to.be.true;380    });381  });382});