From 7057ccb99cacc18ad817c792e8c6479c928f1bed Mon Sep 17 00:00:00 2001 From: Juan Ignacio Rios Date: Wed, 4 Dec 2024 12:52:22 +0100 Subject: [PATCH] WETH integration test --- integration-tests/chopsticks/README.md | 4 + integration-tests/chopsticks/bun.lockb | Bin .../chopsticks/overrides/polimec.ts | 8 +- .../chopsticks/overrides/polkadot-hub.ts | 13 +- .../chopsticks/src/managers/BaseManager.ts | 35 +++- .../chopsticks/src/managers/PolimecManager.ts | 32 +++- .../src/managers/PolkadotHubManager.ts | 32 +++- .../src/managers/PolkadotManager.ts | 25 ++- integration-tests/chopsticks/src/setup.ts | 1 + .../chopsticks/src/tests/hub.test.ts | 64 ++++--- .../chopsticks/src/tests/polimec.test.ts | 53 ++++-- .../chopsticks/src/tests/polkadot.test.ts | 18 +- .../chopsticks/src/transfers/HubToPolimec.ts | 35 ++-- .../chopsticks/src/transfers/PolimecToHub.ts | 26 +-- .../src/transfers/PolkadotToPolimec.ts | 16 +- integration-tests/chopsticks/src/types.ts | 165 +++++++++++++++--- integration-tests/chopsticks/src/utils.ts | 70 +------- 17 files changed, 387 insertions(+), 210 deletions(-) mode change 100644 => 100755 integration-tests/chopsticks/bun.lockb diff --git a/integration-tests/chopsticks/README.md b/integration-tests/chopsticks/README.md index 0ec45cfb1..8f0d3d2ab 100644 --- a/integration-tests/chopsticks/README.md +++ b/integration-tests/chopsticks/README.md @@ -6,6 +6,10 @@ To install dependencies: bun install ``` +```bash +bun papi +``` + To start the chains: ```bash diff --git a/integration-tests/chopsticks/bun.lockb b/integration-tests/chopsticks/bun.lockb old mode 100644 new mode 100755 diff --git a/integration-tests/chopsticks/overrides/polimec.ts b/integration-tests/chopsticks/overrides/polimec.ts index 686ea3260..5c802dee6 100644 --- a/integration-tests/chopsticks/overrides/polimec.ts +++ b/integration-tests/chopsticks/overrides/polimec.ts @@ -1,5 +1,5 @@ import { INITIAL_BALANCES } from '@/constants'; -import { Accounts, Assets } from '@/types'; +import { Accounts, Asset } from '@/types'; export const POLIMEC_WASM = '../../target/release/wbuild/polimec-runtime/polimec_runtime.compact.compressed.wasm'; @@ -21,19 +21,19 @@ export const polimec_storage = { ForeignAssets: { Account: [ [ - [Assets.USDC, Accounts.BOB], + [Asset.USDC, Accounts.BOB], { balance: INITIAL_BALANCES.USDC, }, ], [ - [Assets.USDT, Accounts.BOB], + [Asset.USDT, Accounts.BOB], { balance: INITIAL_BALANCES.USDT, }, ], [ - [Assets.DOT, Accounts.BOB], + [Asset.DOT, Accounts.BOB], { balance: INITIAL_BALANCES.DOT, }, diff --git a/integration-tests/chopsticks/overrides/polkadot-hub.ts b/integration-tests/chopsticks/overrides/polkadot-hub.ts index 9fb9a8a41..433ea064f 100644 --- a/integration-tests/chopsticks/overrides/polkadot-hub.ts +++ b/integration-tests/chopsticks/overrides/polkadot-hub.ts @@ -1,5 +1,5 @@ import { INITIAL_BALANCES } from '@/constants'; -import { Accounts, Assets } from '@/types'; +import { Accounts, Asset } from '@/types'; export const polkadot_hub_storage = { System: { @@ -18,24 +18,17 @@ export const polkadot_hub_storage = { Assets: { Account: [ [ - [Assets.USDT, Accounts.ALICE], + [Asset.USDT, Accounts.ALICE], { balance: INITIAL_BALANCES.USDT, }, ], [ - [Assets.USDC, Accounts.ALICE], + [Asset.USDC, Accounts.ALICE], { balance: INITIAL_BALANCES.USDC, }, ], - [ - [Assets.UNKNOWN, Accounts.ALICE], - { - balance: INITIAL_BALANCES.USDT, - }, - ], ], }, - // TODO: Add the foreignAssets storage to give to ALICE WETH = INITIAL_BALANCES.WETH } as const; diff --git a/integration-tests/chopsticks/src/managers/BaseManager.ts b/integration-tests/chopsticks/src/managers/BaseManager.ts index 81a4a7669..08e4fcc42 100644 --- a/integration-tests/chopsticks/src/managers/BaseManager.ts +++ b/integration-tests/chopsticks/src/managers/BaseManager.ts @@ -1,5 +1,13 @@ import { DERIVE_PATHS } from '@/constants'; -import type { Accounts, ChainClient, ChainToDefinition, Chains } from '@/types'; +import { + type Accounts, + type Asset, + AssetLocation, + type AssetSourceRelation, + type ChainClient, + type ChainToDefinition, + Chains, +} from '@/types'; import { sr25519CreateDerive } from '@polkadot-labs/hdkd'; import { DEV_PHRASE, entropyToMiniSecret, mnemonicToEntropy } from '@polkadot-labs/hdkd-helpers'; import type { PolkadotSigner, TypedApi } from 'polkadot-api'; @@ -67,10 +75,25 @@ export abstract class BaseChainManager { return events[0]?.payload.actual_fee || 0n; } - async getNativeBalanceOf(account: Accounts) { - const api = this.getApi(this.getChainType()); - const balance = await api.query.System.Account.getValue(account); - return balance.data.free; + // Make sure to override this in the other managers + abstract getAssetSourceRelation(asset: Asset): AssetSourceRelation | undefined; + + async getAssetBalanceOf(account: Accounts, asset: Asset): Promise { + const chain = this.getChainType(); + const api = this.getApi(chain); + const asset_source_relation = this.getAssetSourceRelation(asset); + const asset_location = AssetLocation(asset, asset_source_relation); + const account_balances_result = await api.apis.FungiblesApi.query_account_balances(account); + + if (account_balances_result.success === true && account_balances_result.value.type === 'V4') { + const assets = account_balances_result.value.value; + for (const asset of assets) { + if (asset.id === asset_location && asset.fun.type === 'Fungible') { + return asset.fun.value; + } + } + } + return 0n; } // @ts-expect-error - TODO: Not sure which is the correct type for this @@ -78,8 +101,6 @@ export abstract class BaseChainManager { abstract getChainType(): Chains; - abstract getAssetBalanceOf(account: Accounts, asset: number): Promise; - abstract connect(): void; abstract disconnect(): void; diff --git a/integration-tests/chopsticks/src/managers/PolimecManager.ts b/integration-tests/chopsticks/src/managers/PolimecManager.ts index 303c86939..49078b46f 100644 --- a/integration-tests/chopsticks/src/managers/PolimecManager.ts +++ b/integration-tests/chopsticks/src/managers/PolimecManager.ts @@ -1,4 +1,4 @@ -import { type Accounts, type Assets, Chains } from '@/types'; +import { type Accounts, Asset, AssetLocation, AssetSourceRelation, Chains } from '@/types'; import { polimec } from '@polkadot-api/descriptors'; import { createClient } from 'polkadot-api'; import { getWsProvider } from 'polkadot-api/ws-provider/web'; @@ -34,10 +34,34 @@ export class PolimecManager extends BaseChainManager { return '58kXueYKLr5b8yCeY3Gd1nLQX2zSJLXjfMzTAuksNq25CFEL' as Accounts; } - async getAssetBalanceOf(account: Accounts, asset: Assets) { + getAssetSourceRelation(asset: Asset): AssetSourceRelation | undefined { + switch (asset) { + case Asset.DOT: + return AssetSourceRelation.Parent; + case Asset.USDT: + return AssetSourceRelation.Sibling; + case Asset.USDC: + return AssetSourceRelation.Sibling; + case Asset.WETH: + return undefined; + } + } + + async getAssetBalanceOf(account: Accounts, asset: Asset): Promise { const api = this.getApi(Chains.Polimec); - const balance = await api.query.ForeignAssets.Account.getValue(asset, account); - return balance?.balance || 0n; + const asset_source_relation = this.getAssetSourceRelation(asset); + const asset_location = AssetLocation(asset, asset_source_relation); + const account_balances_result = await api.apis.FungiblesApi.query_account_balances(account); + + if (account_balances_result.success === true && account_balances_result.value.type === 'V4') { + const assets = account_balances_result.value.value; + for (const asset of assets) { + if (asset.id === asset_location && asset.fun.type === 'Fungible') { + return asset.fun.value; + } + } + } + return 0n; } async getXcmFee() { diff --git a/integration-tests/chopsticks/src/managers/PolkadotHubManager.ts b/integration-tests/chopsticks/src/managers/PolkadotHubManager.ts index 1e889e2d8..29d7fb4ca 100644 --- a/integration-tests/chopsticks/src/managers/PolkadotHubManager.ts +++ b/integration-tests/chopsticks/src/managers/PolkadotHubManager.ts @@ -1,4 +1,4 @@ -import { type Accounts, type Assets, Chains } from '@/types'; +import { type Accounts, Asset, AssetLocation, AssetSourceRelation, Chains } from '@/types'; import { pah } from '@polkadot-api/descriptors'; import { createClient } from 'polkadot-api'; import { getWsProvider } from 'polkadot-api/ws-provider/web'; @@ -30,12 +30,34 @@ export class PolkadotHubManager extends BaseChainManager { return api.tx.PolkadotXcm; } - async getAssetBalanceOf(account: Accounts, asset: Assets) { - const api = this.getApi(Chains.PolkadotHub); - const balance = await api.query.Assets.Account.getValue(asset, account); - return balance?.balance || 0n; + getAssetSourceRelation(asset: Asset): AssetSourceRelation | undefined { + switch (asset) { + case Asset.DOT: + return AssetSourceRelation.Parent; + case Asset.USDT: + return AssetSourceRelation.Self; + case Asset.USDC: + return AssetSourceRelation.Self; + case Asset.WETH: + return undefined; + } } + async getAssetBalanceOf(account: Accounts, asset: Asset): Promise { + const api = this.getApi(Chains.PolkadotHub); + const asset_source_relation = this.getAssetSourceRelation(asset); + const asset_location = AssetLocation(asset, asset_source_relation); + const account_balances_result = await api.apis.FungiblesApi.query_account_balances(account); + if (account_balances_result.success === true && account_balances_result.value.type === 'V4') { + const assets = account_balances_result.value.value; + for (const asset of assets) { + if (asset.id === asset_location && asset.fun.type === 'Fungible') { + return asset.fun.value; + } + } + } + return 0n; + } async getSwapCredit() { const api = this.getApi(Chains.PolkadotHub); const events = await api.event.AssetConversion.SwapCreditExecuted.pull(); diff --git a/integration-tests/chopsticks/src/managers/PolkadotManager.ts b/integration-tests/chopsticks/src/managers/PolkadotManager.ts index 92beee323..4af7f6e15 100644 --- a/integration-tests/chopsticks/src/managers/PolkadotManager.ts +++ b/integration-tests/chopsticks/src/managers/PolkadotManager.ts @@ -1,4 +1,4 @@ -import { type Accounts, Chains } from '@/types'; +import { type Accounts, Asset, AssetSourceRelation, Chains } from '@/types'; import { polkadot } from '@polkadot-api/descriptors'; import { createClient } from 'polkadot-api'; import { getWsProvider } from 'polkadot-api/ws-provider/web'; @@ -30,8 +30,27 @@ export class PolkadotManager extends BaseChainManager { return api.tx.XcmPallet; } - async getAssetBalanceOf(_account: Accounts, _asset: number): Promise { - throw new Error('Polkadot does not support assets'); + getAssetSourceRelation(asset: Asset): AssetSourceRelation | undefined { + switch (asset) { + case Asset.DOT: + return AssetSourceRelation.Self; + case Asset.USDT: + return undefined; + case Asset.USDC: + return undefined; + case Asset.WETH: + return undefined; + } + } + + async getAssetBalanceOf(account: Accounts, asset: Asset): Promise { + const api = this.getApi(this.getChainType()); + if (asset === Asset.DOT) { + const balance = await api.query.System.Account.getValue(account); + return balance.data.free; + } else { + return 0n + } } async getXcmFee() { diff --git a/integration-tests/chopsticks/src/setup.ts b/integration-tests/chopsticks/src/setup.ts index 5f2119656..cb8170e11 100644 --- a/integration-tests/chopsticks/src/setup.ts +++ b/integration-tests/chopsticks/src/setup.ts @@ -80,6 +80,7 @@ export class ChainSetup { 'wasm-override': POLIMEC_WASM, 'import-storage': polimec_storage, 'build-block-mode': BuildBlockMode.Instant, + 'runtime-log-level': 3, }); } diff --git a/integration-tests/chopsticks/src/tests/hub.test.ts b/integration-tests/chopsticks/src/tests/hub.test.ts index 20b9de7b2..d519131ed 100644 --- a/integration-tests/chopsticks/src/tests/hub.test.ts +++ b/integration-tests/chopsticks/src/tests/hub.test.ts @@ -3,7 +3,7 @@ import { TRANSFER_AMOUNTS } from '@/constants'; import { createChainManager } from '@/managers/Factory'; import { ChainSetup } from '@/setup'; import { HubToPolimecTransfer } from '@/transfers/HubToPolimec'; -import { Accounts, Assets, Chains } from '@/types'; +import { Accounts, Asset, AssetSourceRelation, Chains } from '@/types'; describe('Polkadot Hub -> Polimec Transfer Tests', () => { const sourceManager = createChainManager(Chains.PolkadotHub); @@ -18,33 +18,43 @@ describe('Polkadot Hub -> Polimec Transfer Tests', () => { }); afterAll(async () => await chainSetup.cleanup()); - test('Send DOT to Polimec', () => - transferTest.testTransfer({ - amount: TRANSFER_AMOUNTS.NATIVE, - account: Accounts.ALICE, - asset: Assets.DOT, - })); - - test('Send USDt to Polimec', () => - transferTest.testTransfer({ - amount: TRANSFER_AMOUNTS.TOKENS, - account: Accounts.ALICE, - asset: Assets.USDT, - })); - - test('Send USDC to Polimec', () => - transferTest.testTransfer({ - amount: TRANSFER_AMOUNTS.TOKENS, - account: Accounts.ALICE, - asset: Assets.USDC, - })); - - test('Send Unknown Asset to Polimec', () => - expect(() => + test( + 'Send DOT to Polimec', + () => transferTest.testTransfer({ - amount: TRANSFER_AMOUNTS.TOKENS, + amount: TRANSFER_AMOUNTS.NATIVE, account: Accounts.ALICE, - asset: Assets.UNKNOWN, + asset: Asset.DOT, + assetSourceRelation: AssetSourceRelation.Parent, }), - ).toThrow()); + { timeout: 25000 }, + ); + // + // test('Send USDT to Polimec', () => + // transferTest.testTransfer({ + // amount: TRANSFER_AMOUNTS.TOKENS, + // account: Accounts.ALICE, + // asset: Asset.USDT, + // assetSourceRelation: AssetSourceRelation.Self, + // }), {timeout: 25000}); + // + // test('Send USDC to Polimec', () => + // transferTest.testTransfer({ + // amount: TRANSFER_AMOUNTS.TOKENS, + // account: Accounts.ALICE, + // asset: Asset.USDC, + // assetSourceRelation: AssetSourceRelation.Self, + // }), {timeout: 25000}); + + // test( + // 'Send WETH to Polimec', + // () => + // transferTest.testTransfer({ + // amount: TRANSFER_AMOUNTS.BRIDGED, + // account: Accounts.ALICE, + // asset: Asset.WETH, + // assetSourceRelation: undefined, + // }), + // { timeout: 25000 }, + // ); }); diff --git a/integration-tests/chopsticks/src/tests/polimec.test.ts b/integration-tests/chopsticks/src/tests/polimec.test.ts index 39e989d96..f0e9f5a5c 100644 --- a/integration-tests/chopsticks/src/tests/polimec.test.ts +++ b/integration-tests/chopsticks/src/tests/polimec.test.ts @@ -4,7 +4,7 @@ import { createChainManager } from '@/managers/Factory'; import { polimec_storage } from '@/polimec'; import { ChainSetup } from '@/setup'; import { PolimecToHubTransfer } from '@/transfers/PolimecToHub'; -import { Accounts, Assets, Chains } from '@/types'; +import { Accounts, Asset, AssetSourceRelation, Chains } from '@/types'; describe('Polimec -> Hub Transfer Tests', () => { const sourceManager = createChainManager(Chains.Polimec); @@ -19,24 +19,39 @@ describe('Polimec -> Hub Transfer Tests', () => { }); afterAll(async () => await chainSetup.cleanup()); - test('Send USDC to Hub', () => - transferTest.testTransfer({ - amount: TRANSFER_AMOUNTS.TOKENS, - account: Accounts.BOB, - asset: Assets.USDC, - })); + test( + 'Send USDC to Hub', + () => + transferTest.testTransfer({ + amount: TRANSFER_AMOUNTS.TOKENS, + account: Accounts.BOB, + asset: Asset.USDC, + assetSourceRelation: AssetSourceRelation.Sibling, + }), + { timeout: 25000 }, + ); - test('Send USDt to Hub', () => - transferTest.testTransfer({ - amount: TRANSFER_AMOUNTS.TOKENS, - account: Accounts.BOB, - asset: Assets.USDT, - })); + test( + 'Send USDT to Hub', + () => + transferTest.testTransfer({ + amount: TRANSFER_AMOUNTS.TOKENS, + account: Accounts.BOB, + asset: Asset.USDT, + assetSourceRelation: AssetSourceRelation.Sibling, + }), + { timeout: 25000 }, + ); - test('Send DOT to Hub', () => - transferTest.testTransfer({ - amount: TRANSFER_AMOUNTS.NATIVE, - account: Accounts.BOB, - asset: Assets.DOT, - })); + test( + 'Send DOT to Hub', + () => + transferTest.testTransfer({ + amount: TRANSFER_AMOUNTS.NATIVE, + account: Accounts.BOB, + asset: Asset.DOT, + assetSourceRelation: AssetSourceRelation.Parent, + }), + { timeout: 25000 }, + ); }); diff --git a/integration-tests/chopsticks/src/tests/polkadot.test.ts b/integration-tests/chopsticks/src/tests/polkadot.test.ts index 9a13531e3..699ec86ad 100644 --- a/integration-tests/chopsticks/src/tests/polkadot.test.ts +++ b/integration-tests/chopsticks/src/tests/polkadot.test.ts @@ -3,7 +3,7 @@ import { TRANSFER_AMOUNTS } from '@/constants'; import { createChainManager } from '@/managers/Factory'; import { ChainSetup } from '@/setup'; import { PolkadotToPolimecTransfer } from '@/transfers/PolkadotToPolimec'; -import { Accounts, Assets, Chains } from '@/types'; +import { Accounts, Asset, Chains } from '@/types'; describe('Polkadot -> Polimec Transfer Tests', () => { const chainSetup = new ChainSetup(); @@ -19,10 +19,14 @@ describe('Polkadot -> Polimec Transfer Tests', () => { }); afterAll(async () => await chainSetup.cleanup()); - test('Send DOT to Polimec', () => - transferTest.testTransfer({ - amount: TRANSFER_AMOUNTS.NATIVE, - account: Accounts.ALICE, - asset: Assets.DOT, - })); + test( + 'Send DOT to Polimec', + () => + transferTest.testTransfer({ + amount: TRANSFER_AMOUNTS.NATIVE, + account: Accounts.ALICE, + asset: Asset.DOT, + }), + { timeout: 25000 }, + ); }); diff --git a/integration-tests/chopsticks/src/transfers/HubToPolimec.ts b/integration-tests/chopsticks/src/transfers/HubToPolimec.ts index f3793759f..d591f74b0 100644 --- a/integration-tests/chopsticks/src/transfers/HubToPolimec.ts +++ b/integration-tests/chopsticks/src/transfers/HubToPolimec.ts @@ -2,14 +2,20 @@ import { expect } from 'bun:test'; import { INITIAL_BALANCES } from '@/constants'; import type { PolimecManager } from '@/managers/PolimecManager'; import type { PolkadotHubManager } from '@/managers/PolkadotHubManager'; -import { type Accounts, Assets, Chains, type PolimecBalanceCheck } from '@/types'; +import { + type Accounts, + Asset, + type AssetSourceRelation, + Chains, + type PolimecBalanceCheck, + getVersionedAssets, +} from '@/types'; import { createTransferData } from '@/utils'; -import { BaseTransferTest } from './BaseTransfer'; +import { type BaseTransferOptions, BaseTransferTest } from './BaseTransfer'; -interface HubTransferOptions { - amount: bigint; - account: Accounts; - asset: Assets; +interface HubTransferOptions extends BaseTransferOptions { + asset: Asset; + assetSourceRelation?: AssetSourceRelation; } export class HubToPolimecTransfer extends BaseTransferTest { @@ -20,17 +26,17 @@ export class HubToPolimecTransfer extends BaseTransferTest { super(sourceManager, destManager); } - async executeTransfer({ amount, account, asset }: HubTransferOptions) { + async executeTransfer({ amount, account, asset, assetSourceRelation }: HubTransferOptions) { const [sourceBlock, destBlock] = await Promise.all([ this.sourceManager.getBlockNumber(), this.destManager.getBlockNumber(), ]); + const assets = getVersionedAssets(asset, amount, assetSourceRelation); const data = createTransferData({ - amount, toChain: Chains.Polimec, + assets, recv: account, - assetIndex: asset === Assets.DOT ? undefined : BigInt(asset), }); const api = this.sourceManager.getApi(Chains.PolkadotHub); @@ -46,13 +52,10 @@ export class HubToPolimecTransfer extends BaseTransferTest { account, asset, }: Omit): Promise<{ balances: PolimecBalanceCheck }> { - const isNativeTransfer = asset === Assets.DOT; const treasuryAccount = this.destManager.getTreasuryAccount(); return { balances: { - source: isNativeTransfer - ? await this.sourceManager.getNativeBalanceOf(account) - : await this.sourceManager.getAssetBalanceOf(account, asset), + source: await this.sourceManager.getAssetBalanceOf(account, asset), destination: await this.destManager.getAssetBalanceOf(account, asset), treasury: await this.destManager.getAssetBalanceOf(treasuryAccount, asset), }, @@ -64,11 +67,11 @@ export class HubToPolimecTransfer extends BaseTransferTest { finalBalances: PolimecBalanceCheck, { asset }: HubTransferOptions, ) { - // TODO: At the moment we exclude fees from the balance check since the PAPI team is wotking on some utilies to calculate fees. + // TODO: At the moment we exclude fees from the balance check since the PAPI team is working on some utilities to calculate fees. const initialBalance = - asset === Assets.DOT + asset === Asset.DOT ? INITIAL_BALANCES.DOT - : asset === Assets.USDT + : asset === Asset.USDT ? INITIAL_BALANCES.USDT : INITIAL_BALANCES.USDC; // Note: Initially every account on destination is empty. diff --git a/integration-tests/chopsticks/src/transfers/PolimecToHub.ts b/integration-tests/chopsticks/src/transfers/PolimecToHub.ts index 7d65132f3..c497ccdd0 100644 --- a/integration-tests/chopsticks/src/transfers/PolimecToHub.ts +++ b/integration-tests/chopsticks/src/transfers/PolimecToHub.ts @@ -2,12 +2,19 @@ import { expect } from 'bun:test'; import { INITIAL_BALANCES } from '@/constants'; import type { PolimecManager } from '@/managers/PolimecManager'; import type { PolkadotHubManager } from '@/managers/PolkadotHubManager'; -import { Assets, type BalanceCheck, Chains } from '@/types'; +import { + Asset, + type AssetSourceRelation, + type BalanceCheck, + Chains, + getVersionedAssets, +} from '@/types'; import { createTransferData } from '@/utils'; import { type BaseTransferOptions, BaseTransferTest } from './BaseTransfer'; interface PolimecTransferOptions extends BaseTransferOptions { - asset: Assets; + asset: Asset; + assetSourceRelation: AssetSourceRelation; } export class PolimecToHubTransfer extends BaseTransferTest { @@ -18,16 +25,16 @@ export class PolimecToHubTransfer extends BaseTransferTest): Promise<{ balances: BalanceCheck }> { - const isNativeTransfer = asset === Assets.DOT; return { balances: { source: await this.sourceManager.getAssetBalanceOf(account, asset), - destination: isNativeTransfer - ? await this.destManager.getNativeBalanceOf(account) - : await this.destManager.getAssetBalanceOf(account, asset), + destination: await this.destManager.getAssetBalanceOf(account, asset), }, }; } @@ -62,9 +66,9 @@ export class PolimecToHubTransfer extends BaseTransferTest { @@ -23,11 +23,7 @@ export class PolkadotToPolimecTransfer extends BaseTransferTest = { + api: TypedApi; + client: PolkadotClient; +}; export const ParaId = { [Chains.Polimec]: 3344, [Chains.PolkadotHub]: 1000, }; +export enum AssetSourceRelation { + Parent = 0, + Sibling = 1, + Self = 2, +} + export enum Accounts { BOB = '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty', ALICE = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY', } -export enum Assets { - USDT = 1984, - DOT = 10, - USDC = 1337, - UNKNOWN = 42, -} - export type ChainToDefinition = { [Chains.Polimec]: Polimec; [Chains.PolkadotHub]: PolkadotHub; [Chains.Polkadot]: Polkadot; }; -export type ChainClient = { - api: TypedApi; - client: PolkadotClient; -}; - export interface TransferResult { sourceBlock: number; destBlock: number; @@ -54,17 +62,126 @@ export interface PolimecBalanceCheck extends BalanceCheck { } export interface TransferDataParams { - amount: bigint; toChain: Chains; - assetIndex?: bigint; + assets: XcmVersionedAssets; recv?: Accounts; isMultiHop?: boolean; - // TODO: Check if this flag is actually needed. - isFromBridge?: boolean; } -export interface CreateAssetsParams { - amount: bigint; - assetIndex?: bigint; - isFromBridge?: boolean; +export enum Asset { + USDT = 1984, + DOT = 10, + USDC = 1337, + WETH = 10000, +} + +function AssetHubAssetLocation( + assetId: bigint, + source_relation: AssetSourceRelation, +): XcmVersionedLocation { + switch (source_relation) { + case AssetSourceRelation.Sibling: + return XcmVersionedLocation.V4({ + parents: 1, + interior: XcmV3Junctions.X3([ + XcmV3Junction.Parachain(ParaId[Chains.PolkadotHub]), + XcmV3Junction.PalletInstance(50), + XcmV3Junction.GeneralIndex(assetId), + ]), + }); + case AssetSourceRelation.Self: + return XcmVersionedLocation.V4({ + parents: 0, + interior: XcmV3Junctions.X2([ + XcmV3Junction.PalletInstance(50), + XcmV3Junction.GeneralIndex(assetId), + ]), + }); + case AssetSourceRelation.Parent: + return XcmVersionedLocation.V4({ + parents: 0, + interior: XcmV3Junctions.X3([ + XcmV3Junction.Parachain(ParaId[Chains.PolkadotHub]), + XcmV3Junction.PalletInstance(50), + XcmV3Junction.GeneralIndex(assetId), + ]), + }); + } +} + +function NativeAssetLocation( + source_relation: AssetSourceRelation, + paraId?: number, +): XcmVersionedLocation { + switch (source_relation) { + case AssetSourceRelation.Sibling: + if (!paraId) { + throw new Error('You need to specify a paraId with SourceRelation.Sibling'); + } + return XcmVersionedLocation.V4({ + parents: 1, + interior: XcmV3Junctions.X1([XcmV3Junction.Parachain(paraId)]), + }); + case AssetSourceRelation.Self: + return XcmVersionedLocation.V4({ + parents: 0, + interior: XcmV3Junctions.Here(), + }); + case AssetSourceRelation.Parent: + return XcmVersionedLocation.V4({ + parents: 1, + interior: XcmV3Junctions.Here(), + }); + } +} + +function EthereumAssetLocation(contract_address: FixedSizeBinary<20>): XcmVersionedLocation { + return XcmVersionedLocation.V4({ + parents: 2, + interior: XcmV3Junctions.X2([ + XcmV3Junction.GlobalConsensus(XcmV3JunctionNetworkId.Ethereum(1)), + XcmV3Junction.AccountKey20({ network: undefined, key: contract_address }), + ]), + }); +} + +export function AssetLocation( + asset: Asset, + asset_source_relation?: AssetSourceRelation, +): XcmVersionedLocation { + if (asset_source_relation === undefined && asset !== Asset.WETH) { + throw new Error('You need to specify a asset_source_relation if asset is not WETH'); + } + + switch (asset) { + case Asset.USDT: + return AssetHubAssetLocation(1984n, asset_source_relation); + + case Asset.USDC: + return AssetHubAssetLocation(1337n, asset_source_relation); + + case Asset.DOT: + return NativeAssetLocation(asset_source_relation); + + case Asset.WETH: { + const contract_hex = '0x9d39a5de30e57443bff2a8307a4256c8797a3497'; + const byteArray = hexToU8a(contract_hex); + return EthereumAssetLocation(new FixedSizeBinary(byteArray)); + } + } +} + +export function getVersionedAssets( + asset: Asset, + amount: bigint, + asset_source_relation?: AssetSourceRelation, +): XcmVersionedAssets { + const asset_location = AssetLocation(asset, asset_source_relation); + + return XcmVersionedAssets.V4([ + { + id: asset_location.value, + fun: XcmV3MultiassetFungibility.Fungible(amount), + }, + ]); } diff --git a/integration-tests/chopsticks/src/utils.ts b/integration-tests/chopsticks/src/utils.ts index 670d9fb58..3fb06d28a 100644 --- a/integration-tests/chopsticks/src/utils.ts +++ b/integration-tests/chopsticks/src/utils.ts @@ -1,9 +1,11 @@ import { Accounts, + Asset, + AssetSourceRelation, Chains, - type CreateAssetsParams, ParaId, type TransferDataParams, + getVersionedAssets, } from '@/types'; import { XcmV3Instruction, @@ -15,7 +17,6 @@ import { XcmV3MultiassetWildMultiAsset, XcmV3WeightLimit, XcmVersionedAssetId, - XcmVersionedAssets, XcmVersionedLocation, XcmVersionedXcm, } from '@polkadot-api/descriptors'; @@ -57,61 +58,7 @@ const custom_xcm_on_dest = (): XcmVersionedXcm => { ]); }; -// TODO: Modify this function to allow the creation of an XcmVersionedAssets that supports also WETH/bridged assets. -const createHubAssets = ({ - amount, - assetIndex, - isFromBridge, -}: CreateAssetsParams): XcmVersionedAssets => - XcmVersionedAssets.V3([ - { - fun: XcmV3MultiassetFungibility.Fungible(amount), - id: XcmV3MultiassetAssetId.Concrete({ - parents: assetIndex ? 0 : 1, - interior: assetIndex - ? XcmV3Junctions.X2([ - XcmV3Junction.PalletInstance(50), - XcmV3Junction.GeneralIndex(assetIndex), - ]) - : XcmV3Junctions.Here(), - }), - }, - ]); - -const createDotAssets = ({ amount }: CreateAssetsParams): XcmVersionedAssets => - XcmVersionedAssets.V3([ - { - fun: XcmV3MultiassetFungibility.Fungible(amount), - id: XcmV3MultiassetAssetId.Concrete({ - parents: 0, - interior: XcmV3Junctions.Here(), - }), - }, - ]); - -const createPolimecAssets = ({ amount, assetIndex }: CreateAssetsParams): XcmVersionedAssets => { - if (!assetIndex) { - throw new Error('You need to specify an Asset ID while creating an asset for Polimec'); - } - return XcmVersionedAssets.V3([ - { - id: XcmV3MultiassetAssetId.Concrete({ - parents: 1, - interior: - assetIndex === 10n - ? XcmV3Junctions.Here() - : XcmV3Junctions.X3([ - XcmV3Junction.Parachain(ParaId[Chains.PolkadotHub]), - XcmV3Junction.PalletInstance(50), - XcmV3Junction.GeneralIndex(assetIndex), - ]), - }), - fun: XcmV3MultiassetFungibility.Fungible(amount), - }, - ]); -}; - -export const createTransferData = ({ amount, toChain, assetIndex, recv }: TransferDataParams) => { +export const createTransferData = ({ toChain, assets, recv }: TransferDataParams) => { if (toChain === Chains.Polkadot) { throw new Error('Invalid chain'); } @@ -133,16 +80,13 @@ export const createTransferData = ({ amount, toChain, assetIndex, recv }: Transf return { dest, beneficiary, - assets: - toChain === Chains.PolkadotHub - ? createPolimecAssets({ amount, assetIndex }) - : createHubAssets({ amount, assetIndex }), + assets, fee_asset_item: 0, weight_limit: XcmV3WeightLimit.Unlimited(), }; }; -export const createMultiHopTransferData = ({ amount }: TransferDataParams) => { +export const createMultiHopTransferData = (amount: bigint) => { const dest = XcmVersionedLocation.V3({ parents: 0, interior: XcmV3Junctions.X1(XcmV3Junction.Parachain(ParaId[Chains.PolkadotHub])), @@ -150,7 +94,7 @@ export const createMultiHopTransferData = ({ amount }: TransferDataParams) => { return { dest, - assets: createDotAssets({ amount }), + assets: getVersionedAssets(Asset.DOT, amount, AssetSourceRelation.Self), assets_transfer_type: Enum('Teleport'), remote_fees_id: XcmVersionedAssetId.V3( XcmV3MultiassetAssetId.Concrete({