Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix hub foreign asset keys #90

Merged
merged 6 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/violet-shirts-rule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@galacticcouncil/xcm-cfg': patch
---

Fix assethub foreign balance location (v3 -> v4)
276 changes: 159 additions & 117 deletions integration-tests/xcm-test/src/__snapshots__/call.spec.ts.snap

Large diffs are not rendered by default.

505 changes: 505 additions & 0 deletions integration-tests/xcm-test/src/__snapshots__/e2e.spec.ts.snap

Large diffs are not rendered by default.

118 changes: 91 additions & 27 deletions integration-tests/xcm-test/src/call.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,8 @@ const jestConsole = console;
const { configService, init } = setup;
const { runXcm } = xcm;

describe('Wallet with XCM config', () => {
jest.setTimeout(3 * 60 * 1000); // Execution time <= 3 min

let wallet: Wallet;

const blacklist = ['acala-evm'];
const getPolkadotChains = () => {
const blacklist: string[] = ['acala-evm'];
const chains = Array.from(configService.chains.values())
.filter(
(c) =>
Expand All @@ -25,6 +21,32 @@ describe('Wallet with XCM config', () => {
)
.filter((c) => !blacklist.includes(c.key));

return {
blacklist,
chains,
};
};

const getKusamaChains = () => {
const blacklist: string[] = ['basilisk'];
const chains = Array.from(configService.chains.values())
.filter((c) => c.ecosystem === ChainEcosystem.Kusama)
.filter((c) => !blacklist.includes(c.key));

return {
blacklist,
chains,
};
};

describe('Wallet with XCM config', () => {
jest.setTimeout(3 * 60 * 1000); // Execution time <= 3 min

let wallet: Wallet;

const polkadot = getPolkadotChains();
const kusama = getKusamaChains();

beforeAll(async () => {
global.console = console;
console.log('Starting suite 👷 ...\n');
Expand All @@ -40,27 +62,69 @@ describe('Wallet with XCM config', () => {
expect(wallet).toBeDefined();
});

describe.each(chains)('should return valid calldata for', (c) => {
const config = configService.getChainRoutes(c);
const { chain, routes } = config;

for (const route of Array.from(routes.values())) {
const info = getRouteInfo(chain, route);

runXcm(
`${info} transfer`,
async () => {
return {
chain: chain,
route: route,
};
},
async () => {
return {
wallet: wallet,
};
describe.each(polkadot.chains)(
'should return valid Polkadot calldata for',
(c) => {
const config = configService.getChainRoutes(c);
const { chain, routes } = config;

for (const route of Array.from(routes.values())) {
const { blacklist } = polkadot;
const { destination } = route;

if (blacklist.includes(destination.chain.key)) {
continue;
}
);

const info = getRouteInfo(chain, route);
runXcm(
`${info} transfer`,
async () => {
return {
chain: chain,
route: route,
};
},
async () => {
return {
wallet: wallet,
};
}
);
}
}
});
);

describe.each(kusama.chains)(
'should return valid Kusama calldata for',
(c) => {
const config = configService.getChainRoutes(c);
const { chain, routes } = config;

for (const route of Array.from(routes.values())) {
const { blacklist } = kusama;
const { destination } = route;

if (blacklist.includes(destination.chain.key)) {
continue;
}

const info = getRouteInfo(chain, route);
runXcm(
`${info} transfer`,
async () => {
return {
chain: chain,
route: route,
};
},
async () => {
return {
wallet: wallet,
};
}
);
}
}
);
});
97 changes: 57 additions & 40 deletions integration-tests/xcm-test/src/e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,77 +9,94 @@ import console from 'console';

import { setup, network, xcm, SetupCtx } from './e2e';
import { getRouteInfo } from './utils';
import { write, loadExisting } from './file';

const jestConsole = console;
const DB = 'metadata.db.json';

const { configService, initWithCtx } = setup;
const { createNetworks } = network;
const { runXcm } = xcm;

const getPolkadotChains = () => {
const bridge: string[] = ['ethereum'];
const blacklist: string[] = bridge.concat(['acala-evm', 'nodle']);
const chains: Parachain[] = Array.from(configService.chains.values())
.filter((c) => c instanceof Parachain)
.filter((c) => c.ecosystem === ChainEcosystem.Polkadot)
.filter((c) => !blacklist.includes(c.key));

return {
blacklist,
bridge,
chains,
};
};

describe('Wallet with XCM config', () => {
jest.setTimeout(3 * 60 * 1000); // Execution time <= 3 min

let wallet: Wallet;
let networks: SetupCtx[] = [];

const blacklist = ['acala-evm', 'acala', 'nodle'];
const bridge = ['ethereum'];
const chains = Array.from(configService.chains.values())
.filter((c) => c instanceof Parachain)
.filter((c) => c.ecosystem === ChainEcosystem.Polkadot)
.filter((c) => !blacklist.includes(c.key));
const reportCtx = loadExisting(DB);
const polkadot = getPolkadotChains();

beforeAll(async () => {
global.console = console;
networks = await createNetworks(chains);
networks = await createNetworks(polkadot.chains);
const ctx = networks.find((n) => n.config.key === 'hydration')!;
wallet = await initWithCtx(ctx);
});

afterAll(async () => {
global.console = jestConsole;
await Promise.all(networks.map((network) => network.teardown()));
await SubstrateApis.getInstance().release();
await Promise.all(networks.map((network) => network.teardown()));
write(reportCtx, DB);
});

it('is defined', () => {
expect(configService).toBeDefined();
});

describe.each(chains)('should result in valid transfer for', (c) => {
const config = configService.getChainRoutes(c);
const { chain, routes } = config;
describe.each(polkadot.chains)(
'should result in valid Polkadot transfer for',
(c) => {
const config = configService.getChainRoutes(c);
const { chain, routes } = config;

for (const route of Array.from(routes.values())) {
const skip = bridge
.concat(blacklist)
.includes(route.destination.chain.key);
if (skip) {
continue;
}
for (const route of Array.from(routes.values())) {
const { blacklist } = polkadot;
const { destination } = route;

const info = getRouteInfo(chain, route);
runXcm(
`${info} transfer`,
async () => {
return {
chain: chain,
route: route,
};
},
async () => {
return {
networks: networks,
wallet: wallet,
};
},
{
skip:
chain.key != 'hydration' ||
route.destination.chain.key != 'zeitgeist',
//route.source.asset.key != 'wbtc_mwh',
if (blacklist.includes(destination.chain.key)) {
continue;
}
);

const isContractTransfer = !!route.contract;

const info = getRouteInfo(chain, route);
runXcm(
`${info} transfer`,
async () => {
return {
chain: chain,
route: route,
};
},
async () => {
return {
report: reportCtx,
networks: networks,
wallet: wallet,
};
},
{
skip: isContractTransfer,
}
);
}
}
});
);
});
13 changes: 13 additions & 0 deletions integration-tests/xcm-test/src/e2e/amount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Asset, AssetAmount } from '@galacticcouncil/xcm-core';

export const getAmount = async (
amount: number,
asset: Asset,
assetDecimals: number
) => {
const assetAmount = amount * 10 ** assetDecimals;
return AssetAmount.fromAsset(asset, {
decimals: assetDecimals,
amount: BigInt(assetAmount),
});
};
70 changes: 70 additions & 0 deletions integration-tests/xcm-test/src/e2e/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import type {
DispatchError,
EventRecord,
} from '@polkadot/types/interfaces/system';
import type { AnyJson } from '@polkadot/types-codec/types';
import { ApiPromise } from '@polkadot/api';

import { findNestedKey } from '../utils';

export function checkIfFailed(api: ApiPromise, events: EventRecord[]): boolean {
return events.some(({ event: { method, section, data } }) => {
const eventData = data.toHuman();
if (section === 'system' && method === 'ExtrinsicFailed') {
logEvent(section, method, eventData);
logError(api, data);
return true;
}
return false;
});
}

export function checkIfSent(events: EventRecord[]): boolean {
return events.some(({ event: { method, section, data } }) => {
const eventData = data.toHuman();
switch (section) {
case 'xcmpQueue':
logEvent(section, method, eventData);
return method === 'XcmpMessageSent';
default:
return false;
}
});
}

export function checkIfProcessed(events: EventRecord[]): boolean {
return events.some(({ event: { method, section, data } }) => {
const eventData = data.toHuman();
switch (section) {
case 'messageQueue':
logEvent(section, method, eventData);
return method === 'Processed' && checkProcessedStatus(eventData);
case 'xcmpQueue':
logEvent(section, method, eventData);
return method === 'Success';
case 'dmpQueue':
logEvent(section, method, eventData);
return method === 'ExecutedDownward';
default:
return false;
}
});
}

function checkProcessedStatus(data: AnyJson): boolean {
const dataEntry = findNestedKey(data, 'success');
return dataEntry['success'] === true;
}

function logEvent(section: string, method: string, data: AnyJson) {
console.log('🥢 STATUS: ' + section + '.' + method, data);
}

function logError(api: ApiPromise, data: any) {
const { dispatchError } = data;
const error = dispatchError as DispatchError;
const decoded = api.registry.findMetaError(error.asModule);
console.error(
`🥢 ${decoded.section}.${decoded.method}: ${decoded.docs.join(' ')}`
);
}
1 change: 1 addition & 0 deletions integration-tests/xcm-test/src/e2e/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * as moonbeam from './moonbeam';
Loading