diff --git a/packages/core/src/xcm/horizontal.ts b/packages/core/src/xcm/horizontal.ts index c7573252..cb46d8ea 100644 --- a/packages/core/src/xcm/horizontal.ts +++ b/packages/core/src/xcm/horizontal.ts @@ -30,5 +30,15 @@ export const connectHorizontal = async (parachains: Record) } } }) + + const hrmpHeads = await chain.head.read('BTreeMap', meta.query.parachainSystem.lastHrmpMqcHeads) + if (hrmpHeads && !process.env.DISABLE_AUTO_HRMP) { + const existingChannels = Array.from(hrmpHeads.keys()).map((x) => x.toNumber()) + for (const paraId of Object.keys(parachains).filter((x) => x !== id)) { + if (!existingChannels.includes(Number(paraId))) { + chain.submitHorizontalMessages(Number(paraId), []) + } + } + } } } diff --git a/packages/e2e/src/__snapshots__/connect-horizontal.test.ts.snap b/packages/e2e/src/__snapshots__/connect-horizontal.test.ts.snap new file mode 100644 index 00000000..ed29851a --- /dev/null +++ b/packages/e2e/src/__snapshots__/connect-horizontal.test.ts.snap @@ -0,0 +1,30 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`connectHorizontal > connectHorizontal opens channel > system events 1`] = ` +[ + { + "data": { + "messageHash": "(hash)", + }, + "method": "XcmpMessageSent", + "section": "xcmpQueue", + }, +] +`; + +exports[`connectHorizontal > connectHorizontal opens channel > system events 2`] = ` +[ + { + "data": { + "error": "TooExpensive", + "messageHash": "(hash)", + "weight": { + "proofSize": 0, + "refTime": 600000000, + }, + }, + "method": "Fail", + "section": "xcmpQueue", + }, +] +`; diff --git a/packages/e2e/src/connect-horizontal.test.ts b/packages/e2e/src/connect-horizontal.test.ts new file mode 100644 index 00000000..0596c2c0 --- /dev/null +++ b/packages/e2e/src/connect-horizontal.test.ts @@ -0,0 +1,69 @@ +import { connectHorizontal } from '@acala-network/chopsticks-core/xcm/horizontal.js' +import { describe, it } from 'vitest' + +import { checkSystemEvents, setupContext, testingPairs } from './helper.js' +import networks from './networks.js' + +describe('connectHorizontal', () => { + it('connectHorizontal opens channel', async () => { + const { alice } = testingPairs() + const acala = await networks.acala({ blockNumber: 5729464 }) + await acala.dev.setStorage({ + System: { + Account: [[[alice.address], { providers: 1, data: { free: 1000e12 } }]], + }, + }) + const zeitgeist = await setupContext({ + endpoint: 'wss://zeitgeist-rpc.dwellir.com', + blockNumber: 5084336, + db: !process.env.RUN_TESTS_WITHOUT_DB ? 'e2e-tests-db.sqlite' : undefined, + }) + + await connectHorizontal({ + 2000: acala.chain, + 2092: zeitgeist.chain, + }) + + await acala.dev.newBlock() + await zeitgeist.dev.newBlock() + + // This tx will be sent to Zeitgeist and fail but it's fine for this test as we only want to test the connection + await acala.api.tx.xTokens + .transfer( + { + Token: 'ACA', + }, + 1e12, + { + V3: { + parents: 1, + interior: { + X2: [ + { + Parachain: 2092, + }, + { + AccountId32: { + id: alice.addressRaw, + }, + }, + ], + }, + }, + }, + { + Unlimited: null, + }, + ) + .signAndSend(alice) + + await acala.dev.newBlock() + await checkSystemEvents(acala, 'xcmpQueue', 'XcmpMessageSent').toMatchSnapshot() + + await zeitgeist.dev.newBlock() + await checkSystemEvents(zeitgeist, 'xcmpQueue', 'Fail').toMatchSnapshot() + + await acala.teardown() + await zeitgeist.teardown() + }) +})