From d6c3f03d6db15d1bffd1f69d348463cb93a1e219 Mon Sep 17 00:00:00 2001 From: Adel Golghalyani Date: Fri, 31 May 2024 13:03:44 +0200 Subject: [PATCH] first mvp --- .../chopsticks/src/helper/api.ts | 4 +- .../src/network/polkadot/hydraDx.ts | 8 +- .../chopsticks/src/network/polkadot/index.ts | 29 ++- .../chopsticks/src/network/polkadot/relay.ts | 6 +- .../src/network/polkadot/spiritnet.ts | 6 +- .../chopsticks/src/network/types.ts | 5 +- .../chopsticks/src/tests/index.ts | 1 + .../__snapshots__/index.test.ts.snap | 161 ++++++++++++++ .../__snapshots__/transfers.test.ts.snap | 30 --- .../xcm/limitedReserveTransfer/config.ts | 207 ++++++++++++++++++ .../xcm/limitedReserveTransfer/index.test.ts | 120 ++++++++++ .../tests/xcm/limitedReserveTransfer/index.ts | 124 ----------- .../limitedReserveTransfer/transfers.test.ts | 140 ------------ ...mitedReserveTransferSpiritnetHydraDxV3.ts} | 0 ...limitedReseveTransferHydraDxSpiritnet..ts} | 0 15 files changed, 534 insertions(+), 307 deletions(-) create mode 100644 integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/__snapshots__/index.test.ts.snap delete mode 100644 integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/__snapshots__/transfers.test.ts.snap create mode 100644 integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/config.ts create mode 100644 integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/index.test.ts delete mode 100644 integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/index.ts delete mode 100644 integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/transfers.test.ts rename integration-tests/chopsticks/src/tests/xcm/{limitedReserveTransferSpiritnetHydraDxV3.test.ts => limitedReserveTransferSpiritnetHydraDxV3.ts} (100%) rename integration-tests/chopsticks/src/tests/xcm/{limitedReseveTransferHydraDxSpiritnet.test.ts => limitedReseveTransferHydraDxSpiritnet..ts} (100%) diff --git a/integration-tests/chopsticks/src/helper/api.ts b/integration-tests/chopsticks/src/helper/api.ts index d906aabbc..58cee42be 100644 --- a/integration-tests/chopsticks/src/helper/api.ts +++ b/integration-tests/chopsticks/src/helper/api.ts @@ -34,8 +34,8 @@ export const xtokens = { }, }), transfer: - (token: any, amount: any, dest: (dest: any) => any, weight: any = 'Unlimited') => - ({ api }: { api: ApiPromise }, acc: any) => + (token: any, dest: (dest: any) => any, weight: any = 'Unlimited') => + ({ api }: { api: ApiPromise }, acc: any, amount: any) => api.tx.xTokens.transfer(token, amount, dest(acc), weight), } diff --git a/integration-tests/chopsticks/src/network/polkadot/hydraDx.ts b/integration-tests/chopsticks/src/network/polkadot/hydraDx.ts index 2f4a8dfe6..41bd68477 100644 --- a/integration-tests/chopsticks/src/network/polkadot/hydraDx.ts +++ b/integration-tests/chopsticks/src/network/polkadot/hydraDx.ts @@ -3,12 +3,16 @@ import { SetupOption } from '@acala-network/chopsticks-testing' import { initialBalanceHDX, initialBalanceKILT, toNumber } from '../../helper/utils.js' /// Options used to create the HydraDx context -export const getSetupOptions = (blockNumber: number | undefined = undefined) => +export const getSetupOptions = ( + blockNumber: number | undefined = undefined, + wasmOverride: string | undefined = undefined +) => ({ endpoint: process.env.HYDRADX_WS || ['wss://hydradx-rpc.dwellir.com', 'wss://rpc.hydradx.cloud'], db: './db/hydradx.db.sqlite', port: toNumber(process.env.HYDRADX_PORT) || 9001, blockNumber, + wasmOverride, }) as SetupOption export const kiltTokenId = 28 @@ -39,6 +43,8 @@ export function assignKiltTokensToAccounts(addr: string[], balance: bigint = ini } } +export const KILTLocation = { Concrete: { parents: 1, interior: { X1: [{ Parachain: 2086 }] } } } + /// HydraDX ParaId export const paraId = 2034 diff --git a/integration-tests/chopsticks/src/network/polkadot/index.ts b/integration-tests/chopsticks/src/network/polkadot/index.ts index a8d0772c3..fa3f900c1 100644 --- a/integration-tests/chopsticks/src/network/polkadot/index.ts +++ b/integration-tests/chopsticks/src/network/polkadot/index.ts @@ -3,11 +3,28 @@ import * as PolkadotConfig from './relay.js' import * as HydraDxConfig from './hydraDx.js' import { ChainConfigs } from '../types.js' -const BLOCK_NUMBER_SPIRITNET = 5_000_000 -const BLOCK_NUMBER_HYDRADX_POLKADOT = 4_000_000 +function getEnvVariable(name: string): number { + const value = process.env[name] + if (value === undefined) { + throw new Error(`Environment variable ${name} is not set.`) + } + return Number(value) +} -export const chainConfigs: ChainConfigs = { - spiritnet: { config: SpiritnetConfig.getSetupOptions, blockNumber: BLOCK_NUMBER_SPIRITNET, name: 'spiritnet' }, - hydraDx: { config: HydraDxConfig.getSetupOptions, blockNumber: BLOCK_NUMBER_HYDRADX_POLKADOT, name: 'hydradx' }, - polkadot: { config: PolkadotConfig.getSetupOptions, blockNumber: BLOCK_NUMBER_HYDRADX_POLKADOT, name: 'polkadot' }, +export const all: ChainConfigs = { + spiritnet: { + config: SpiritnetConfig.getSetupOptions, + blockNumber: getEnvVariable('SPIRITNET_BLOCK_NUMBER'), + name: 'spiritnet', + }, + hydraDx: { + config: HydraDxConfig.getSetupOptions, + blockNumber: getEnvVariable('HYDRADX_BLOCK_NUMBER'), + name: 'hydradx', + }, + polkadot: { + config: PolkadotConfig.getSetupOptions, + blockNumber: getEnvVariable('POLKADOT_BLOCK_NUMBER'), + name: 'polkadot', + }, } diff --git a/integration-tests/chopsticks/src/network/polkadot/relay.ts b/integration-tests/chopsticks/src/network/polkadot/relay.ts index e7fc1ecb1..4f5ddb51c 100644 --- a/integration-tests/chopsticks/src/network/polkadot/relay.ts +++ b/integration-tests/chopsticks/src/network/polkadot/relay.ts @@ -3,7 +3,10 @@ import type { SetupOption } from '@acala-network/chopsticks-testing' import { initialBalanceDOT, toNumber } from '../../helper/utils.js' /// Options used to create the HydraDx context -export const getSetupOptions = (blockNumber: number | undefined = undefined) => +export const getSetupOptions = ( + blockNumber: number | undefined = undefined, + wasmOverride: string | undefined = undefined +) => ({ endpoint: process.env.POLKADOT_WS || [ 'wss://rpc.polkadot.io', @@ -13,6 +16,7 @@ export const getSetupOptions = (blockNumber: number | undefined = undefined) => db: './db/polkadot.db.sqlite', port: toNumber(process.env.POLKADOT_PORT) || 9000, blockNumber, + wasmOverride, }) as SetupOption /// Assigns the native tokens to an accounts diff --git a/integration-tests/chopsticks/src/network/polkadot/spiritnet.ts b/integration-tests/chopsticks/src/network/polkadot/spiritnet.ts index ce729640d..cdf78a5ed 100644 --- a/integration-tests/chopsticks/src/network/polkadot/spiritnet.ts +++ b/integration-tests/chopsticks/src/network/polkadot/spiritnet.ts @@ -3,11 +3,15 @@ import { SetupOption } from '@acala-network/chopsticks-testing' import { initialBalanceKILT, toNumber } from '../../helper/utils.js' /// Options used to create the Spiritnet context -export const getSetupOptions = (blockNumber: number | undefined = undefined) => +export const getSetupOptions = ( + blockNumber: number | undefined = undefined, + wasmOverride: string | undefined = undefined +) => ({ endpoint: process.env.SPIRITNET_WS || 'wss://kilt-rpc.dwellir.com', db: './db/spiritnet.db.sqlite', port: toNumber(process.env.SPIRITNET_PORT) || 9002, + wasmOverride, blockNumber, }) as SetupOption diff --git a/integration-tests/chopsticks/src/network/types.ts b/integration-tests/chopsticks/src/network/types.ts index d1b291c4e..776d604f5 100644 --- a/integration-tests/chopsticks/src/network/types.ts +++ b/integration-tests/chopsticks/src/network/types.ts @@ -3,8 +3,9 @@ import type { SetupOption, setupContext } from '@acala-network/chopsticks-testin export type Config = Awaited> export interface Chain { - config: (blockNumber?: number | undefined) => SetupOption - blockNumber: number + config: (blockNumber?: number, wasmOverride?: string) => SetupOption + blockNumber?: number + wasmOverride?: string name: string } diff --git a/integration-tests/chopsticks/src/tests/index.ts b/integration-tests/chopsticks/src/tests/index.ts index 14e40726c..23371f6ad 100644 --- a/integration-tests/chopsticks/src/tests/index.ts +++ b/integration-tests/chopsticks/src/tests/index.ts @@ -29,6 +29,7 @@ export async function shutDownNetwork(chains: Config[]) { } export async function setupNetwork(relayChain: SetupOption, sender: SetupOption, receiver: SetupOption) { + await setTimeout(50) const relayChainContext = await setupContext(relayChain) const senderChainContext = await setupContext(sender) const receiverChainContext = await setupContext(receiver) diff --git a/integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/__snapshots__/index.test.ts.snap b/integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/__snapshots__/index.test.ts.snap new file mode 100644 index 000000000..c9e2fce8e --- /dev/null +++ b/integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/__snapshots__/index.test.ts.snap @@ -0,0 +1,161 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Limited Reserve Transfers > Kilt -> HydraDx at block > receiver events "currencies" 1`] = ` +[ + { + "data": { + "amount": "(rounded 1000000000000000)", + "currencyId": 28, + "who": "7MZG43idRmdg8VSt5BS9mVJeBhhxxt5y55hCsMpoKp5xFQX2", + }, + "method": "Deposited", + "section": "currencies", + }, + { + "data": { + "amount": "(rounded 4100000000000)", + "currencyId": 28, + "who": "7L53bUTBopuwFt3mKUfmkzgGLayYa1Yvn1hAg9v5UMrQzTfh", + }, + "method": "Deposited", + "section": "currencies", + }, +] +`; + +exports[`Limited Reserve Transfers > Kilt -> HydraDx at block > receiver events "tokens" 1`] = ` +[ + { + "data": { + "amount": "(rounded 1000000000000000)", + "currencyId": 28, + "who": "7MZG43idRmdg8VSt5BS9mVJeBhhxxt5y55hCsMpoKp5xFQX2", + }, + "method": "Endowed", + "section": "tokens", + }, + { + "data": { + "amount": "(rounded 1000000000000000)", + "currencyId": 28, + "who": "7MZG43idRmdg8VSt5BS9mVJeBhhxxt5y55hCsMpoKp5xFQX2", + }, + "method": "Deposited", + "section": "tokens", + }, + { + "data": { + "amount": "(rounded 4100000000000)", + "currencyId": 28, + "who": "7L53bUTBopuwFt3mKUfmkzgGLayYa1Yvn1hAg9v5UMrQzTfh", + }, + "method": "Deposited", + "section": "tokens", + }, +] +`; + +exports[`Limited Reserve Transfers > Kilt -> HydraDx at block > receiver events "xcmpQueue" 1`] = ` +[ + { + "data": { + "messageHash": "(hash)", + "messageId": "(hash)", + "weight": { + "proofSize": 0, + "refTime": 400000000, + }, + }, + "method": "Success", + "section": "xcmpQueue", + }, +] +`; + +exports[`Limited Reserve Transfers > Kilt -> HydraDx at block > sender events "polkadotXcm" 1`] = ` +[ + { + "data": { + "outcome": { + "Complete": { + "proofSize": 0, + "refTime": 400000000, + }, + }, + }, + "method": "Attempted", + "section": "polkadotXcm", + }, +] +`; + +exports[`Limited Reserve Transfers > Kilt -> HydraDx at block > sender events "xcmpQueue" 1`] = ` +[ + { + "data": { + "messageHash": "(hash)", + }, + "method": "XcmpMessageSent", + "section": "xcmpQueue", + }, +] +`; + +exports[`Limited Reserve Transfers > Kilt -> HydraDx at block > sender events {"section":"balances","method":"Withdraw"} 1`] = ` +[ + { + "data": { + "amount": "(rounded 170000000000)", + "who": "4seWojfEHrk5YKPahdErazQ3CWEHZYi6NV4gKz5AaejWbRPJ", + }, + "method": "Withdraw", + "section": "balances", + }, +] +`; + +exports[`Limited Reserve Transfers > Kilt -> HydraDx live status > receiver events "xcmpQueue" 1`] = ` +[ + { + "data": { + "messageHash": "(hash)", + "messageId": "(hash)", + "weight": { + "proofSize": 0, + "refTime": 400000000, + }, + }, + "method": "Success", + "section": "xcmpQueue", + }, +] +`; + +exports[`Limited Reserve Transfers > Kilt -> HydraDx live status > sender events "polkadotXcm" 1`] = ` +[ + { + "data": { + "outcome": { + "Complete": { + "proofSize": 0, + "refTime": 400000000, + }, + }, + }, + "method": "Attempted", + "section": "polkadotXcm", + }, +] +`; + +exports[`Limited Reserve Transfers > Kilt -> HydraDx live status > sender events "xcmpQueue" 1`] = ` +[ + { + "data": { + "messageHash": "(hash)", + }, + "method": "XcmpMessageSent", + "section": "xcmpQueue", + }, +] +`; diff --git a/integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/__snapshots__/transfers.test.ts.snap b/integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/__snapshots__/transfers.test.ts.snap deleted file mode 100644 index 69a91d813..000000000 --- a/integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/__snapshots__/transfers.test.ts.snap +++ /dev/null @@ -1,30 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`Limited Reserve Transfers > with latest block > from spiritnet Account -> hydradx Account > sender events polkadotXcm 1`] = ` -[ - { - "data": { - "outcome": { - "Complete": { - "proofSize": 0, - "refTime": 400000000, - }, - }, - }, - "method": "Attempted", - "section": "polkadotXcm", - }, -] -`; - -exports[`Limited Reserve Transfers > with latest block > from spiritnet Account -> hydradx Account > sender events xcmpQueue 1`] = ` -[ - { - "data": { - "messageHash": "(hash)", - }, - "method": "XcmpMessageSent", - "section": "xcmpQueue", - }, -] -`; diff --git a/integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/config.ts b/integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/config.ts new file mode 100644 index 000000000..a39f702e5 --- /dev/null +++ b/integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/config.ts @@ -0,0 +1,207 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import type { KeyringPair } from '@polkadot/keyring/types' + +import * as PolkadotChainConfigs from '../../../network/polkadot/index.js' +import { initialBalanceHDX, initialBalanceKILT, keysAlice, keysBob } from '../../../helper/utils.js' +import * as SpiritnetConfig from '../../../network/polkadot/spiritnet.js' +import * as HydraDxConfig from '../../../network/polkadot/hydraDx.js' +import { tx, query } from '../../../helper/api.js' +import { ApiPromise } from '@polkadot/api' +import { SubmittableExtrinsic } from '@polkadot/api/types' +import { EventFilter, SetupOption } from '@acala-network/chopsticks-testing' + +interface LimitedReserveTestConfiguration { + config: { + desc: string + precision: bigint + } + + blockchain: { + sender: SetupOption + receiver: SetupOption + relay: SetupOption + } + + query: { + sender: ( + { + api, + }: { + api: ApiPromise + }, + address: string + ) => Promise + receiver: ( + { + api, + }: { + api: ApiPromise + }, + address: string + ) => Promise + } + + test: { + tx: ( + { + api, + }: { + api: ApiPromise + }, + acc: string, + amount: number | string + ) => SubmittableExtrinsic<'promise'> + + pallets: { + sender: EventFilter[] + receiver: EventFilter[] + } + + balanceToTransfer: bigint + } + accounts: { + senderAccount: KeyringPair + receiverAccount: KeyringPair + } + storage: { + senderStorage: Record> + receiverStorage: Record> + relayStorage: Record> + } + + sovereignAccount: { + sender: string + receiver: string + } +} + +// Test pairs for limited reserve transfers +export const testPairsLimitedReserveTransfers: LimitedReserveTestConfiguration[] = [ + // Kilt -> HydraDx + { + config: { + desc: 'Kilt -> HydraDx live status', + precision: BigInt(95), + }, + + blockchain: { + sender: PolkadotChainConfigs.all.spiritnet.config(), + receiver: PolkadotChainConfigs.all.hydraDx.config(), + relay: PolkadotChainConfigs.all.polkadot.config(), + }, + accounts: { + senderAccount: keysAlice, + receiverAccount: keysBob, + }, + query: { + sender: query.balances, + receiver: query.tokens(HydraDxConfig.kiltTokenId), + }, + test: { + tx: tx.xcmPallet.limitedReserveTransferAssetsV2( + SpiritnetConfig.KILT, + tx.xcmPallet.parachainV2(1, HydraDxConfig.paraId) + ), + pallets: { + sender: ['xcmpQueue', 'polkadotXcm'], + receiver: ['xcmpQueue'], + }, + balanceToTransfer: BigInt(1e15), + }, + storage: { + senderStorage: SpiritnetConfig.assignNativeTokensToAccounts([keysAlice.address], initialBalanceKILT), + receiverStorage: {}, + relayStorage: {}, + }, + sovereignAccount: { + sender: SpiritnetConfig.hydraDxSovereignAccount, + receiver: SpiritnetConfig.hydraDxSovereignAccount, + }, + }, + + { + config: { + desc: 'Kilt -> HydraDx at block', + precision: BigInt(100), + }, + + blockchain: { + sender: PolkadotChainConfigs.all.spiritnet.config(PolkadotChainConfigs.all.spiritnet.blockNumber), + receiver: PolkadotChainConfigs.all.hydraDx.config(PolkadotChainConfigs.all.hydraDx.blockNumber), + relay: PolkadotChainConfigs.all.polkadot.config(PolkadotChainConfigs.all.polkadot.blockNumber), + }, + accounts: { + senderAccount: keysAlice, + receiverAccount: keysBob, + }, + query: { + sender: query.balances, + receiver: query.tokens(HydraDxConfig.kiltTokenId), + }, + test: { + tx: tx.xcmPallet.limitedReserveTransferAssetsV2( + SpiritnetConfig.KILT, + tx.xcmPallet.parachainV2(1, HydraDxConfig.paraId) + ), + pallets: { + sender: ['xcmpQueue', 'polkadotXcm', { section: 'balances', method: 'Withdraw' }], + receiver: ['xcmpQueue', 'tokens', 'currencies'], + }, + balanceToTransfer: BigInt(1e15), + }, + storage: { + senderStorage: SpiritnetConfig.assignNativeTokensToAccounts([keysAlice.address], initialBalanceKILT), + receiverStorage: {}, + relayStorage: {}, + }, + sovereignAccount: { + sender: SpiritnetConfig.hydraDxSovereignAccount, + receiver: SpiritnetConfig.hydraDxSovereignAccount, + }, + }, + + // HydraDx -> Kilt + { + config: { + desc: 'HydraDx -> KILT at live', + precision: BigInt(95), + }, + + blockchain: { + sender: PolkadotChainConfigs.all.spiritnet.config(), + receiver: PolkadotChainConfigs.all.hydraDx.config(), + relay: PolkadotChainConfigs.all.polkadot.config(), + }, + accounts: { + senderAccount: keysAlice, + receiverAccount: keysBob, + }, + query: { + sender: query.tokens(HydraDxConfig.kiltTokenId), + receiver: query.balances, + }, + test: { + tx: tx.xtokens.transfer(HydraDxConfig.KILTLocation, tx.xtokens.parachainV3(SpiritnetConfig.paraId)), + pallets: { + sender: [], + receiver: [], + }, + balanceToTransfer: BigInt(1e15), + }, + storage: { + senderStorage: { + ...HydraDxConfig.assignNativeTokensToAccounts([keysAlice.address], initialBalanceHDX), + ...HydraDxConfig.assignKiltTokensToAccounts([keysAlice.address], initialBalanceKILT), + }, + receiverStorage: {}, + relayStorage: {}, + }, + sovereignAccount: { + sender: SpiritnetConfig.hydraDxSovereignAccount, + receiver: SpiritnetConfig.hydraDxSovereignAccount, + }, + }, +] as const + +export type TestType = (typeof testPairsLimitedReserveTransfers)[number] diff --git a/integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/index.test.ts b/integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/index.test.ts new file mode 100644 index 000000000..1a590b57d --- /dev/null +++ b/integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/index.test.ts @@ -0,0 +1,120 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { describe, beforeEach, it, afterEach, ExpectStatic } from 'vitest' +import { sendTransaction, withExpect } from '@acala-network/chopsticks-testing' + +import { createBlock, hexAddress, setStorage } from '../../utils.js' + +import { testPairsLimitedReserveTransfers } from './config.js' +import { Config } from '../../../network/types.js' +import { setupNetwork, shutDownNetwork } from '../../index.js' +import type { KeyringPair } from '@polkadot/keyring/types' + +describe.each(testPairsLimitedReserveTransfers)( + 'Limited Reserve Transfers', + { sequential: true, timeout: 30_000 }, + async ({ blockchain, storage, accounts, query, sovereignAccount, test, config }) => { + let senderContext: Config + let receiverContext: Config + let relayContext: Config + let senderAccount: KeyringPair + let receiverAccount: KeyringPair + const { desc, precision } = config + + beforeEach(async () => { + const { receiver, sender, relay } = blockchain + + const { receiverChainContext, senderChainContext, relayChainContext } = await setupNetwork( + relay, + sender, + receiver + ) + + relayContext = relayChainContext + senderContext = senderChainContext + receiverContext = receiverChainContext + + const { receiverStorage, senderStorage, relayStorage } = storage + await setStorage(senderContext, senderStorage) + await setStorage(receiverContext, receiverStorage) + await setStorage(relayContext, relayStorage) + + const { senderAccount: a, receiverAccount: b } = accounts + senderAccount = a + receiverAccount = b + }, 20_000) + + afterEach(async () => { + try { + await shutDownNetwork([senderContext, receiverContext, relayContext]) + } catch (error) { + console.error(error) + } + }) + + it(desc, { timeout: 10_000, retry: 3 }, async ({ expect }) => { + const { checkEvents, checkSystemEvents } = withExpect(expect) + + // test parameters + const { pallets, tx, balanceToTransfer } = test + + // Balance of the receiver sovereign account before the transfer + const receiverSovereignAccountBalanceBeforeTransfer = await query.sender( + senderContext, + sovereignAccount.sender + ) + + const initialBalanceReceiver = await query.receiver(receiverContext, receiverAccount.address) + + // Check initial balance receiver should be zero + expect(initialBalanceReceiver).toBe(BigInt(0)) + + const signedTx = tx( + senderContext, + hexAddress(receiverAccount.address), + balanceToTransfer.toString() + ).signAsync(senderAccount) + + const events = await sendTransaction(signedTx) + + // check sender state + await createBlock(senderContext) + + pallets.sender.map((pallet) => + checkEvents(events, pallet).toMatchSnapshot(`sender events ${JSON.stringify(pallet)}`) + ) + + const balanceSenderAfterTransfer = await query.sender(senderContext, senderAccount.address) + const receiverSovereignAccountBalanceAfterTransfer = await query.sender( + senderContext, + sovereignAccount.sender + ) + expect(receiverSovereignAccountBalanceAfterTransfer).toBe( + receiverSovereignAccountBalanceBeforeTransfer + BigInt(balanceToTransfer) + ) + + checkBalanceInRange(balanceSenderAfterTransfer, expect, precision) + + // check receiver state + await createBlock(receiverContext) + + pallets.receiver.map((pallet) => + checkSystemEvents(receiverContext, pallet).toMatchSnapshot(`receiver events ${JSON.stringify(pallet)}`) + ) + + const balanceReceiverAfterTransfer = await query.receiver(receiverContext, receiverAccount.address) + + checkBalanceInRange(balanceReceiverAfterTransfer, expect, precision) + }) + } +) + +// Check Balance is in range +function checkBalanceInRange(receivedBalance: bigint, expect: ExpectStatic, precision: bigint) { + if (precision < BigInt(0) || precision > BigInt(100)) { + throw new Error('Precision must be between 0 and 100') + } + + const lowerBound = (receivedBalance * precision) / BigInt(100) + expect(receivedBalance).toBeLessThanOrEqual(receivedBalance) + expect(receivedBalance).toBeGreaterThanOrEqual(lowerBound) +} diff --git a/integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/index.ts b/integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/index.ts deleted file mode 100644 index e40622f99..000000000 --- a/integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/index.ts +++ /dev/null @@ -1,124 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -import type { KeyringPair } from '@polkadot/keyring/types' - -import * as PolkadotChainConfigs from '../../../network/polkadot/index.js' -import { initialBalanceKILT, keysAlice, keysBob } from '../../../helper/utils.js' -import * as SpiritnetConfig from '../../../network/polkadot/spiritnet.js' -import * as HydraDxConfig from '../../../network/polkadot/hydraDx.js' -import { tx, query } from '../../../helper/api.js' -import { ApiPromise } from '@polkadot/api' -import { SubmittableExtrinsic } from '@polkadot/api/types' -import { Chain } from '../../../network/types.js' -import { EventFilter } from '@acala-network/chopsticks-testing' - -interface LimitedReserveTestConfiguration { - blockchain: { - sender: Chain - receiver: Chain - relay: Chain - } - - query: { - sender: ( - { - api, - }: { - api: ApiPromise - }, - address: string - ) => Promise - receiver: ( - { - api, - }: { - api: ApiPromise - }, - address: string - ) => Promise - } - - test: { - tx: ( - { - api, - }: { - api: ApiPromise - }, - acc: string, - amount: number - ) => SubmittableExtrinsic<'promise'> - - pallets: { - sender: { - live: EventFilter[] - block: EventFilter[] - } - receiver: { - live: EventFilter[] - block: EventFilter[] - } - } - } - accounts: { - senderAccount: KeyringPair - receiverAccount: KeyringPair - } - storage: { - senderStorage: Record> - receiverStorage: Record> - relayStorage: Record> - } - - sovereignAccount: { - sender: string - receiver: string - } -} - -// Test pairs for limited reserve transfers -export const testPairsLimitedReserveTransfers: LimitedReserveTestConfiguration[] = [ - // Kilt -> HydraDx - { - blockchain: { - sender: PolkadotChainConfigs.chainConfigs.spiritnet, - receiver: PolkadotChainConfigs.chainConfigs.hydraDx, - relay: PolkadotChainConfigs.chainConfigs.polkadot, - }, - accounts: { - senderAccount: keysAlice, - receiverAccount: keysBob, - }, - query: { - sender: query.balances, - receiver: query.tokens(HydraDxConfig.kiltTokenId), - }, - test: { - tx: tx.xcmPallet.limitedReserveTransferAssetsV2( - SpiritnetConfig.KILT, - tx.xcmPallet.parachainV2(1, HydraDxConfig.paraId) - ), - pallets: { - sender: { - live: ['xcmpQueue', 'polkadotXcm'], - block: ['xcmpQueue', 'polkadotXcm'], - }, - receiver: { - live: [], - block: [], - }, - }, - }, - storage: { - senderStorage: SpiritnetConfig.assignNativeTokensToAccounts([keysAlice.address], initialBalanceKILT), - receiverStorage: {}, - relayStorage: {}, - }, - sovereignAccount: { - sender: SpiritnetConfig.hydraDxSovereignAccount, - receiver: SpiritnetConfig.hydraDxSovereignAccount, - }, - }, -] as const - -export type TestType = (typeof testPairsLimitedReserveTransfers)[number] diff --git a/integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/transfers.test.ts b/integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/transfers.test.ts deleted file mode 100644 index f699c15f2..000000000 --- a/integration-tests/chopsticks/src/tests/xcm/limitedReserveTransfer/transfers.test.ts +++ /dev/null @@ -1,140 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { describe, beforeEach, it, afterEach } from 'vitest' -import { sendTransaction, withExpect } from '@acala-network/chopsticks-testing' - -import { createBlock, hexAddress, setStorage } from '../../utils.js' - -import { testPairsLimitedReserveTransfers } from './index.js' -import { Config } from '../../../network/types.js' -import { setupNetwork, shutDownNetwork } from '../../index.js' -import type { KeyringPair } from '@polkadot/keyring/types' - -describe.each(testPairsLimitedReserveTransfers)( - 'Limited Reserve Transfers', - async ({ blockchain, storage, accounts, query, sovereignAccount, test }) => { - describe('with latest block', async () => { - let senderContext: Config - let receiverContext: Config - let relayContext: Config - let senderAccount: KeyringPair - let receiverAccount: KeyringPair - - beforeEach(async () => { - const { receiver, sender, relay } = blockchain - const senderOptions = sender.config(undefined) - const targetOptions = receiver.config(undefined) - const relayOptions = relay.config(undefined) - - const { receiverChainContext, senderChainContext, relayChainContext } = await setupNetwork( - relayOptions, - senderOptions, - targetOptions - ) - relayContext = relayChainContext - senderContext = senderChainContext - receiverContext = receiverChainContext - - const { receiverStorage, senderStorage, relayStorage } = storage - await setStorage(senderContext, senderStorage) - await setStorage(receiverContext, receiverStorage) - await setStorage(relayContext, relayStorage) - - const { senderAccount: a, receiverAccount: b } = accounts - senderAccount = a - receiverAccount = b - }, 20_000) - - afterEach(async () => { - shutDownNetwork([senderContext, receiverContext, relayContext]) - }) - - it( - `from ${blockchain.sender.name} Account -> ${blockchain.receiver.name} Account`, - async ({ expect }) => { - const { checkEvents } = withExpect(expect) - - const { pallets, tx } = test - - // Balance of the receiver sovereign account before the transfer - const receiverSovereignAccountBalanceBeforeTransfer = await query.receiver( - receiverContext, - sovereignAccount.receiver - ) - - const initialBalanceSender = await query.sender(senderContext, senderAccount.address) - - const initialBalanceReceiver = await query.receiver(receiverContext, receiverAccount.address) - - // Check initial balance receiver should be zero - expect(initialBalanceReceiver).toBe(BigInt(0)) - - const signedTx = tx(senderContext, hexAddress(receiverAccount.address), 1e12).signAsync( - senderAccount - ) - - const events = await sendTransaction(signedTx) - - await createBlock(senderContext) - - pallets.sender.map((pallet) => - checkEvents(events, pallet).toMatchSnapshot(`sender events ${pallet}`) - ) - - expect( - (await checkEvents(events, { section: 'balances', method: 'Withdraw' }).value()).length - ).toBe(1) - - const balanceSenderAfterTransfer = await query.sender(senderContext, senderAccount.address) - const balanceReceiverAfterTransfer = await query.receiver(receiverContext, receiverAccount.address) - const receiverSovereignAccountBalanceAfterTransfer = await query.receiver( - receiverContext, - sovereignAccount.receiver - ) - - expect(receiverSovereignAccountBalanceAfterTransfer).toBe( - receiverSovereignAccountBalanceBeforeTransfer + BigInt(1e12) - ) - - expect(balanceSenderAfterTransfer).toBe(initialBalanceSender - BigInt(1e12)) - - expect(balanceReceiverAfterTransfer).toBe(BigInt(1e12)) - }, - { timeout: 10_000 } - ) - }) - } -) - -//const KILT_ASSET_V2 = { V2: [getNativeAssetIdLocation(KILT)] } -// test('Limited Reserve V2 Transfers from Spiritnet Account Alice -> HydraDx Account Alice', async ({ expect }) => { - -// await checkBalance( -// getFreeBalanceSpiritnet, -// SpiritnetConfig.hydraDxSovereignAccount, -// expect, -// hydraDxSovereignAccountBalanceBeforeTransfer + KILT -// ) - -// // check balance sender -// // Equal to `initialBalanceKILT - KILT` - tx fees -// await checkBalanceInRange(getFreeBalanceSpiritnet, keysAlice.address, expect, [ -// BigInt('98999830999996320'), -// BigInt('98999830999996321'), -// ]) - -// // Check receiver state -// await createBlock(hydradxContext) - -// // Check events receiver -// checkSystemEvents(hydradxContext, { section: 'currencies', method: 'Deposited' }).toMatchSnapshot( -// 'receiver events currencies' -// ) -// checkSystemEvents(hydradxContext, 'xcmpQueue').toMatchSnapshot('receiver events xcmpQueue') - -// // check balance receiver -// // check balance. Equal to `KILT` - tx fees -// await checkBalanceInRange(getFreeBalanceHydraDxKilt, aliceAddress, expect, [ -// BigInt(996349465529793), -// BigInt(996349465529796), -// ]) -// }, 20_000) diff --git a/integration-tests/chopsticks/src/tests/xcm/limitedReserveTransferSpiritnetHydraDxV3.test.ts b/integration-tests/chopsticks/src/tests/xcm/limitedReserveTransferSpiritnetHydraDxV3.ts similarity index 100% rename from integration-tests/chopsticks/src/tests/xcm/limitedReserveTransferSpiritnetHydraDxV3.test.ts rename to integration-tests/chopsticks/src/tests/xcm/limitedReserveTransferSpiritnetHydraDxV3.ts diff --git a/integration-tests/chopsticks/src/tests/xcm/limitedReseveTransferHydraDxSpiritnet.test.ts b/integration-tests/chopsticks/src/tests/xcm/limitedReseveTransferHydraDxSpiritnet..ts similarity index 100% rename from integration-tests/chopsticks/src/tests/xcm/limitedReseveTransferHydraDxSpiritnet.test.ts rename to integration-tests/chopsticks/src/tests/xcm/limitedReseveTransferHydraDxSpiritnet..ts