Skip to content

Commit

Permalink
test: add foreign assets script to test network (#272)
Browse files Browse the repository at this point in the history
Co-authored-by: bee344 <[email protected]>
Co-authored-by: Alberto Nicolas Penayo <[email protected]>
  • Loading branch information
3 people authored Nov 2, 2023
1 parent e1dbdc0 commit 8f11c7a
Show file tree
Hide file tree
Showing 6 changed files with 295 additions and 105 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"build:examples": "substrate-exec-rimraf examples/build/ && substrate-exec-tsc --project examples/tsconfig.json",
"start": "node ./lib/index.js",
"start:zombienet-post-script": "yarn build:scripts && node ./scripts/build/testNetworkSetup.js",
"start:zombienet-foreign-assets-script": "yarn build:scripts && node ./scripts/build/testNetworkForeignAssets.js",
"lint": "substrate-dev-run-lint",
"lint:fix": "substrate-dev-run-lint --fix",
"test": "NODE_ENV=test substrate-exec-jest --detectOpenHandles",
Expand Down
5 changes: 5 additions & 0 deletions scripts/consts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright 2023 Parity Technologies (UK) Ltd.

export const KUSAMA_ASSET_HUB_WS_URL = 'ws://127.0.0.1:9911';
export const ROCOCO_ALICE_WS_URL = 'ws://127.0.0.1:9900';
export const TRAPPIST_WS_URL = 'ws://127.0.0.1:9921';
220 changes: 220 additions & 0 deletions scripts/testNetworkForeignAssets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
// Copyright 2023 Parity Technologies (UK) Ltd.

import { ApiPromise, WsProvider } from '@polkadot/api';
import { Keyring } from '@polkadot/keyring';
import { cryptoWaitReady } from '@polkadot/util-crypto';
import chalk from 'chalk';

import { KUSAMA_ASSET_HUB_WS_URL, TRAPPIST_WS_URL } from './consts';
import { awaitBlockProduction, delay, logWithDate } from './util';

const fAssetSetMetadataCall = (assetHubApi: ApiPromise): `0x${string}` => {
const trappistMultiLocation = {
parents: 1,
interior: {
X1: {
parachain: 1836,
},
},
};

const setMetadataTx = assetHubApi.tx.foreignAssets.setMetadata(trappistMultiLocation, 'Trappist Hop', 'Hop', 12);

const hexCall = assetHubApi.registry
.createType('Call', {
callIndex: setMetadataTx.callIndex,
args: setMetadataTx.args,
})
.toHex();

return hexCall;
};

const fAssetCreateCall = (assetHubApi: ApiPromise): `0x${string}` => {
const trappistMultiLocation = {
parents: 1,
interior: {
X1: {
parachain: 1836,
},
},
};

const createTx = assetHubApi.tx.foreignAssets.create(
trappistMultiLocation,
'5Eg2fnsjAAr8RGZfa8Sy5mYFPabA9ZLNGYECCKXPD6xnK6D2', // Sibling 1836 -> ParaId
'100000000000'
);

const hexCall = assetHubApi.registry
.createType('Call', {
callIndex: createTx.callIndex,
args: createTx.args,
})
.toHex();

return hexCall;
};

const sudoCallWrapper = (trappistApi: ApiPromise, call: `0x${string}`) => {
// Double encode the call
const xcmDoubleEncoded = trappistApi.createType('XcmDoubleEncoded', {
encoded: call,
});

const xcmOriginType = trappistApi.createType('XcmOriginKind', 'Xcm');
const xcmDestMultiLocation = {
V3: {
parents: 1,
interior: {
X1: {
parachain: 1000,
},
},
},
};
const xcmMessage = {
V3: [
{
withdrawAsset: [
{
id: {
concrete: {
parents: 1,
interior: { Here: '' },
},
},
fun: {
fungible: 100000000000,
},
},
],
},
{
buyExecution: {
fees: {
id: {
concrete: {
parents: 1,
interior: { Here: '' },
},
},
fun: {
fungible: 100000000000,
},
},
weightLimit: { Unlimited: '' },
},
},
{
transact: {
originKind: xcmOriginType,
requireWeightAtMost: {
refTime: 8000000000,
proofSize: 65536,
},
call: xcmDoubleEncoded,
},
},
{
refundSurplus: true,
},
{
depositAsset: {
assets: {
wild: {
All: '',
},
},
beneficiary: {
parents: 0,
interior: {
x1: {
AccountId32: {
id: '0x7369626c2c070000000000000000000000000000000000000000000000000000',
},
},
},
},
},
},
],
};
const xcmMsg = trappistApi.tx.polkadotXcm.send(xcmDestMultiLocation, xcmMessage);
const xcmCall = trappistApi.createType('Call', {
callIndex: xcmMsg.callIndex,
args: xcmMsg.args,
});

return xcmCall;
};

const createForeignAssetViaSudo = (assetHubApi: ApiPromise, trappistApi: ApiPromise) => {
const foreignAssetCreateCall = fAssetCreateCall(assetHubApi);
return sudoCallWrapper(trappistApi, foreignAssetCreateCall);
};

const setMetadataForeignAssetViaSudo = (assetHubApi: ApiPromise, trappistApi: ApiPromise) => {
const setMetadataCall = fAssetSetMetadataCall(assetHubApi);
return sudoCallWrapper(trappistApi, setMetadataCall);
};

const main = async () => {
logWithDate(chalk.yellow('Initializing script to create foreignAssets on chain'));
await cryptoWaitReady();

const keyring = new Keyring({ type: 'sr25519' });
const alice = keyring.addFromUri('//Alice');
const bob = keyring.addFromUri('//Bob');

const kusamaAssetHubApi = await ApiPromise.create({
provider: new WsProvider(KUSAMA_ASSET_HUB_WS_URL),
noInitWarn: true,
});

await kusamaAssetHubApi.isReady;
logWithDate(chalk.green('Created a connection to Kusama AssetHub'));

const trappistApi = await ApiPromise.create({
provider: new WsProvider(TRAPPIST_WS_URL),
noInitWarn: true,
});

await trappistApi.isReady;
logWithDate(chalk.green('Created a connection to Trappist'));

logWithDate(chalk.magenta('Sending funds to Trappist Sibling on Kusama AssetHub'));

await kusamaAssetHubApi.tx.balances
.transferKeepAlive('5Eg2fnsjAAr8RGZfa8Sy5mYFPabA9ZLNGYECCKXPD6xnK6D2', 10000000000000)
.signAndSend(bob);

const foreignAssetsCreateSudoXcmCall = createForeignAssetViaSudo(kusamaAssetHubApi, trappistApi);

logWithDate('Sending Sudo XCM message from relay chain to execute create foreign asset call on Kusama AssetHub');
await trappistApi.tx.sudo.sudo(foreignAssetsCreateSudoXcmCall).signAndSend(alice);

await delay(24000);

const foreignAssetsSetMetadataSudoXcmCall = setMetadataForeignAssetViaSudo(kusamaAssetHubApi, trappistApi);

logWithDate('Sending Sudo XCM message from relay chain to execute setMetadata call on Kusama AssetHub');
await trappistApi.tx.sudo.sudo(foreignAssetsSetMetadataSudoXcmCall).signAndSend(alice);

await delay(24000);

await kusamaAssetHubApi.disconnect().then(() => {
logWithDate(chalk.blue('Polkadot-js successfully disconnected from asset-hub'));
});

await trappistApi.disconnect().then(() => {
logWithDate(chalk.blue('Polkadot-js successfully disconnected from trappist'));
});
};

// eslint-disable-next-line @typescript-eslint/no-floating-promises
awaitBlockProduction(TRAPPIST_WS_URL).then(async () => {
await main()
.catch(console.error)
.finally(() => process.exit());
});
63 changes: 4 additions & 59 deletions scripts/testNetworkSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,72 +5,17 @@ import '@polkadot/api-augment';
import { ApiPromise, WsProvider } from '@polkadot/api';
import { Keyring } from '@polkadot/keyring';
import { DispatchError } from '@polkadot/types/interfaces';
import { formatDate } from '@polkadot/util';
import { cryptoWaitReady } from '@polkadot/util-crypto';
import chalk from 'chalk';

import { KUSAMA_ASSET_HUB_WS_URL, ROCOCO_ALICE_WS_URL } from './consts';
import { awaitBlockProduction, delay, logWithDate } from './util';

/**
* This script is intended to be run after zombienet is running.
* It uses the hard coded values given in `zombienet.toml`.
*/

const KUSAMA_ASSET_HUB_WS_URL = 'ws://127.0.0.1:9911';
const ROCOCO_ALICE_WS_URL = 'ws://127.0.0.1:9900';

/**
* Set a delay (sleep)
*
* @param ms Milliseconds
*/
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

/**
* Formats a string to match the output of polkadot-js logging.
*
* @param log String to be logged
* @param remove Remove lines before that were cleared by std
*/
const logWithDate = (log: string, remove?: boolean) => {
remove
? console.log(`\r${formatDate(new Date())} ${log}`)
: console.log(`${formatDate(new Date())} ${log}`);
};

/**
* Will block the main script from running until there is blocks in Polkadot AssetHub being produced.
*/
const awaitBlockProduction = async () => {
logWithDate(chalk.yellow(`Initializing polkadot-js: Polling until ${KUSAMA_ASSET_HUB_WS_URL} is available`));
const kusamaAssetHubApi = await ApiPromise.create({
provider: new WsProvider(KUSAMA_ASSET_HUB_WS_URL),
noInitWarn: true,
});
logWithDate(chalk.yellow('Polkadot-js is connected'));

await kusamaAssetHubApi.isReady;

let counter = 3;
let blocksProducing = false;
while (!blocksProducing) {
const { number } = await kusamaAssetHubApi.rpc.chain.getHeader();

if (number.toNumber() > 0) {
blocksProducing = true;
}
await delay(1000);

counter += 1;
process.stdout.clearLine(0);
process.stdout.write(`\rWaiting for Block production on Kusama AssetHub${'.'.repeat((counter % 3) + 1)}`);
}

process.stdout.clearLine(0);
logWithDate(chalk.magenta('Blocks are producing'), true);
await kusamaAssetHubApi.disconnect().then(() => {
logWithDate(chalk.blue('Polkadot-js successfully disconnected'));
});
};

const main = async () => {
logWithDate(chalk.yellow('Initializing script to run transaction on chain'));
await cryptoWaitReady();
Expand Down Expand Up @@ -214,7 +159,7 @@ const main = async () => {
};

// eslint-disable-next-line @typescript-eslint/no-floating-promises
awaitBlockProduction().then(async () => {
awaitBlockProduction(KUSAMA_ASSET_HUB_WS_URL).then(async () => {
await main()
.catch(console.error)
.finally(() => process.exit());
Expand Down
59 changes: 59 additions & 0 deletions scripts/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2023 Parity Technologies (UK) Ltd.

import { ApiPromise, WsProvider } from '@polkadot/api';
import { formatDate } from '@polkadot/util';
import chalk from 'chalk';

/**
* Set a delay (sleep)
*
* @param ms Milliseconds
*/
export const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

/**
* Formats a string to match the output of polkadot-js logging.
*
* @param log String to be logged
* @param remove Remove lines before that were cleared by std
*/
export const logWithDate = (log: string, remove?: boolean) => {
remove
? console.log(`\r${formatDate(new Date())} ${log}`)
: console.log(`${formatDate(new Date())} ${log}`);
};

/**
* Will block the main script from running until there is blocks in Polkadot AssetHub being produced.
*/
export const awaitBlockProduction = async (wsUrl: string) => {
logWithDate(chalk.yellow(`Initializing polkadot-js: Polling until ${wsUrl} is available`));
const api = await ApiPromise.create({
provider: new WsProvider(wsUrl),
noInitWarn: true,
});
logWithDate(chalk.yellow('Polkadot-js is connected'));

await api.isReady;

let counter = 3;
let blocksProducing = false;
while (!blocksProducing) {
const { number } = await api.rpc.chain.getHeader();

if (number.toNumber() > 0) {
blocksProducing = true;
}
await delay(1000);

counter += 1;
process.stdout.clearLine(0);
process.stdout.write(`\rWaiting for Block production on Kusama AssetHub${'.'.repeat((counter % 3) + 1)}`);
}

process.stdout.clearLine(0);
logWithDate(chalk.magenta('Blocks are producing'), true);
await api.disconnect().then(() => {
logWithDate(chalk.blue('Polkadot-js successfully disconnected'));
});
};
Loading

0 comments on commit 8f11c7a

Please sign in to comment.