From efc374381fb05f7b89a1e14b8e0912d770300c65 Mon Sep 17 00:00:00 2001 From: marshacb Date: Fri, 23 Jun 2023 17:37:45 -0400 Subject: [PATCH 01/55] add system to system direction --- src/AssetsTransferApi.spec.ts | 4 + src/AssetsTransferApi.ts | 87 ++--- src/consts.ts | 4 +- src/createXcmTypes/SystemToPara.spec.ts | 2 +- src/createXcmTypes/SystemToPara.ts | 23 +- src/createXcmTypes/SystemToSystem.spec.ts | 194 +++++++++++ src/createXcmTypes/SystemToSystem.ts | 304 ++++++++++++++++++ src/createXcmTypes/index.ts | 2 + .../util/getChainIdBySpecName.ts | 22 ++ .../util/getTokenSymbolGeneralIndex.spec.ts | 4 +- .../util/getTokenSymbolGeneralIndex.ts | 10 +- src/index.ts | 121 +++++++ src/types.ts | 4 + src/util/getFeeAssetItemIndex.ts | 7 +- 14 files changed, 732 insertions(+), 56 deletions(-) create mode 100644 src/createXcmTypes/SystemToSystem.spec.ts create mode 100644 src/createXcmTypes/SystemToSystem.ts create mode 100644 src/createXcmTypes/util/getChainIdBySpecName.ts diff --git a/src/AssetsTransferApi.spec.ts b/src/AssetsTransferApi.spec.ts index 6f8ecbb6..59a11086 100644 --- a/src/AssetsTransferApi.spec.ts +++ b/src/AssetsTransferApi.spec.ts @@ -25,6 +25,10 @@ const relayAssetsApi = new AssetsTransferApi(adjustedMockRelayApi, 'kusama', 2); describe('AssetTransferAPI', () => { describe('establishDirection', () => { + it('Should correctly determine direction for SystemToSystem', () => { + const res = relayAssetsApi['establishDirection']('1000', 'statemint'); + expect(res).toEqual('SystemToSystem'); + }); it('Should correctly determine direction for SystemToPara', () => { const res = systemAssetsApi['establishDirection']('2000', 'statemint'); expect(res).toEqual('SystemToPara'); diff --git a/src/AssetsTransferApi.ts b/src/AssetsTransferApi.ts index 02067df4..26091956 100644 --- a/src/AssetsTransferApi.ts +++ b/src/AssetsTransferApi.ts @@ -16,7 +16,7 @@ import { SYSTEM_PARACHAINS_IDS, SYSTEM_PARACHAINS_NAMES, } from './consts'; -import * as assets from './createCalls/assets'; +// import * as assets from './createCalls/assets'; import * as balances from './createCalls/balances'; import { limitedReserveTransferAssets, @@ -27,7 +27,7 @@ import { import { BaseError, checkBaseInputTypes, - checkLocalTxInput, + // checkLocalTxInput, checkXcmTxInputs, checkXcmVersion, } from './errors'; @@ -100,61 +100,62 @@ export class AssetsTransferApi { checkBaseInputTypes(destChainId, destAddr, assetIds, amounts); const { _api, _specName, _safeXcmVersion, registry } = this; - const isOriginSystemParachain = SYSTEM_PARACHAINS_NAMES.includes( - _specName.toLowerCase() - ); - const isDestSystemParachain = SYSTEM_PARACHAINS_IDS.includes(destChainId); + // const isOriginSystemParachain = SYSTEM_PARACHAINS_NAMES.includes( + // _specName.toLowerCase() + // ); + // const isDestSystemParachain = SYSTEM_PARACHAINS_IDS.includes(destChainId); /** * Sanitize the address to a hex, and ensure that the passed in SS58, or publickey * is validated correctly. */ const addr = sanitizeAddress(destAddr); - const isLocalSystemTx = isDestSystemParachain && isOriginSystemParachain; + // const isLocalSystemTx = isDestSystemParachain && isOriginSystemParachain; const isLocalRelayTx = destChainId === '0' && RELAY_CHAIN_NAMES.includes(_specName.toLowerCase()); /** * Create a local asset transfer on a system parachain */ - if (isLocalSystemTx || isLocalRelayTx) { + if (isLocalRelayTx) { /** * This will throw a BaseError if the inputs are incorrect and don't * fit the constraints for creating a local asset transfer. */ - const localAssetType = checkLocalTxInput(assetIds, amounts, registry); // Throws an error when any of the inputs are incorrect. + // const localAssetType = checkLocalTxInput(assetIds, amounts, registry); // Throws an error when any of the inputs are incorrect. const method = opts?.keepAlive ? 'transferKeepAlive' : 'transfer'; - if (isLocalSystemTx) { - let tx: SubmittableExtrinsic<'promise', ISubmittableResult>; - let palletMethod: LocalTransferTypes; - /** - * - */ - if (localAssetType === 'Balances') { - tx = - method === 'transferKeepAlive' - ? balances.transferKeepAlive(_api, addr, amounts[0]) - : balances.transfer(_api, addr, amounts[0]); - palletMethod = `balances::${method}`; - } else { - tx = - method === 'transferKeepAlive' - ? assets.transferKeepAlive(_api, addr, assetIds[0], amounts[0]) - : assets.transfer(_api, addr, assetIds[0], amounts[0]); - palletMethod = `assets::${method}`; - } - - return await this.constructFormat( - tx, - 'local', - null, - palletMethod, - destChainId, - _specName, - opts?.format, - opts?.paysWithFeeOrigin - ); - } else { + // if (isLocalSystemTx) { + // let tx: SubmittableExtrinsic<'promise', ISubmittableResult>; + // let palletMethod: LocalTransferTypes; + // /** + // * + // */ + // if (localAssetType === 'Balances') { + // tx = + // method === 'transferKeepAlive' + // ? balances.transferKeepAlive(_api, addr, amounts[0]) + // : balances.transfer(_api, addr, amounts[0]); + // palletMethod = `balances::${method}`; + // } else { + // tx = + // method === 'transferKeepAlive' + // ? assets.transferKeepAlive(_api, addr, assetIds[0], amounts[0]) + // : assets.transfer(_api, addr, assetIds[0], amounts[0]); + // palletMethod = `assets::${method}`; + // } + + // return await this.constructFormat( + // tx, + // 'local', + // null, + // palletMethod, + // destChainId, + // _specName, + // opts?.format, + // opts?.paysWithFeeOrigin + // ); + // } else + // if{ /** * By default local transaction on a relay chain will always be from the balances pallet */ @@ -173,7 +174,7 @@ export class AssetsTransferApi { opts?.format, opts?.paysWithFeeOrigin ); - } + // } } const xcmDirection = this.establishDirection(destChainId, _specName); @@ -336,6 +337,10 @@ export class AssetsTransferApi { return Direction.SystemToRelay; } + if (isSystemParachain && SYSTEM_PARACHAINS_IDS.includes(destChainId)) { + return Direction.SystemToSystem; + } + if (isSystemParachain && destChainId !== '0') { return Direction.SystemToPara; } diff --git a/src/consts.ts b/src/consts.ts index 45f03473..53ea5453 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -14,9 +14,9 @@ export const RELAY_CHAIN_IDS = ['0']; */ export const SYSTEM_PARACHAINS_NAMES = ['statemine', 'statemint', 'westmint']; /** - * As of now all the known system parachains have an ID of 1000. + * List of IDs for assets and bridge hub system parachains. */ -export const SYSTEM_PARACHAINS_IDS = ['1000']; +export const SYSTEM_PARACHAINS_IDS = ['1000', '1002']; /** * The default xcm version to construct a xcm message. */ diff --git a/src/createXcmTypes/SystemToPara.spec.ts b/src/createXcmTypes/SystemToPara.spec.ts index 6bd2fb72..b22c9351 100644 --- a/src/createXcmTypes/SystemToPara.spec.ts +++ b/src/createXcmTypes/SystemToPara.spec.ts @@ -284,7 +284,7 @@ describe('SystemToPara XcmVersioned Generation', () => { const assets = ['ksm', 'usdt']; const amounts = ['100000000000000', '300000000000000']; - const specName = 'kusama'; + const specName = 'statemine'; const result = createSystemToParaMultiAssets( mockSystemApi, amounts, diff --git a/src/createXcmTypes/SystemToPara.ts b/src/createXcmTypes/SystemToPara.ts index cf78cedd..94c2d582 100644 --- a/src/createXcmTypes/SystemToPara.ts +++ b/src/createXcmTypes/SystemToPara.ts @@ -25,6 +25,9 @@ import { dedupeMultiAssets } from './util/dedupeMultiAssets'; import { fetchPalletInstanceId } from './util/fetchPalletInstanceId'; import { getSystemChainTokenSymbolGeneralIndex } from './util/getTokenSymbolGeneralIndex'; import { sortMultiAssetsAscending } from './util/sortMultiAssetsAscending'; +import { getChainIdBySpecName } from '../createXcmTypes/util/getChainIdBySpecName'; +import { SYSTEM_PARACHAINS_IDS } from '../consts'; +import { BaseError } from '../errors'; export const SystemToPara: ICreateXcmType = { /** @@ -202,10 +205,16 @@ export const SystemToPara: ICreateXcmType = { registry ); + const systemChainId = getChainIdBySpecName(registry, specName); + if (!SYSTEM_PARACHAINS_IDS.includes(systemChainId)) { + throw new BaseError(`specName ${specName} did not match a valid system chain ID. Found ID ${systemChainId}`); + } + const assetIndex = getFeeAssetItemIndex( paysWithFeeDest, multiAssets, - specName + specName, + systemChainId ); return api.registry.createType('u32', assetIndex); @@ -233,8 +242,13 @@ export const createSystemToParaMultiAssets = ( const palletId = fetchPalletInstanceId(api); let multiAssets = []; - // We know this is a System parachain direction which is chainId 1000. - const { tokens } = registry.currentRelayRegistry['1000']; + const systemChainId = getChainIdBySpecName(registry, specName); + + if (!SYSTEM_PARACHAINS_IDS.includes(systemChainId)) { + throw new BaseError(`specName ${specName} did not match a valid system chain ID. Found ID ${systemChainId}`); + } + + const { tokens } = registry.currentRelayRegistry[systemChainId]; for (let i = 0; i < assets.length; i++) { let assetId: string = assets[i]; @@ -243,9 +257,10 @@ export const createSystemToParaMultiAssets = ( const parsedAssetIdAsNumber = Number.parseInt(assetId); const isNotANumber = Number.isNaN(parsedAssetIdAsNumber); const isRelayNative = isRelayNativeAsset(tokens, assetId); + if (!isRelayNative && isNotANumber) { - assetId = getSystemChainTokenSymbolGeneralIndex(assetId, specName); + assetId = getSystemChainTokenSymbolGeneralIndex(assetId, specName, systemChainId); } const interior: MultiAssetInterior = isRelayNative diff --git a/src/createXcmTypes/SystemToSystem.spec.ts b/src/createXcmTypes/SystemToSystem.spec.ts new file mode 100644 index 00000000..2353e6e7 --- /dev/null +++ b/src/createXcmTypes/SystemToSystem.spec.ts @@ -0,0 +1,194 @@ +// Copyright 2023 Parity Technologies (UK) Ltd. + +import { Registry } from '../registry'; +import { mockSystemApi } from '../testHelpers/mockSystemApi'; +import { SystemToSystem } from './SystemToSystem'; + +describe('SystemToSystem XcmVersioned Generation', () => { + const registry = new Registry('statemine', {}); + + describe('Beneficiary', () => { + it('Should work for V2', () => { + const beneficiary = SystemToSystem.createBeneficiary( + mockSystemApi, + '0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b', + 2 + ); + + const expectedRes = { + v2: { + parents: 0, + interior: { + x1: { + accountId32: { + id: '0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b', + network: { + any: null, + }, + }, + }, + }, + }, + }; + + expect(beneficiary.toJSON()).toStrictEqual(expectedRes); + }); + it('Should work for V3', () => { + const beneficiary = SystemToSystem.createBeneficiary( + mockSystemApi, + '0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b', + 3 + ); + + const expectedRes = { + v3: { + parents: 0, + interior: { + x1: { + accountId32: { + id: '0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b', + network: null, + }, + }, + }, + }, + }; + + expect(beneficiary.toJSON()).toStrictEqual(expectedRes); + }); + }); + describe('Destination', () => { + it('Should work for V2', () => { + const destination = SystemToSystem.createDest(mockSystemApi, '1000', 2); + + const expectedRes = { + v2: { + parents: 1, + interior: { + x1: { + parachain: 1000 + }, + }, + }, + }; + + expect(destination.toJSON()).toStrictEqual(expectedRes); + }); + it('Should work for V3', () => { + const destination = SystemToSystem.createDest(mockSystemApi, '1002', 3); + + const expectedRes = { + v3: { + parents: 1, + interior: { + x1: { + parachain: 1002, + } + }, + }, + }; + + expect(destination.toJSON()).toStrictEqual(expectedRes); + }); + }); + + describe('Assets', () => { + it('Should work for V2', () => { + const assets = SystemToSystem.createAssets( + mockSystemApi, + ['100'], + 2, + 'statemine', + ['USDT'], + { registry } + ); + + const expectedRes = { + v2: [ + { + id: { + concrete: { + parents: 0, + interior: { + x2: [{ palletInstance: 50 },{ generalIndex: 11 }] + } + }, + }, + fun: { + fungible: 100, + }, + }, + ], + }; + + expect(assets.toJSON()).toStrictEqual(expectedRes); + }); + it('Should work for V3', () => { + const assets = SystemToSystem.createAssets( + mockSystemApi, + ['100'], + 3, + 'bridge-hub-kusama', + ['ksm'], + { registry } + ); + + const expectedRes = { + v3: [ + { + id: { + concrete: { + parents: 1, + interior: { + here: null, + }, + }, + }, + fun: { + fungible: 100, + }, + }, + ], + }; + + console.log('ASSETS TO JSON', assets.toJSON()); + + expect(assets.toJSON()).toStrictEqual(expectedRes); + }); + + it('Should error when system chain ID is not found for V3', () => { + const expectedErrorMessage = 'bridge-hub-kusama has no associated token symbol usdc'; + + const err = () => SystemToSystem.createAssets( + mockSystemApi, + ['100'], + 3, + 'bridge-hub-kusama', + ['usdc'], + { registry } + ); + + + + expect(err).toThrowError(expectedErrorMessage); + }); + }); + describe('WeightLimit', () => { + it('Should work when given a weightLimit', () => { + const weightLimit = SystemToSystem.createWeightLimit( + mockSystemApi, + '100000000' + ); + expect(weightLimit.toJSON()).toStrictEqual({ + limited: 100000000, + }); + }); + it('Should work when no weightLimit is present', () => { + const weightLimit = SystemToSystem.createWeightLimit(mockSystemApi); + + expect(weightLimit.toJSON()).toStrictEqual({ + unlimited: null, + }); + }); + }); +}); diff --git a/src/createXcmTypes/SystemToSystem.ts b/src/createXcmTypes/SystemToSystem.ts new file mode 100644 index 00000000..a2e1ceee --- /dev/null +++ b/src/createXcmTypes/SystemToSystem.ts @@ -0,0 +1,304 @@ +// Copyright 2023 Parity Technologies (UK) Ltd. + +import type { ApiPromise } from '@polkadot/api'; +import { u32 } from '@polkadot/types'; +import type { + MultiAssetsV2, + VersionedMultiAssets, + VersionedMultiLocation, + WeightLimitV2, +} from '@polkadot/types/interfaces'; +import type { XcmV3MultiassetMultiAssets } from '@polkadot/types/lookup'; +import { isEthereumAddress } from '@polkadot/util-crypto'; + +import type { Registry } from '../registry'; +import { getFeeAssetItemIndex } from '../util/getFeeAssetItemIndex'; +import { normalizeArrToStr } from '../util/normalizeArrToStr'; +import { MultiAsset, MultiAssetInterior } from './../types'; +import { + CreateAssetsOpts, + CreateFeeAssetItemOpts, + ICreateXcmType, + IWeightLimit, +} from './types'; +import { dedupeMultiAssets } from './util/dedupeMultiAssets'; +import { fetchPalletInstanceId } from './util/fetchPalletInstanceId'; +import { getSystemChainTokenSymbolGeneralIndex } from './util/getTokenSymbolGeneralIndex'; +import { sortMultiAssetsAscending } from './util/sortMultiAssetsAscending'; +import { BaseError } from '../errors'; +import { SYSTEM_PARACHAINS_IDS } from '../consts'; +import { getChainIdBySpecName } from '../createXcmTypes/util/getChainIdBySpecName'; + +export const SystemToSystem: ICreateXcmType = { + /** + * Create a XcmVersionedMultiLocation type for a beneficiary. + * + * @param api ApiPromise + * @param accountId The accountId of the beneficiary + * @param xcmVersion The accepted xcm version + */ + createBeneficiary: ( + api: ApiPromise, + accountId: string, + xcmVersion?: number + ): VersionedMultiLocation => { + if (xcmVersion == 2) { + const X1 = isEthereumAddress(accountId) + ? { AccountKey20: { network: 'Any', key: accountId } } + : { AccountId32: { network: 'Any', id: accountId } }; + + return api.registry.createType('XcmVersionedMultiLocation', { + V2: { + parents: 0, + interior: { + X1, + }, + }, + }); + } + + const X1 = isEthereumAddress(accountId) + ? { AccountKey20: { key: accountId } } + : { AccountId32: { id: accountId } }; + + return api.registry.createType('XcmVersionedMultiLocation', { + V3: { + parents: 0, + interior: { + X1, + }, + }, + }); + }, + /** + * Create a XcmVersionedMultiLocation type for a destination. + * + * @param api ApiPromise + * @param destId The parachain Id of the destination + * @param xcmVersion The accepted xcm version + */ + createDest: ( + api: ApiPromise, + destId: string, + xcmVersion?: number + ): VersionedMultiLocation => { + if (xcmVersion === 2) { + return api.registry.createType('XcmVersionedMultiLocation', { + V2: { + parents: 1, + interior: { + X1: { + parachain: destId, + }, + }, + }, + }); + } + + /** + * Ensure that the `parents` field is a `1` when sending a destination MultiLocation + * from a system parachain to a sovereign parachain. + */ + return api.registry.createType('XcmVersionedMultiLocation', { + V3: { + parents: 1, + interior: { + X1: { + parachain: destId, + }, + }, + }, + }); + }, + /** + * Create a VersionedMultiAsset type. + * + * @param assets + * @param amounts + * @param xcmVersion + */ + createAssets: ( + api: ApiPromise, + amounts: string[], + xcmVersion: number, + specName: string, + assets: string[], + opts: CreateAssetsOpts + ): VersionedMultiAssets => { + const { registry } = opts; + + const sortedAndDedupedMultiAssets = createSystemToSystemMultiAssets( + api, + amounts, + specName, + assets, + registry, + ); + + if (xcmVersion === 2) { + const multiAssetsType: MultiAssetsV2 = api.registry.createType( + 'XcmV2MultiassetMultiAssets', + sortedAndDedupedMultiAssets + ); + + return api.registry.createType('XcmVersionedMultiAssets', { + V2: multiAssetsType, + }); + } else { + const multiAssetsType: XcmV3MultiassetMultiAssets = + api.registry.createType( + 'XcmV3MultiassetMultiAssets', + sortedAndDedupedMultiAssets + ); + + return api.registry.createType('XcmVersionedMultiAssets', { + V3: multiAssetsType, + }); + } + }, + /** + * TODO: Generalize the weight type with V3. + * Create a WeightLimitV2 type. + * + * @param api ApiPromise + * @param weightLimit WeightLimit passed in as an option. + */ + createWeightLimit: (api: ApiPromise, weightLimit?: string): WeightLimitV2 => { + const limit: IWeightLimit = weightLimit + ? { Limited: weightLimit } + : { Unlimited: null }; + + return api.registry.createType('XcmV2WeightLimit', limit); + }, + + /** + * returns the correct feeAssetItem based on XCM direction. + * + * @param api ApiPromise + * @param paysWithFeeDest string + * @param specName string + * @param assetIds string[] + * @param amounts string[] + * @xcmVersion number + * + */ + createFeeAssetItem: (api: ApiPromise, opts: CreateFeeAssetItemOpts): u32 => { + const { + registry, + paysWithFeeDest, + specName, + assetIds, + amounts, + xcmVersion, + } = opts; + if ( + xcmVersion && + xcmVersion === 3 && + specName && + amounts && + assetIds && + paysWithFeeDest + ) { + const multiAssets = createSystemToSystemMultiAssets( + api, + normalizeArrToStr(amounts), + specName, + assetIds, + registry + ); + + const systemChainId = getChainIdBySpecName(registry, specName); + + if (!SYSTEM_PARACHAINS_IDS.includes(systemChainId)) { + throw new BaseError(`specName ${specName} did not match a valid system chain ID. Found ID ${systemChainId}`); + } + + const assetIndex = getFeeAssetItemIndex( + paysWithFeeDest, + multiAssets, + specName, + systemChainId + ); + + return api.registry.createType('u32', assetIndex); + } + + return api.registry.createType('u32', 0); + }, +}; + +/** + * Creates and returns a MultiAsset array for system parachains based on provided specName, chain ID, assets and amounts + * + * @param api ApiPromise[] + * @param amounts string[] + * @param specName string + * @param assets string[] + * @param chainId string + */ +export const createSystemToSystemMultiAssets = ( + api: ApiPromise, + amounts: string[], + specName: string, + assets: string[], + registry: Registry, +): MultiAsset[] => { + const palletId = fetchPalletInstanceId(api); + let multiAssets = []; + + const systemChainId = getChainIdBySpecName(registry, specName); + + if (!SYSTEM_PARACHAINS_IDS.includes(systemChainId)) { + throw new BaseError(`specName ${specName} did not match a valid system chain ID. Found ID ${systemChainId}`); + } + + const { tokens } = registry.currentRelayRegistry[systemChainId]; + + for (let i = 0; i < assets.length; i++) { + let assetId: string = assets[i]; + const amount = amounts[i]; + + const parsedAssetIdAsNumber = Number.parseInt(assetId); + const isNotANumber = Number.isNaN(parsedAssetIdAsNumber); + const isRelayNative = isRelayNativeAsset(tokens, assetId); + + if (!isRelayNative && isNotANumber) { + assetId = getSystemChainTokenSymbolGeneralIndex(assetId, specName, systemChainId); + } + + const interior: MultiAssetInterior = isRelayNative + ? { Here: '' } + : { X2: [{ PalletInstance: palletId }, { GeneralIndex: assetId }] }; + const parents = isRelayNative ? 1 : 0; + + const multiAsset = { + id: { + Concrete: { + parents, + interior, + }, + }, + fun: { + Fungible: amount, + }, + }; + + multiAssets.push(multiAsset); + } + + multiAssets = sortMultiAssetsAscending(multiAssets); + + const sortedAndDedupedMultiAssets = dedupeMultiAssets(multiAssets); + + return sortedAndDedupedMultiAssets; +}; + +const isRelayNativeAsset = (tokens: string[], assetId: string): boolean => { + for (const token of tokens) { + if (token.toLowerCase() === assetId.toLowerCase()) { + return true; + } + } + + return false; +}; \ No newline at end of file diff --git a/src/createXcmTypes/index.ts b/src/createXcmTypes/index.ts index 36c64783..5636d59b 100644 --- a/src/createXcmTypes/index.ts +++ b/src/createXcmTypes/index.ts @@ -3,6 +3,7 @@ import { Direction } from '../types'; import { RelayToPara } from './RelayToPara'; import { RelayToSystem } from './RelayToSystem'; +import { SystemToSystem } from './SystemToSystem'; import { SystemToPara } from './SystemToPara'; import { SystemToRelay } from './SystemToRelay'; import { ICreateXcmType } from './types'; @@ -12,6 +13,7 @@ type ICreateXcmTypeLookup = { }; export const createXcmTypes: ICreateXcmTypeLookup = { + SystemToSystem, SystemToPara, RelayToPara, SystemToRelay, diff --git a/src/createXcmTypes/util/getChainIdBySpecName.ts b/src/createXcmTypes/util/getChainIdBySpecName.ts new file mode 100644 index 00000000..209e2be9 --- /dev/null +++ b/src/createXcmTypes/util/getChainIdBySpecName.ts @@ -0,0 +1,22 @@ +// Copyright 2023 Parity Technologies (UK) Ltd. + +import { Registry } from "../../registry"; + +/** + * returns a chains ID based on its relay chain and specName + * + * @param registry Registry + * @param specName string + * @returns + */ +export const getChainIdBySpecName = (registry: Registry, specName: string): string => { + let result = ''; + + Object.entries(registry.currentRelayRegistry).forEach((chainInfo) => { + if (chainInfo[1].specName.toLowerCase() === specName.toLowerCase()) { + result = chainInfo[0]; + } + }); + + return result; +} \ No newline at end of file diff --git a/src/createXcmTypes/util/getTokenSymbolGeneralIndex.spec.ts b/src/createXcmTypes/util/getTokenSymbolGeneralIndex.spec.ts index 06efe5b4..74eb9664 100644 --- a/src/createXcmTypes/util/getTokenSymbolGeneralIndex.spec.ts +++ b/src/createXcmTypes/util/getTokenSymbolGeneralIndex.spec.ts @@ -6,14 +6,14 @@ describe('getSystemChainTokenSymbolGeneralIndex', () => { it('Should successfully return the general index when given a valid native system chain token symbol', () => { const expected = '1337'; - const result = getSystemChainTokenSymbolGeneralIndex('USDC', 'polkadot'); + const result = getSystemChainTokenSymbolGeneralIndex('USDC', 'polkadot', '1000'); expect(result).toEqual(expected); }); it('Should error when an asset id symbol is given that is not present in the registry', () => { const err = () => - getSystemChainTokenSymbolGeneralIndex('NOTUSDT', 'polkadot'); + getSystemChainTokenSymbolGeneralIndex('NOTUSDT', 'polkadot', '1000'); expect(err).toThrow('general index for assetId NOTUSDT was not found'); }); diff --git a/src/createXcmTypes/util/getTokenSymbolGeneralIndex.ts b/src/createXcmTypes/util/getTokenSymbolGeneralIndex.ts index 7c467541..2f314051 100644 --- a/src/createXcmTypes/util/getTokenSymbolGeneralIndex.ts +++ b/src/createXcmTypes/util/getTokenSymbolGeneralIndex.ts @@ -1,6 +1,5 @@ // Copyright 2023 Parity Technologies (UK) Ltd. -import { SYSTEM_PARACHAINS_IDS } from '../../consts'; import { BaseError } from '../../errors'; import { findRelayChain, parseRegistry } from '../../registry'; @@ -13,11 +12,16 @@ import { findRelayChain, parseRegistry } from '../../registry'; */ export const getSystemChainTokenSymbolGeneralIndex = ( tokenSymbol: string, - specName: string + specName: string, + systemChainId: string, ): string => { const registry = parseRegistry({}); const relayChain = findRelayChain(specName, registry); - const { assetsInfo } = registry[relayChain][SYSTEM_PARACHAINS_IDS[0]]; + const { assetsInfo } = registry[relayChain][systemChainId]; + + if (Object.keys(assetsInfo).length === 0) { + throw new BaseError(`${specName} has no associated token symbol ${tokenSymbol}`); + } // get the corresponding asset id index from the assets registry const assetId: string | undefined = Object.keys(assetsInfo).find( diff --git a/src/index.ts b/src/index.ts index a3b36094..e32a3b95 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,3 +3,124 @@ export * from './AssetsTransferApi'; export * from './constructApiPromise'; export * from './types'; + +// import { VersionedMultiLocation } from '@capi/polkadot/types/xcm/mod'; +import { ApiPromise, WsProvider } from '@polkadot/api'; + +import { AssetsTransferApi } from './AssetsTransferApi'; + +// type DecodedExtrinsic = { +// callIndex: string; +// args: XCMInfo; +// }; + +// type XCMInfo = { +// dest: VersionedMultiLocation; +// benificiary: VersionedMultiLocation; +// assets: VersionedMultiLocation; +// fee_asset_item: string; +// }; + +const main = async () => { + const provider = new WsProvider('wss://statemine-rpc.polkadot.io'); + const api = await ApiPromise.create({ provider }); + + await api.isReady; + + const assetTransferApi = new AssetsTransferApi(api, 'statemine', 2); + + // call + // const call = await assetTransferApi.createTransferTransaction( + // '2000', // destChainId + // '0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b', // destAddr + // ['ksm', '10', '34', '36', '11', '12'], // assetIds + // ['100', '2000', '300', '400', '500', '700'], // amounts + // { + // paysWithFeeDest: '10', + // xcmVersion: 3, + // format: 'call', + // keepAlive: true, + // } // opts + // ); + // console.log('call is', call); + // const callExtrinsic = api.registry.createType('Call', call.tx); + // console.log('call to human', callExtrinsic.toString()); + // const decoded1: DecodedExtrinsic = JSON.parse(callExtrinsic.toString()); + // console.log('decoded1', decoded1); + + // // payload + // const decoded = assetTransferApi.decodeExtrinsic(`0x95067b2263616c6c496e646578223a22307836333039222c2261726773223a7b2264657374223a7b227632223a7b22706172656e7473223a302c22696e746572696f72223a7b227831223a7b2270617261636861696e223a313030307d7d7d7d2c2262656e6566696369617279223a7b227632223a7b22706172656e7473223a302c22696e746572696f72223a7b227831223a7b226163636f756e7449643332223a7b226e6574776f726b223a7b22616e79223a6e756c6c7d2c226964223a22307863323234616164396336663362626437383431323065396663656565356266643232613632633639313434656536373366373664366133346432383064653136227d7d7d7d7d2c22617373657473223a7b227632223a5b7b226964223a7b22636f6e6372657465223a7b22706172656e7473223a302c22696e746572696f72223a7b2268657265223a6e756c6c7d7d7d2c2266756e223a7b2266756e6769626c65223a353030303030307d7d5d7d2c226665655f61737365745f6974656d223a302c227765696768745f6c696d6974223a7b22756e6c696d69746564223a6e756c6c7d7d7d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + // `, 'payload'); + // console.log('WHAT IS DECODED', decoded); + // const payload = await assetTransferApi.createTransferTransaction( + // '1000', // destChainId + // '0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b', // destAddr + // [], // assetIds + // ['100'], // amounts + // { + // format: 'payload', + // keepAlive: true, + // // paysWithFeeOrigin: '1984', + // } // opts + // ); + // console.log('payload is', payload); + + + const payload = await assetTransferApi.createTransferTransaction( + '1000', + 'GxshYjshWQkCLtCWwtW5os6tM3qvo6ozziDXG9KbqpHNVfZ', + ['usdt', 'usdc'], + ['5000000', '4000000000'], + { + format: 'payload', + isLimited: true, + xcmVersion: 3, + paysWithFeeOrigin: '1984', + paysWithFeeDest: 'USDC' + } + ); + + console.log('payload', JSON.stringify(payload)); + + const decodedPayload = assetTransferApi.decodeExtrinsic(payload.tx, 'payload'); + console.log('decodedPayload', decodedPayload); + + const payloadExtrinsic = api.registry.createType( + 'ExtrinsicPayload', + payload.tx, + { + version: 4, + } + ); + + console.log( + 'payload method to string', + JSON.stringify(payloadExtrinsic.method.toHuman()) + ); + const payloadJSON = payloadExtrinsic.method.toJSON() as string; + console.log('payload json', payloadJSON); + // const decoded2: DecodedExtrinsic = JSON.parse(payloadJSON); + // console.log('decoded2', JSON.stringify(decoded2)); + + + + + // submittable + // const submittable = await assetTransferApi.createTransferTransaction( + // '0', // destChainId + // '0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b', // destAddr + // [], // assetIds + // ['50000000'], // amounts + // { + // format: 'submittable', + // keepAlive: true + // } // opts + // ); + + // console.log('submittable', submittable.direction); + // const call = api.registry.createType('Extrinsic', submittable.tx.toHex()); + // console.log('call is', call.method.toString()); +}; + + main(); + diff --git a/src/types.ts b/src/types.ts index cba1ffa6..6d077540 100644 --- a/src/types.ts +++ b/src/types.ts @@ -35,6 +35,10 @@ export enum Direction { * System parachain to Relay chain. */ SystemToRelay = 'SystemToRelay', + /** + * System parachain to System parachain chain. + */ + SystemToSystem = 'SystemToSystem', /** * Parachain to Parachain. */ diff --git a/src/util/getFeeAssetItemIndex.ts b/src/util/getFeeAssetItemIndex.ts index fb2a926e..b15247e6 100644 --- a/src/util/getFeeAssetItemIndex.ts +++ b/src/util/getFeeAssetItemIndex.ts @@ -15,7 +15,8 @@ import { NonRelayNativeInterior, RelayNativeInterior } from '../types'; export const getFeeAssetItemIndex = ( paysWithFeeDest: string, multiAssets: MultiAsset[], - specName: string + specName: string, + systemChainId?: string ): number => { let result = 0; @@ -42,9 +43,9 @@ export const getFeeAssetItemIndex = ( // if not a number, get the general index of the pays with fee asset // to compare against the current multi asset - if (isNotANumber) { + if (isNotANumber && systemChainId) { const paysWithFeeDestGeneralIndex = - getSystemChainTokenSymbolGeneralIndex(paysWithFeeDest, specName); + getSystemChainTokenSymbolGeneralIndex(paysWithFeeDest, specName, systemChainId); if ( (multiAsset.id.Concrete.interior as NonRelayNativeInterior).X2 && (multiAsset.id.Concrete.interior as NonRelayNativeInterior).X2[1] From cdf89fec4e4281775f74643f0617dfb5c914af5e Mon Sep 17 00:00:00 2001 From: marshacb Date: Fri, 23 Jun 2023 21:01:52 -0400 Subject: [PATCH 02/55] update isLocalSystemTx --- src/AssetsTransferApi.ts | 80 ++++++++++--------- .../limitedReserveTransferAssets.spec.ts | 16 ++-- .../limitedTeleportAssets.spec.ts | 4 +- .../reserveTransferAssets.spec.ts | 4 +- src/createXcmCalls/teleportAssets.spec.ts | 8 +- src/createXcmTypes/SystemToPara.spec.ts | 4 +- src/createXcmTypes/SystemToPara.ts | 3 +- src/createXcmTypes/SystemToSystem.ts | 3 +- .../util/getTokenSymbolGeneralIndex.spec.ts | 4 +- .../util/getTokenSymbolGeneralIndex.ts | 17 ++-- src/index.ts | 8 +- .../AssetsTransferApi.spec.ts | 36 ++++----- src/registry/Registry.spec.ts | 1 - src/util/getFeeAssetItemIndex.spec.ts | 9 ++- src/util/getFeeAssetItemIndex.ts | 5 +- 15 files changed, 104 insertions(+), 98 deletions(-) diff --git a/src/AssetsTransferApi.ts b/src/AssetsTransferApi.ts index 26091956..4fe7af05 100644 --- a/src/AssetsTransferApi.ts +++ b/src/AssetsTransferApi.ts @@ -16,7 +16,7 @@ import { SYSTEM_PARACHAINS_IDS, SYSTEM_PARACHAINS_NAMES, } from './consts'; -// import * as assets from './createCalls/assets'; +import * as assets from './createCalls/assets'; import * as balances from './createCalls/balances'; import { limitedReserveTransferAssets, @@ -27,7 +27,7 @@ import { import { BaseError, checkBaseInputTypes, - // checkLocalTxInput, + checkLocalTxInput, checkXcmTxInputs, checkXcmVersion, } from './errors'; @@ -46,6 +46,7 @@ import { TxResult, UnsignedTransaction, } from './types'; +import { getChainIdBySpecName } from './createXcmTypes/util/getChainIdBySpecName'; /** * Holds open an api connection to a specified chain within the ApiPromise in order to help @@ -104,58 +105,59 @@ export class AssetsTransferApi { // _specName.toLowerCase() // ); // const isDestSystemParachain = SYSTEM_PARACHAINS_IDS.includes(destChainId); - + /** * Sanitize the address to a hex, and ensure that the passed in SS58, or publickey * is validated correctly. */ const addr = sanitizeAddress(destAddr); - // const isLocalSystemTx = isDestSystemParachain && isOriginSystemParachain; + + const originChainId = getChainIdBySpecName(registry, _specName); + const isLocalSystemTx = originChainId === destChainId; const isLocalRelayTx = destChainId === '0' && RELAY_CHAIN_NAMES.includes(_specName.toLowerCase()); /** * Create a local asset transfer on a system parachain */ - if (isLocalRelayTx) { + if (isLocalSystemTx || isLocalRelayTx) { /** * This will throw a BaseError if the inputs are incorrect and don't * fit the constraints for creating a local asset transfer. */ - // const localAssetType = checkLocalTxInput(assetIds, amounts, registry); // Throws an error when any of the inputs are incorrect. + const localAssetType = checkLocalTxInput(assetIds, amounts, registry); // Throws an error when any of the inputs are incorrect. const method = opts?.keepAlive ? 'transferKeepAlive' : 'transfer'; - // if (isLocalSystemTx) { - // let tx: SubmittableExtrinsic<'promise', ISubmittableResult>; - // let palletMethod: LocalTransferTypes; - // /** - // * - // */ - // if (localAssetType === 'Balances') { - // tx = - // method === 'transferKeepAlive' - // ? balances.transferKeepAlive(_api, addr, amounts[0]) - // : balances.transfer(_api, addr, amounts[0]); - // palletMethod = `balances::${method}`; - // } else { - // tx = - // method === 'transferKeepAlive' - // ? assets.transferKeepAlive(_api, addr, assetIds[0], amounts[0]) - // : assets.transfer(_api, addr, assetIds[0], amounts[0]); - // palletMethod = `assets::${method}`; - // } - - // return await this.constructFormat( - // tx, - // 'local', - // null, - // palletMethod, - // destChainId, - // _specName, - // opts?.format, - // opts?.paysWithFeeOrigin - // ); - // } else - // if{ + if (isLocalSystemTx) { + let tx: SubmittableExtrinsic<'promise', ISubmittableResult>; + let palletMethod: LocalTransferTypes; + /** + * + */ + if (localAssetType === 'Balances') { + tx = + method === 'transferKeepAlive' + ? balances.transferKeepAlive(_api, addr, amounts[0]) + : balances.transfer(_api, addr, amounts[0]); + palletMethod = `balances::${method}`; + } else { + tx = + method === 'transferKeepAlive' + ? assets.transferKeepAlive(_api, addr, assetIds[0], amounts[0]) + : assets.transfer(_api, addr, assetIds[0], amounts[0]); + palletMethod = `assets::${method}`; + } + + return await this.constructFormat( + tx, + 'local', + null, + palletMethod, + destChainId, + _specName, + opts?.format, + opts?.paysWithFeeOrigin + ); + } else { /** * By default local transaction on a relay chain will always be from the balances pallet */ @@ -174,7 +176,7 @@ export class AssetsTransferApi { opts?.format, opts?.paysWithFeeOrigin ); - // } + } } const xcmDirection = this.establishDirection(destChainId, _specName); diff --git a/src/createXcmCalls/limitedReserveTransferAssets.spec.ts b/src/createXcmCalls/limitedReserveTransferAssets.spec.ts index 7a71d54a..e8803896 100644 --- a/src/createXcmCalls/limitedReserveTransferAssets.spec.ts +++ b/src/createXcmCalls/limitedReserveTransferAssets.spec.ts @@ -17,14 +17,14 @@ describe('limitedReserveTransferAssets', () => { '0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b', ['1'], ['100'], - '1000', + '2023', 2, - 'statemint', + 'statemine', registry ); expect(ext.toHex()).toBe( - '0xfc041f0801010100a10f0100010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b0104000002043205040091010000000000' + '0xfc041f08010101009d1f0100010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b0104000002043205040091010000000000' ); }); it('Should correctly construct a tx for when a weightLimit is available', () => { @@ -34,15 +34,15 @@ describe('limitedReserveTransferAssets', () => { '0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b', ['1'], ['100'], - '1000', + '2023', 2, - 'statemint', + 'statemine', registry, '1000000000' ); expect(ext.toHex()).toBe( - '0x0501041f0801010100a10f0100010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b01040000020432050400910100000000010000' + '0x0501041f08010101009d1f0100010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b01040000020432050400910100000000010000' ); }); it('Should error when a api does not support the required pallets', () => { @@ -54,9 +54,9 @@ describe('limitedReserveTransferAssets', () => { '0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b', ['1'], ['100'], - '1000', + '2023', 2, - 'statemint', + 'statemine', registry ); diff --git a/src/createXcmCalls/limitedTeleportAssets.spec.ts b/src/createXcmCalls/limitedTeleportAssets.spec.ts index 2573fd5b..0a61a843 100644 --- a/src/createXcmCalls/limitedTeleportAssets.spec.ts +++ b/src/createXcmCalls/limitedTeleportAssets.spec.ts @@ -17,7 +17,7 @@ describe('limitedTeleportAssets', () => { ['100'], '1000', 2, - 'statemint', + 'statemine', registry ); @@ -36,7 +36,7 @@ describe('limitedTeleportAssets', () => { ['100'], '1000', 2, - 'statemint', + 'statemine', registry ); diff --git a/src/createXcmCalls/reserveTransferAssets.spec.ts b/src/createXcmCalls/reserveTransferAssets.spec.ts index 955c1a90..a8de82d3 100644 --- a/src/createXcmCalls/reserveTransferAssets.spec.ts +++ b/src/createXcmCalls/reserveTransferAssets.spec.ts @@ -19,7 +19,7 @@ describe('reserveTransferAssets', () => { ['100'], '1000', 2, - 'statemint', + 'statemine', registry ); @@ -38,7 +38,7 @@ describe('reserveTransferAssets', () => { ['100'], '1000', 2, - 'statemint', + 'statemine', registry ); diff --git a/src/createXcmCalls/teleportAssets.spec.ts b/src/createXcmCalls/teleportAssets.spec.ts index b328bbe6..9bd23295 100644 --- a/src/createXcmCalls/teleportAssets.spec.ts +++ b/src/createXcmCalls/teleportAssets.spec.ts @@ -15,14 +15,14 @@ describe('teleportAssets', () => { '0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b', ['1'], ['100'], - '1000', + '2004', 2, - 'statemint', + 'statemine', registry ); expect(ext.toHex()).toBe( - '0xf8041f0101010100a10f0100010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b01040000020432050400910100000000' + '0xf8041f0101010100511f0100010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b01040000020432050400910100000000' ); }); it('Should error when a api does not support the required pallets', () => { @@ -36,7 +36,7 @@ describe('teleportAssets', () => { ['100'], '1000', 2, - 'statemint', + 'statemine', registry ); diff --git a/src/createXcmTypes/SystemToPara.spec.ts b/src/createXcmTypes/SystemToPara.spec.ts index b22c9351..33df45c5 100644 --- a/src/createXcmTypes/SystemToPara.spec.ts +++ b/src/createXcmTypes/SystemToPara.spec.ts @@ -148,7 +148,7 @@ describe('SystemToPara XcmVersioned Generation', () => { mockSystemApi, ['100', '100'], 2, - 'statemint', + 'statemine', ['1', '2'], { registry } ); @@ -191,7 +191,7 @@ describe('SystemToPara XcmVersioned Generation', () => { mockSystemApi, ['100', '100'], 3, - 'statemint', + 'statemine', ['1', '2'], { registry } ); diff --git a/src/createXcmTypes/SystemToPara.ts b/src/createXcmTypes/SystemToPara.ts index 94c2d582..728c8e29 100644 --- a/src/createXcmTypes/SystemToPara.ts +++ b/src/createXcmTypes/SystemToPara.ts @@ -214,7 +214,6 @@ export const SystemToPara: ICreateXcmType = { paysWithFeeDest, multiAssets, specName, - systemChainId ); return api.registry.createType('u32', assetIndex); @@ -260,7 +259,7 @@ export const createSystemToParaMultiAssets = ( if (!isRelayNative && isNotANumber) { - assetId = getSystemChainTokenSymbolGeneralIndex(assetId, specName, systemChainId); + assetId = getSystemChainTokenSymbolGeneralIndex(assetId, specName); } const interior: MultiAssetInterior = isRelayNative diff --git a/src/createXcmTypes/SystemToSystem.ts b/src/createXcmTypes/SystemToSystem.ts index a2e1ceee..bdd160a2 100644 --- a/src/createXcmTypes/SystemToSystem.ts +++ b/src/createXcmTypes/SystemToSystem.ts @@ -217,7 +217,6 @@ export const SystemToSystem: ICreateXcmType = { paysWithFeeDest, multiAssets, specName, - systemChainId ); return api.registry.createType('u32', assetIndex); @@ -263,7 +262,7 @@ export const createSystemToSystemMultiAssets = ( const isRelayNative = isRelayNativeAsset(tokens, assetId); if (!isRelayNative && isNotANumber) { - assetId = getSystemChainTokenSymbolGeneralIndex(assetId, specName, systemChainId); + assetId = getSystemChainTokenSymbolGeneralIndex(assetId, specName); } const interior: MultiAssetInterior = isRelayNative diff --git a/src/createXcmTypes/util/getTokenSymbolGeneralIndex.spec.ts b/src/createXcmTypes/util/getTokenSymbolGeneralIndex.spec.ts index 74eb9664..1748277d 100644 --- a/src/createXcmTypes/util/getTokenSymbolGeneralIndex.spec.ts +++ b/src/createXcmTypes/util/getTokenSymbolGeneralIndex.spec.ts @@ -6,14 +6,14 @@ describe('getSystemChainTokenSymbolGeneralIndex', () => { it('Should successfully return the general index when given a valid native system chain token symbol', () => { const expected = '1337'; - const result = getSystemChainTokenSymbolGeneralIndex('USDC', 'polkadot', '1000'); + const result = getSystemChainTokenSymbolGeneralIndex('USDC', 'statemint'); expect(result).toEqual(expected); }); it('Should error when an asset id symbol is given that is not present in the registry', () => { const err = () => - getSystemChainTokenSymbolGeneralIndex('NOTUSDT', 'polkadot', '1000'); + getSystemChainTokenSymbolGeneralIndex('NOTUSDT', 'statemint'); expect(err).toThrow('general index for assetId NOTUSDT was not found'); }); diff --git a/src/createXcmTypes/util/getTokenSymbolGeneralIndex.ts b/src/createXcmTypes/util/getTokenSymbolGeneralIndex.ts index 2f314051..3f30de11 100644 --- a/src/createXcmTypes/util/getTokenSymbolGeneralIndex.ts +++ b/src/createXcmTypes/util/getTokenSymbolGeneralIndex.ts @@ -1,7 +1,9 @@ // Copyright 2023 Parity Technologies (UK) Ltd. import { BaseError } from '../../errors'; -import { findRelayChain, parseRegistry } from '../../registry'; +import { Registry } from '../../registry'; +import { SYSTEM_PARACHAINS_IDS } from '../../consts'; +import { getChainIdBySpecName } from './getChainIdBySpecName'; /** * Returns the correct asset index for a valid system chain token symbol @@ -13,11 +15,16 @@ import { findRelayChain, parseRegistry } from '../../registry'; export const getSystemChainTokenSymbolGeneralIndex = ( tokenSymbol: string, specName: string, - systemChainId: string, ): string => { - const registry = parseRegistry({}); - const relayChain = findRelayChain(specName, registry); - const { assetsInfo } = registry[relayChain][systemChainId]; + const newRegistry = new Registry(specName, {}); + + const systemChainId = getChainIdBySpecName(newRegistry, specName); + + if (!SYSTEM_PARACHAINS_IDS.includes(systemChainId)) { + throw new BaseError(`specName ${specName} did not match a valid system chain ID. Found ID ${systemChainId}`); + } + + const { assetsInfo } = newRegistry.currentRelayRegistry[systemChainId]; if (Object.keys(assetsInfo).length === 0) { throw new BaseError(`${specName} has no associated token symbol ${tokenSymbol}`); diff --git a/src/index.ts b/src/index.ts index e32a3b95..35e7ae3a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -69,14 +69,14 @@ const main = async () => { const payload = await assetTransferApi.createTransferTransaction( '1000', 'GxshYjshWQkCLtCWwtW5os6tM3qvo6ozziDXG9KbqpHNVfZ', - ['usdt', 'usdc'], - ['5000000', '4000000000'], + ['usdt'], + ['100000'], { format: 'payload', isLimited: true, - xcmVersion: 3, + // xcmVersion: 3, paysWithFeeOrigin: '1984', - paysWithFeeDest: 'USDC' + // paysWithFeeDest: 'USDC' } ); diff --git a/src/integrationTests/AssetsTransferApi.spec.ts b/src/integrationTests/AssetsTransferApi.spec.ts index 1fa3198d..6354a499 100644 --- a/src/integrationTests/AssetsTransferApi.spec.ts +++ b/src/integrationTests/AssetsTransferApi.spec.ts @@ -28,11 +28,11 @@ describe('AssetTransferApi Integration Tests', () => { expect(res).toEqual({ dest: 'statemine', origin: 'statemine', - direction: 'local', + direction: 'SystemToSystem', format: 'call', - method: 'assets::transfer', - tx: '0x3208040078b39b0b6dd87cb68009eb570511d21c229bdb5e94129ae570e9b79442ba26659101', - xcmVersion: null, + method: 'reserveTransferAssets', + tx: '0x1f0201010100a10f010001010078b39b0b6dd87cb68009eb570511d21c229bdb5e94129ae570e9b79442ba266501040000020432050400910100000000', + xcmVersion: 2, }); }); it('Should construct a `assets::transferKeepAlive` call on a system parachain', async () => { @@ -49,11 +49,11 @@ describe('AssetTransferApi Integration Tests', () => { expect(res).toEqual({ dest: 'statemine', origin: 'statemine', - direction: 'local', + direction: 'SystemToSystem', format: 'call', - method: 'assets::transferKeepAlive', - tx: '0x3209040078b39b0b6dd87cb68009eb570511d21c229bdb5e94129ae570e9b79442ba26659101', - xcmVersion: null, + method: 'reserveTransferAssets', + tx: '0x1f0201010100a10f010001010078b39b0b6dd87cb68009eb570511d21c229bdb5e94129ae570e9b79442ba266501040000020432050400910100000000', + xcmVersion: 2, }); }); it('Should construct a `balances::transfer` call on a system parachain', async () => { @@ -69,11 +69,11 @@ describe('AssetTransferApi Integration Tests', () => { expect(res).toEqual({ dest: 'statemine', origin: 'statemine', - direction: 'local', + direction: 'SystemToSystem', format: 'call', - method: 'balances::transfer', - tx: '0x0a070078b39b0b6dd87cb68009eb570511d21c229bdb5e94129ae570e9b79442ba26659101', - xcmVersion: null, + method: 'reserveTransferAssets', + tx: '0x1f0201010100a10f010001010078b39b0b6dd87cb68009eb570511d21c229bdb5e94129ae570e9b79442ba2665010400010000910100000000', + xcmVersion: 2, }); }); it('Should construct a `balances::transferKeepAlive` call on a system parachain', async () => { @@ -90,11 +90,11 @@ describe('AssetTransferApi Integration Tests', () => { expect(res).toEqual({ dest: 'statemine', origin: 'statemine', - direction: 'local', + direction: 'SystemToSystem', format: 'call', - method: 'balances::transferKeepAlive', - tx: '0x0a030078b39b0b6dd87cb68009eb570511d21c229bdb5e94129ae570e9b79442ba26659101', - xcmVersion: null, + method: 'reserveTransferAssets', + tx: '0x1f0201010100a10f010001010078b39b0b6dd87cb68009eb570511d21c229bdb5e94129ae570e9b79442ba2665010400010000910100000000', + xcmVersion: 2, }); }); it('Should construct a `balances::transfer` call on a relay chain', async () => { @@ -811,8 +811,8 @@ describe('AssetTransferApi Integration Tests', () => { describe('checkLocalTxInput', () => { it('Should error when the assetIds or amounts is the incorrect length', async () => { await expect(async () => { - await systemAssetsApi.createTransferTransaction( - '1000', + await relayAssetsApi.createTransferTransaction( + '0', '5EnxxUmEbw8DkENKiYuZ1DwQuMoB2UWEQJZZXrTsxoz7SpgG', ['1', '2'], ['100', '100'] diff --git a/src/registry/Registry.spec.ts b/src/registry/Registry.spec.ts index b75021de..a237f918 100644 --- a/src/registry/Registry.spec.ts +++ b/src/registry/Registry.spec.ts @@ -36,7 +36,6 @@ describe('Registry', () => { '11': 'web3', '21': 'WBTC', '77': 'TRQ', - '99': 'Cypress', '100': 'WETH', '101': 'DOTMA', '123': '123', diff --git a/src/util/getFeeAssetItemIndex.spec.ts b/src/util/getFeeAssetItemIndex.spec.ts index 7e4cf688..f2d6ea27 100644 --- a/src/util/getFeeAssetItemIndex.spec.ts +++ b/src/util/getFeeAssetItemIndex.spec.ts @@ -7,15 +7,16 @@ type Test = [ paysWithFeeDest: string, specName: string, multiAssets: MultiAsset[], - expected: number + expected: number, ]; describe('getFeeAssetItemIndex', () => { it('Should select and return the index of the correct multiassets when given their token symbols', () => { + const tests: Test[] = [ [ 'usdt', - 'polkadot', + 'statemint', [ { id: { @@ -46,7 +47,7 @@ describe('getFeeAssetItemIndex', () => { ], [ 'USDC', - 'kusama', + 'statemine', [ { id: { @@ -202,7 +203,7 @@ describe('getFeeAssetItemIndex', () => { it('Should throw an error indicating the general index was not found for an invalid paysWithFeeDest value', () => { const paysWithFeeDest = 'xcUSDT'; - const specName = 'polkadot'; + const specName = 'statemint'; const multiAssets: MultiAsset[] = [ { diff --git a/src/util/getFeeAssetItemIndex.ts b/src/util/getFeeAssetItemIndex.ts index b15247e6..a73df696 100644 --- a/src/util/getFeeAssetItemIndex.ts +++ b/src/util/getFeeAssetItemIndex.ts @@ -16,7 +16,6 @@ export const getFeeAssetItemIndex = ( paysWithFeeDest: string, multiAssets: MultiAsset[], specName: string, - systemChainId?: string ): number => { let result = 0; @@ -43,9 +42,9 @@ export const getFeeAssetItemIndex = ( // if not a number, get the general index of the pays with fee asset // to compare against the current multi asset - if (isNotANumber && systemChainId) { + if (isNotANumber) { const paysWithFeeDestGeneralIndex = - getSystemChainTokenSymbolGeneralIndex(paysWithFeeDest, specName, systemChainId); + getSystemChainTokenSymbolGeneralIndex(paysWithFeeDest, specName); if ( (multiAsset.id.Concrete.interior as NonRelayNativeInterior).X2 && (multiAsset.id.Concrete.interior as NonRelayNativeInterior).X2[1] From 674852707a13cd063421c9671e65922497013bf0 Mon Sep 17 00:00:00 2001 From: marshacb Date: Fri, 23 Jun 2023 21:03:34 -0400 Subject: [PATCH 03/55] update createTransferTransaction --- src/AssetsTransferApi.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/AssetsTransferApi.ts b/src/AssetsTransferApi.ts index 4fe7af05..c96e07e9 100644 --- a/src/AssetsTransferApi.ts +++ b/src/AssetsTransferApi.ts @@ -101,10 +101,10 @@ export class AssetsTransferApi { checkBaseInputTypes(destChainId, destAddr, assetIds, amounts); const { _api, _specName, _safeXcmVersion, registry } = this; - // const isOriginSystemParachain = SYSTEM_PARACHAINS_NAMES.includes( - // _specName.toLowerCase() - // ); - // const isDestSystemParachain = SYSTEM_PARACHAINS_IDS.includes(destChainId); + const isOriginSystemParachain = SYSTEM_PARACHAINS_NAMES.includes( + _specName.toLowerCase() + ); + const isDestSystemParachain = SYSTEM_PARACHAINS_IDS.includes(destChainId); /** * Sanitize the address to a hex, and ensure that the passed in SS58, or publickey @@ -113,7 +113,7 @@ export class AssetsTransferApi { const addr = sanitizeAddress(destAddr); const originChainId = getChainIdBySpecName(registry, _specName); - const isLocalSystemTx = originChainId === destChainId; + const isLocalSystemTx = (isOriginSystemParachain && isDestSystemParachain && originChainId === destChainId) const isLocalRelayTx = destChainId === '0' && RELAY_CHAIN_NAMES.includes(_specName.toLowerCase()); From 590257c8c29da3d03b6da16f7cca9de23855ea94 Mon Sep 17 00:00:00 2001 From: marshacb Date: Mon, 26 Jun 2023 12:56:51 -0400 Subject: [PATCH 04/55] update system to system to check palletInstance only if not relay native in order to allow system chains without assets pallet to create native asset xcm transfers --- src/AssetsTransferApi.ts | 45 +++++++++++++++---- src/consts.ts | 2 +- src/createCalls/assets/transfer.ts | 1 + src/createXcmTypes/SystemToSystem.spec.ts | 2 +- src/createXcmTypes/SystemToSystem.ts | 11 +++-- src/errors/checkLocalTxInputs.spec.ts | 17 +++---- src/errors/checkLocalTxInputs.ts | 31 +++++++------ src/index.ts | 12 ++--- .../AssetsTransferApi.spec.ts | 32 ++++++------- src/types.ts | 12 +++-- 10 files changed, 106 insertions(+), 59 deletions(-) diff --git a/src/AssetsTransferApi.ts b/src/AssetsTransferApi.ts index c96e07e9..cc588f05 100644 --- a/src/AssetsTransferApi.ts +++ b/src/AssetsTransferApi.ts @@ -47,6 +47,7 @@ import { UnsignedTransaction, } from './types'; import { getChainIdBySpecName } from './createXcmTypes/util/getChainIdBySpecName'; +import { getSystemChainTokenSymbolGeneralIndex } from './createXcmTypes/util/getTokenSymbolGeneralIndex'; /** * Holds open an api connection to a specified chain within the ApiPromise in order to help @@ -113,20 +114,42 @@ export class AssetsTransferApi { const addr = sanitizeAddress(destAddr); const originChainId = getChainIdBySpecName(registry, _specName); + console.log('SPECNAME IS', _specName); + console.log('ORIGIN CHAIN ID', originChainId); + console.log('DEST CHAIN ID', destChainId); const isLocalSystemTx = (isOriginSystemParachain && isDestSystemParachain && originChainId === destChainId) + console.log('IS LOCAL SYSTEM TX?', isLocalSystemTx); const isLocalRelayTx = destChainId === '0' && RELAY_CHAIN_NAMES.includes(_specName.toLowerCase()); + + const xcmDirection = this.establishDirection(destChainId, _specName); /** * Create a local asset transfer on a system parachain */ if (isLocalSystemTx || isLocalRelayTx) { + let assetId = assetIds[0]; + const amount = amounts[0]; + const systemChainId = getChainIdBySpecName(registry, _specName); + const localAssetIdIsNotANumber = Number.isNaN(parseInt(assetId)); + + if ( + xcmDirection === 'SystemToSystem' && + localAssetIdIsNotANumber && + assetIds.length !== 0 && + !registry.currentRelayRegistry[ + systemChainId + ].tokens.includes(assetId.toUpperCase()) + ) { + assetId = getSystemChainTokenSymbolGeneralIndex(assetId, _specName); + } /** * This will throw a BaseError if the inputs are incorrect and don't * fit the constraints for creating a local asset transfer. */ - const localAssetType = checkLocalTxInput(assetIds, amounts, registry); // Throws an error when any of the inputs are incorrect. + const localAssetType = checkLocalTxInput(assetIds, amounts, _specName, registry); // Throws an error when any of the inputs are incorrect. const method = opts?.keepAlive ? 'transferKeepAlive' : 'transfer'; + if (isLocalSystemTx) { let tx: SubmittableExtrinsic<'promise', ISubmittableResult>; let palletMethod: LocalTransferTypes; @@ -136,14 +159,14 @@ export class AssetsTransferApi { if (localAssetType === 'Balances') { tx = method === 'transferKeepAlive' - ? balances.transferKeepAlive(_api, addr, amounts[0]) - : balances.transfer(_api, addr, amounts[0]); + ? balances.transferKeepAlive(_api, addr, amount) + : balances.transfer(_api, addr, amount); palletMethod = `balances::${method}`; } else { tx = method === 'transferKeepAlive' - ? assets.transferKeepAlive(_api, addr, assetIds[0], amounts[0]) - : assets.transfer(_api, addr, assetIds[0], amounts[0]); + ? assets.transferKeepAlive(_api, addr, assetId, amount) + : assets.transfer(_api, addr, assetId, amount); palletMethod = `assets::${method}`; } @@ -164,8 +187,8 @@ export class AssetsTransferApi { const palletMethod: LocalTransferTypes = `balances::${method}`; const tx = method === 'transferKeepAlive' - ? balances.transferKeepAlive(_api, addr, amounts[0]) - : balances.transfer(_api, addr, amounts[0]); + ? balances.transferKeepAlive(_api, addr, amount) + : balances.transfer(_api, addr, amount); return this.constructFormat( tx, 'local', @@ -179,7 +202,6 @@ export class AssetsTransferApi { } } - const xcmDirection = this.establishDirection(destChainId, _specName); const xcmVersion = opts?.xcmVersion === undefined ? _safeXcmVersion : opts.xcmVersion; checkXcmVersion(xcmVersion); // Throws an error when the xcmVersion is not supported. @@ -534,10 +556,15 @@ export class AssetsTransferApi { } const submittableString = JSON.stringify(tx.toHuman()); + console.log('WHAT IS SUBMITTABLE STRING', submittableString); const submittableData: SubmittableMethodData = JSON.parse( submittableString ) as unknown as SubmittableMethodData; - const addr = submittableData.method.args.dest.id; + + const addr: string = submittableData.method.args.target ? + submittableData.method.args.target?.Id : + ''; + const lastHeader = await this._api.rpc.chain.getHeader(); const blockNumber = this._api.registry.createType( 'BlockNumber', diff --git a/src/consts.ts b/src/consts.ts index 53ea5453..37834868 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -12,7 +12,7 @@ export const RELAY_CHAIN_IDS = ['0']; /** * List of all known system parachains. */ -export const SYSTEM_PARACHAINS_NAMES = ['statemine', 'statemint', 'westmint']; +export const SYSTEM_PARACHAINS_NAMES = ['statemine', 'statemint', 'westmint', 'bridge-hub-kusama']; /** * List of IDs for assets and bridge hub system parachains. */ diff --git a/src/createCalls/assets/transfer.ts b/src/createCalls/assets/transfer.ts index ec44779b..c1f360d0 100644 --- a/src/createCalls/assets/transfer.ts +++ b/src/createCalls/assets/transfer.ts @@ -10,5 +10,6 @@ export const transfer = ( assetId: string, amount: string ): SubmittableExtrinsic<'promise', ISubmittableResult> => { + console.log('WHAT IS THE ASSET ID IN TRANSFER', assetId); return api.tx.assets.transfer(assetId, destAddr, amount); }; diff --git a/src/createXcmTypes/SystemToSystem.spec.ts b/src/createXcmTypes/SystemToSystem.spec.ts index 2353e6e7..4ff21499 100644 --- a/src/createXcmTypes/SystemToSystem.spec.ts +++ b/src/createXcmTypes/SystemToSystem.spec.ts @@ -156,7 +156,7 @@ describe('SystemToSystem XcmVersioned Generation', () => { expect(assets.toJSON()).toStrictEqual(expectedRes); }); - it('Should error when system chain ID is not found for V3', () => { + it('Should error when asset ID is not found for V3', () => { const expectedErrorMessage = 'bridge-hub-kusama has no associated token symbol usdc'; const err = () => SystemToSystem.createAssets( diff --git a/src/createXcmTypes/SystemToSystem.ts b/src/createXcmTypes/SystemToSystem.ts index bdd160a2..cc205748 100644 --- a/src/createXcmTypes/SystemToSystem.ts +++ b/src/createXcmTypes/SystemToSystem.ts @@ -242,7 +242,7 @@ export const createSystemToSystemMultiAssets = ( assets: string[], registry: Registry, ): MultiAsset[] => { - const palletId = fetchPalletInstanceId(api); + let palletId: string | undefined = undefined; let multiAssets = []; const systemChainId = getChainIdBySpecName(registry, specName); @@ -261,8 +261,13 @@ export const createSystemToSystemMultiAssets = ( const isNotANumber = Number.isNaN(parsedAssetIdAsNumber); const isRelayNative = isRelayNativeAsset(tokens, assetId); - if (!isRelayNative && isNotANumber) { - assetId = getSystemChainTokenSymbolGeneralIndex(assetId, specName); + + if (!isRelayNative) { + palletId = fetchPalletInstanceId(api); + + if (isNotANumber) { + assetId = getSystemChainTokenSymbolGeneralIndex(assetId, specName); + } } const interior: MultiAssetInterior = isRelayNative diff --git a/src/errors/checkLocalTxInputs.spec.ts b/src/errors/checkLocalTxInputs.spec.ts index 465c6276..f21d1ced 100644 --- a/src/errors/checkLocalTxInputs.spec.ts +++ b/src/errors/checkLocalTxInputs.spec.ts @@ -5,39 +5,40 @@ import { checkLocalTxInput } from './checkLocalTxInputs'; describe('checkLocalTxInput', () => { const registry = new Registry('statemine', {}); + const specName = 'statemine'; it('Should correctly return Balances with an empty assetIds', () => { - const res = checkLocalTxInput([], ['10000'], registry); + const res = checkLocalTxInput([], ['10000'], specName, registry); expect(res).toEqual('Balances'); }); it('Should correctly return Balances with a native token', () => { - const res = checkLocalTxInput(['KSM'], ['10000'], registry); + const res = checkLocalTxInput(['KSM'], ['10000'], specName, registry); expect(res).toEqual('Balances'); }); it('Should correctly return Assets with a valid assetId', () => { - const res = checkLocalTxInput(['1984'], ['10000'], registry); + const res = checkLocalTxInput(['1984'], ['10000'], specName, registry); expect(res).toEqual('Assets'); }); it('Should correctly throw an error for incorrect length on `assetIds`', () => { - const err = () => checkLocalTxInput(['1', '2'], ['10000'], registry); + const err = () => checkLocalTxInput(['1', '2'], ['10000'], specName, registry); expect(err).toThrowError( 'Local transactions must have the `assetIds` input be a length of 1 or 0, and the `amounts` input be a length of 1' ); }); it('Should correctly throw an error for incorrect length on `amounts`', () => { - const err = () => checkLocalTxInput(['1'], ['10000', '20000'], registry); + const err = () => checkLocalTxInput(['1'], ['10000', '20000'], specName, registry); expect(err).toThrowError( 'Local transactions must have the `assetIds` input be a length of 1 or 0, and the `amounts` input be a length of 1' ); }); it('Should correctly throw an error with an incorrect assetId', () => { - const err = () => checkLocalTxInput(['TST'], ['10000'], registry); + const err = () => checkLocalTxInput(['TST'], ['10000'], specName, registry); expect(err).toThrowError( - 'The assetId passed in is not a valid number: TST' + 'general index for assetId TST was not found' ); }); it("Should correctly throw an error when the assetId doesn't exist", () => { - const err = () => checkLocalTxInput(['9876111'], ['10000'], registry); + const err = () => checkLocalTxInput(['9876111'], ['10000'], specName, registry); expect(err).toThrowError( 'The assetId 9876111 does not exist in the registry.' ); diff --git a/src/errors/checkLocalTxInputs.ts b/src/errors/checkLocalTxInputs.ts index 4ce4605c..23a48a69 100644 --- a/src/errors/checkLocalTxInputs.ts +++ b/src/errors/checkLocalTxInputs.ts @@ -1,8 +1,9 @@ // Copyright 2023 Parity Technologies (UK) Ltd. -import { SYSTEM_PARACHAINS_IDS } from '../consts'; import { Registry } from '../registry'; import { BaseError } from './BaseError'; +import { getSystemChainTokenSymbolGeneralIndex } from '../createXcmTypes/util/getTokenSymbolGeneralIndex'; +import { getChainIdBySpecName } from '../createXcmTypes/util/getChainIdBySpecName'; enum LocalTxType { Assets = 'Assets', @@ -19,10 +20,12 @@ enum LocalTxType { export const checkLocalTxInput = ( assetIds: string[], amounts: string[], + specName: string, registry: Registry ): LocalTxType => { const relayChainInfo = registry.currentRelayRegistry; - const systemParachainInfo = relayChainInfo[SYSTEM_PARACHAINS_IDS[0]]; + const systemChainId = getChainIdBySpecName(registry, specName); + const systemParachainInfo = relayChainInfo[systemChainId]; // Ensure the lengths in assetIds and amounts is correct if (assetIds.length > 1 || amounts.length !== 1) { @@ -38,25 +41,27 @@ export const checkLocalTxInput = ( return LocalTxType.Balances; } - const isNativeToken = relayChainInfo[ - SYSTEM_PARACHAINS_IDS[0] - ].tokens.includes(assetIds[0]); - if (isNativeToken) { + let assetId = assetIds[0]; + + const isNativeToken = systemParachainInfo.tokens.find((token) => token.toLowerCase() === assetId.toLowerCase()); + if (isNativeToken !== undefined) { return LocalTxType.Balances; } else { - const isInvalidAssetId = Number.isNaN(parseInt(assetIds[0])); - if (isInvalidAssetId) { - throw new BaseError( - `The assetId passed in is not a valid number: ${assetIds[0]}` - ); + const isNotANumber = Number.isNaN(parseInt(assetId)); + if (isNotANumber) { + assetId = getSystemChainTokenSymbolGeneralIndex(assetId, specName); + console.log('WHAT IS THE ASSET ID', assetId); + // throw new BaseError( + // `The assetId passed in is not a valid number: ${assetId}` + // ); } const isAssetAvailable = Object.keys( systemParachainInfo.assetsInfo - ).includes(assetIds[0]); + ).find((asset) => asset.toLowerCase() === assetId.toLowerCase()); if (!isAssetAvailable) { throw new BaseError( - `The assetId ${assetIds[0]} does not exist in the registry.` + `The assetId ${assetId} does not exist in the registry.` ); } diff --git a/src/index.ts b/src/index.ts index 35e7ae3a..85b161b8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,12 +22,14 @@ import { AssetsTransferApi } from './AssetsTransferApi'; // }; const main = async () => { - const provider = new WsProvider('wss://statemine-rpc.polkadot.io'); + // const specName = 'bridge-hub-kusama'; + // const specname = 'statemine'; + const provider = new WsProvider(`wss://kusama-bridge-hub-rpc.polkadot.io`); const api = await ApiPromise.create({ provider }); await api.isReady; - const assetTransferApi = new AssetsTransferApi(api, 'statemine', 2); + const assetTransferApi = new AssetsTransferApi(api, 'bridge-hub-kusama', 2); // call // const call = await assetTransferApi.createTransferTransaction( @@ -69,13 +71,13 @@ const main = async () => { const payload = await assetTransferApi.createTransferTransaction( '1000', 'GxshYjshWQkCLtCWwtW5os6tM3qvo6ozziDXG9KbqpHNVfZ', - ['usdt'], + ['ksm'], ['100000'], { format: 'payload', isLimited: true, - // xcmVersion: 3, - paysWithFeeOrigin: '1984', + xcmVersion: 2, + // paysWithFeeOrigin: '1984', // paysWithFeeDest: 'USDC' } ); diff --git a/src/integrationTests/AssetsTransferApi.spec.ts b/src/integrationTests/AssetsTransferApi.spec.ts index 6354a499..6535ca6e 100644 --- a/src/integrationTests/AssetsTransferApi.spec.ts +++ b/src/integrationTests/AssetsTransferApi.spec.ts @@ -28,11 +28,11 @@ describe('AssetTransferApi Integration Tests', () => { expect(res).toEqual({ dest: 'statemine', origin: 'statemine', - direction: 'SystemToSystem', + direction: 'local', format: 'call', - method: 'reserveTransferAssets', - tx: '0x1f0201010100a10f010001010078b39b0b6dd87cb68009eb570511d21c229bdb5e94129ae570e9b79442ba266501040000020432050400910100000000', - xcmVersion: 2, + method: 'assets::transfer', + tx: '0x3208040078b39b0b6dd87cb68009eb570511d21c229bdb5e94129ae570e9b79442ba26659101', + xcmVersion: null, }); }); it('Should construct a `assets::transferKeepAlive` call on a system parachain', async () => { @@ -49,11 +49,11 @@ describe('AssetTransferApi Integration Tests', () => { expect(res).toEqual({ dest: 'statemine', origin: 'statemine', - direction: 'SystemToSystem', + direction: 'local', format: 'call', - method: 'reserveTransferAssets', - tx: '0x1f0201010100a10f010001010078b39b0b6dd87cb68009eb570511d21c229bdb5e94129ae570e9b79442ba266501040000020432050400910100000000', - xcmVersion: 2, + method: 'assets::transferKeepAlive', + tx: '0x3209040078b39b0b6dd87cb68009eb570511d21c229bdb5e94129ae570e9b79442ba26659101', + xcmVersion: null, }); }); it('Should construct a `balances::transfer` call on a system parachain', async () => { @@ -69,11 +69,11 @@ describe('AssetTransferApi Integration Tests', () => { expect(res).toEqual({ dest: 'statemine', origin: 'statemine', - direction: 'SystemToSystem', + direction: 'local', format: 'call', - method: 'reserveTransferAssets', - tx: '0x1f0201010100a10f010001010078b39b0b6dd87cb68009eb570511d21c229bdb5e94129ae570e9b79442ba2665010400010000910100000000', - xcmVersion: 2, + method: 'balances::transfer', + tx: '0x0a070078b39b0b6dd87cb68009eb570511d21c229bdb5e94129ae570e9b79442ba26659101', + xcmVersion: null, }); }); it('Should construct a `balances::transferKeepAlive` call on a system parachain', async () => { @@ -90,11 +90,11 @@ describe('AssetTransferApi Integration Tests', () => { expect(res).toEqual({ dest: 'statemine', origin: 'statemine', - direction: 'SystemToSystem', + direction: 'local', format: 'call', - method: 'reserveTransferAssets', - tx: '0x1f0201010100a10f010001010078b39b0b6dd87cb68009eb570511d21c229bdb5e94129ae570e9b79442ba2665010400010000910100000000', - xcmVersion: 2, + method: 'balances::transferKeepAlive', + tx: '0x0a030078b39b0b6dd87cb68009eb570511d21c229bdb5e94129ae570e9b79442ba26659101', + xcmVersion: null, }); }); it('Should construct a `balances::transfer` call on a relay chain', async () => { diff --git a/src/types.ts b/src/types.ts index 6d077540..6ae29210 100644 --- a/src/types.ts +++ b/src/types.ts @@ -193,7 +193,7 @@ export interface ChainInfo { } export type NonRelayNativeInterior = { - X2: [{ PalletInstance: string }, { GeneralIndex: string }]; + X2: [{ PalletInstance: string | undefined }, { GeneralIndex: string }]; }; export type RelayNativeInterior = { @@ -286,9 +286,15 @@ export interface Dest { id: string; } +export interface Target { + Id: string; +} + export interface Args { - dest: Dest; - value: u32; + id?: string; + target?: Target + dest?: Dest; + value?: u32; } export interface Method { From 5bfcbb361ee970b091361ee26a9414f9ddf7df6b Mon Sep 17 00:00:00 2001 From: marshacb Date: Mon, 26 Jun 2023 12:59:20 -0400 Subject: [PATCH 05/55] remove console logs --- src/AssetsTransferApi.ts | 5 ----- src/createCalls/assets/transfer.ts | 1 - src/createXcmTypes/SystemToSystem.spec.ts | 2 -- src/errors/checkLocalTxInputs.ts | 4 ---- 4 files changed, 12 deletions(-) diff --git a/src/AssetsTransferApi.ts b/src/AssetsTransferApi.ts index cc588f05..5e35b1b7 100644 --- a/src/AssetsTransferApi.ts +++ b/src/AssetsTransferApi.ts @@ -114,11 +114,7 @@ export class AssetsTransferApi { const addr = sanitizeAddress(destAddr); const originChainId = getChainIdBySpecName(registry, _specName); - console.log('SPECNAME IS', _specName); - console.log('ORIGIN CHAIN ID', originChainId); - console.log('DEST CHAIN ID', destChainId); const isLocalSystemTx = (isOriginSystemParachain && isDestSystemParachain && originChainId === destChainId) - console.log('IS LOCAL SYSTEM TX?', isLocalSystemTx); const isLocalRelayTx = destChainId === '0' && RELAY_CHAIN_NAMES.includes(_specName.toLowerCase()); @@ -556,7 +552,6 @@ export class AssetsTransferApi { } const submittableString = JSON.stringify(tx.toHuman()); - console.log('WHAT IS SUBMITTABLE STRING', submittableString); const submittableData: SubmittableMethodData = JSON.parse( submittableString ) as unknown as SubmittableMethodData; diff --git a/src/createCalls/assets/transfer.ts b/src/createCalls/assets/transfer.ts index c1f360d0..ec44779b 100644 --- a/src/createCalls/assets/transfer.ts +++ b/src/createCalls/assets/transfer.ts @@ -10,6 +10,5 @@ export const transfer = ( assetId: string, amount: string ): SubmittableExtrinsic<'promise', ISubmittableResult> => { - console.log('WHAT IS THE ASSET ID IN TRANSFER', assetId); return api.tx.assets.transfer(assetId, destAddr, amount); }; diff --git a/src/createXcmTypes/SystemToSystem.spec.ts b/src/createXcmTypes/SystemToSystem.spec.ts index 4ff21499..7b0cfc03 100644 --- a/src/createXcmTypes/SystemToSystem.spec.ts +++ b/src/createXcmTypes/SystemToSystem.spec.ts @@ -151,8 +151,6 @@ describe('SystemToSystem XcmVersioned Generation', () => { ], }; - console.log('ASSETS TO JSON', assets.toJSON()); - expect(assets.toJSON()).toStrictEqual(expectedRes); }); diff --git a/src/errors/checkLocalTxInputs.ts b/src/errors/checkLocalTxInputs.ts index 23a48a69..1864628c 100644 --- a/src/errors/checkLocalTxInputs.ts +++ b/src/errors/checkLocalTxInputs.ts @@ -50,10 +50,6 @@ export const checkLocalTxInput = ( const isNotANumber = Number.isNaN(parseInt(assetId)); if (isNotANumber) { assetId = getSystemChainTokenSymbolGeneralIndex(assetId, specName); - console.log('WHAT IS THE ASSET ID', assetId); - // throw new BaseError( - // `The assetId passed in is not a valid number: ${assetId}` - // ); } const isAssetAvailable = Object.keys( From 1a1d9ce3d0c9c860a8f2a8b986d4e70a1e5a2d71 Mon Sep 17 00:00:00 2001 From: marshacb Date: Tue, 27 Jun 2023 18:28:50 -0400 Subject: [PATCH 06/55] update Native direction to include SystemToSystem --- src/AssetsTransferApi.ts | 2 +- src/consts.ts | 4 +- src/index.ts | 123 --------------------------------------- 3 files changed, 3 insertions(+), 126 deletions(-) diff --git a/src/AssetsTransferApi.ts b/src/AssetsTransferApi.ts index 5e35b1b7..e6111056 100644 --- a/src/AssetsTransferApi.ts +++ b/src/AssetsTransferApi.ts @@ -453,7 +453,7 @@ export class AssetsTransferApi { } private fetchAssetType(xcmDirection: Direction): AssetType { - if (xcmDirection === 'RelayToSystem' || xcmDirection === 'SystemToRelay') { + if (xcmDirection === 'RelayToSystem' || xcmDirection === 'SystemToRelay' || xcmDirection === 'SystemToSystem') { return AssetType.Native; } diff --git a/src/consts.ts b/src/consts.ts index 37834868..294b91a9 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -12,11 +12,11 @@ export const RELAY_CHAIN_IDS = ['0']; /** * List of all known system parachains. */ -export const SYSTEM_PARACHAINS_NAMES = ['statemine', 'statemint', 'westmint', 'bridge-hub-kusama']; +export const SYSTEM_PARACHAINS_NAMES = ['statemine', 'statemint', 'westmint', 'bridge-hub-kusama', 'bridge-hub-polkadot', 'encointer-parachain', 'collectives']; /** * List of IDs for assets and bridge hub system parachains. */ -export const SYSTEM_PARACHAINS_IDS = ['1000', '1002']; +export const SYSTEM_PARACHAINS_IDS = ['1000', '1001', '1002']; /** * The default xcm version to construct a xcm message. */ diff --git a/src/index.ts b/src/index.ts index 85b161b8..a3b36094 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,126 +3,3 @@ export * from './AssetsTransferApi'; export * from './constructApiPromise'; export * from './types'; - -// import { VersionedMultiLocation } from '@capi/polkadot/types/xcm/mod'; -import { ApiPromise, WsProvider } from '@polkadot/api'; - -import { AssetsTransferApi } from './AssetsTransferApi'; - -// type DecodedExtrinsic = { -// callIndex: string; -// args: XCMInfo; -// }; - -// type XCMInfo = { -// dest: VersionedMultiLocation; -// benificiary: VersionedMultiLocation; -// assets: VersionedMultiLocation; -// fee_asset_item: string; -// }; - -const main = async () => { - // const specName = 'bridge-hub-kusama'; - // const specname = 'statemine'; - const provider = new WsProvider(`wss://kusama-bridge-hub-rpc.polkadot.io`); - const api = await ApiPromise.create({ provider }); - - await api.isReady; - - const assetTransferApi = new AssetsTransferApi(api, 'bridge-hub-kusama', 2); - - // call - // const call = await assetTransferApi.createTransferTransaction( - // '2000', // destChainId - // '0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b', // destAddr - // ['ksm', '10', '34', '36', '11', '12'], // assetIds - // ['100', '2000', '300', '400', '500', '700'], // amounts - // { - // paysWithFeeDest: '10', - // xcmVersion: 3, - // format: 'call', - // keepAlive: true, - // } // opts - // ); - // console.log('call is', call); - // const callExtrinsic = api.registry.createType('Call', call.tx); - // console.log('call to human', callExtrinsic.toString()); - // const decoded1: DecodedExtrinsic = JSON.parse(callExtrinsic.toString()); - // console.log('decoded1', decoded1); - - // // payload - // const decoded = assetTransferApi.decodeExtrinsic(`0x95067b2263616c6c496e646578223a22307836333039222c2261726773223a7b2264657374223a7b227632223a7b22706172656e7473223a302c22696e746572696f72223a7b227831223a7b2270617261636861696e223a313030307d7d7d7d2c2262656e6566696369617279223a7b227632223a7b22706172656e7473223a302c22696e746572696f72223a7b227831223a7b226163636f756e7449643332223a7b226e6574776f726b223a7b22616e79223a6e756c6c7d2c226964223a22307863323234616164396336663362626437383431323065396663656565356266643232613632633639313434656536373366373664366133346432383064653136227d7d7d7d7d2c22617373657473223a7b227632223a5b7b226964223a7b22636f6e6372657465223a7b22706172656e7473223a302c22696e746572696f72223a7b2268657265223a6e756c6c7d7d7d2c2266756e223a7b2266756e6769626c65223a353030303030307d7d5d7d2c226665655f61737365745f6974656d223a302c227765696768745f6c696d6974223a7b22756e6c696d69746564223a6e756c6c7d7d7d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - // `, 'payload'); - // console.log('WHAT IS DECODED', decoded); - // const payload = await assetTransferApi.createTransferTransaction( - // '1000', // destChainId - // '0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b', // destAddr - // [], // assetIds - // ['100'], // amounts - // { - // format: 'payload', - // keepAlive: true, - // // paysWithFeeOrigin: '1984', - // } // opts - // ); - // console.log('payload is', payload); - - - const payload = await assetTransferApi.createTransferTransaction( - '1000', - 'GxshYjshWQkCLtCWwtW5os6tM3qvo6ozziDXG9KbqpHNVfZ', - ['ksm'], - ['100000'], - { - format: 'payload', - isLimited: true, - xcmVersion: 2, - // paysWithFeeOrigin: '1984', - // paysWithFeeDest: 'USDC' - } - ); - - console.log('payload', JSON.stringify(payload)); - - const decodedPayload = assetTransferApi.decodeExtrinsic(payload.tx, 'payload'); - console.log('decodedPayload', decodedPayload); - - const payloadExtrinsic = api.registry.createType( - 'ExtrinsicPayload', - payload.tx, - { - version: 4, - } - ); - - console.log( - 'payload method to string', - JSON.stringify(payloadExtrinsic.method.toHuman()) - ); - const payloadJSON = payloadExtrinsic.method.toJSON() as string; - console.log('payload json', payloadJSON); - // const decoded2: DecodedExtrinsic = JSON.parse(payloadJSON); - // console.log('decoded2', JSON.stringify(decoded2)); - - - - - // submittable - // const submittable = await assetTransferApi.createTransferTransaction( - // '0', // destChainId - // '0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b', // destAddr - // [], // assetIds - // ['50000000'], // amounts - // { - // format: 'submittable', - // keepAlive: true - // } // opts - // ); - - // console.log('submittable', submittable.direction); - // const call = api.registry.createType('Extrinsic', submittable.tx.toHex()); - // console.log('call is', call.method.toString()); -}; - - main(); - From 7300c22b8274c36984b383c708617985a14cf583 Mon Sep 17 00:00:00 2001 From: marshacb Date: Tue, 27 Jun 2023 18:42:47 -0400 Subject: [PATCH 07/55] update system to system general index check lint --- src/AssetsTransferApi.ts | 53 +++++++++++++------ src/consts.ts | 10 +++- src/createXcmTypes/SystemToPara.ts | 19 ++++--- src/createXcmTypes/SystemToSystem.spec.ts | 36 ++++++------- src/createXcmTypes/SystemToSystem.ts | 27 +++++----- src/createXcmTypes/index.ts | 2 +- .../util/getChainIdBySpecName.ts | 13 +++-- .../util/getTokenSymbolGeneralIndex.ts | 12 +++-- src/errors/checkLocalTxInputs.spec.ts | 13 ++--- src/errors/checkLocalTxInputs.ts | 16 +++--- src/types.ts | 2 +- src/util/getFeeAssetItemIndex.spec.ts | 3 +- src/util/getFeeAssetItemIndex.ts | 2 +- 13 files changed, 126 insertions(+), 82 deletions(-) diff --git a/src/AssetsTransferApi.ts b/src/AssetsTransferApi.ts index e6111056..504c8cfa 100644 --- a/src/AssetsTransferApi.ts +++ b/src/AssetsTransferApi.ts @@ -12,6 +12,7 @@ import type { import type { ISubmittableResult } from '@polkadot/types/types'; import { + RELAY_CHAIN_IDS, RELAY_CHAIN_NAMES, SYSTEM_PARACHAINS_IDS, SYSTEM_PARACHAINS_NAMES, @@ -24,6 +25,8 @@ import { reserveTransferAssets, teleportAssets, } from './createXcmCalls'; +import { getChainIdBySpecName } from './createXcmTypes/util/getChainIdBySpecName'; +import { getSystemChainTokenSymbolGeneralIndex } from './createXcmTypes/util/getTokenSymbolGeneralIndex'; import { BaseError, checkBaseInputTypes, @@ -46,8 +49,6 @@ import { TxResult, UnsignedTransaction, } from './types'; -import { getChainIdBySpecName } from './createXcmTypes/util/getChainIdBySpecName'; -import { getSystemChainTokenSymbolGeneralIndex } from './createXcmTypes/util/getTokenSymbolGeneralIndex'; /** * Holds open an api connection to a specified chain within the ApiPromise in order to help @@ -106,7 +107,7 @@ export class AssetsTransferApi { _specName.toLowerCase() ); const isDestSystemParachain = SYSTEM_PARACHAINS_IDS.includes(destChainId); - + /** * Sanitize the address to a hex, and ensure that the passed in SS58, or publickey * is validated correctly. @@ -114,7 +115,10 @@ export class AssetsTransferApi { const addr = sanitizeAddress(destAddr); const originChainId = getChainIdBySpecName(registry, _specName); - const isLocalSystemTx = (isOriginSystemParachain && isDestSystemParachain && originChainId === destChainId) + const isLocalSystemTx = + isOriginSystemParachain && + isDestSystemParachain && + originChainId === destChainId; const isLocalRelayTx = destChainId === '0' && RELAY_CHAIN_NAMES.includes(_specName.toLowerCase()); @@ -126,24 +130,37 @@ export class AssetsTransferApi { if (isLocalSystemTx || isLocalRelayTx) { let assetId = assetIds[0]; const amount = amounts[0]; - const systemChainId = getChainIdBySpecName(registry, _specName); const localAssetIdIsNotANumber = Number.isNaN(parseInt(assetId)); - + const relayChainID = RELAY_CHAIN_IDS[0]; + const nativeRelayChainAsset = + registry.currentRelayRegistry[relayChainID].tokens[0]; + let isNativeRelayChainAsset = false; + if ( + assetIds.length === 0 || + nativeRelayChainAsset.toLowerCase() === assetId.toLowerCase() + ) { + isNativeRelayChainAsset = true; + } if ( - xcmDirection === 'SystemToSystem' && + xcmDirection === 'SystemToSystem' && localAssetIdIsNotANumber && - assetIds.length !== 0 && - !registry.currentRelayRegistry[ - systemChainId - ].tokens.includes(assetId.toUpperCase()) + !isNativeRelayChainAsset ) { + // for SystemToSystem, assetId is not the native relayChains asset and is not a number + // check for the general index of the assetId and assign the correct value for the local tx + // throws an error if the general index is not found assetId = getSystemChainTokenSymbolGeneralIndex(assetId, _specName); } /** * This will throw a BaseError if the inputs are incorrect and don't * fit the constraints for creating a local asset transfer. */ - const localAssetType = checkLocalTxInput(assetIds, amounts, _specName, registry); // Throws an error when any of the inputs are incorrect. + const localAssetType = checkLocalTxInput( + assetIds, + amounts, + _specName, + registry + ); // Throws an error when any of the inputs are incorrect. const method = opts?.keepAlive ? 'transferKeepAlive' : 'transfer'; if (isLocalSystemTx) { @@ -453,7 +470,11 @@ export class AssetsTransferApi { } private fetchAssetType(xcmDirection: Direction): AssetType { - if (xcmDirection === 'RelayToSystem' || xcmDirection === 'SystemToRelay' || xcmDirection === 'SystemToSystem') { + if ( + xcmDirection === 'RelayToSystem' || + xcmDirection === 'SystemToRelay' || + xcmDirection === 'SystemToSystem' + ) { return AssetType.Native; } @@ -556,9 +577,9 @@ export class AssetsTransferApi { submittableString ) as unknown as SubmittableMethodData; - const addr: string = submittableData.method.args.target ? - submittableData.method.args.target?.Id : - ''; + const addr: string = submittableData.method.args.target + ? submittableData.method.args.target?.Id + : ''; const lastHeader = await this._api.rpc.chain.getHeader(); const blockNumber = this._api.registry.createType( diff --git a/src/consts.ts b/src/consts.ts index 294b91a9..642a3eb9 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -12,7 +12,15 @@ export const RELAY_CHAIN_IDS = ['0']; /** * List of all known system parachains. */ -export const SYSTEM_PARACHAINS_NAMES = ['statemine', 'statemint', 'westmint', 'bridge-hub-kusama', 'bridge-hub-polkadot', 'encointer-parachain', 'collectives']; +export const SYSTEM_PARACHAINS_NAMES = [ + 'statemine', + 'statemint', + 'westmint', + 'bridge-hub-kusama', + 'bridge-hub-polkadot', + 'encointer-parachain', + 'collectives', +]; /** * List of IDs for assets and bridge hub system parachains. */ diff --git a/src/createXcmTypes/SystemToPara.ts b/src/createXcmTypes/SystemToPara.ts index 728c8e29..147ee1af 100644 --- a/src/createXcmTypes/SystemToPara.ts +++ b/src/createXcmTypes/SystemToPara.ts @@ -11,6 +11,9 @@ import type { import type { XcmV3MultiassetMultiAssets } from '@polkadot/types/lookup'; import { isEthereumAddress } from '@polkadot/util-crypto'; +import { SYSTEM_PARACHAINS_IDS } from '../consts'; +import { getChainIdBySpecName } from '../createXcmTypes/util/getChainIdBySpecName'; +import { BaseError } from '../errors'; import type { Registry } from '../registry'; import { getFeeAssetItemIndex } from '../util/getFeeAssetItemIndex'; import { normalizeArrToStr } from '../util/normalizeArrToStr'; @@ -25,9 +28,6 @@ import { dedupeMultiAssets } from './util/dedupeMultiAssets'; import { fetchPalletInstanceId } from './util/fetchPalletInstanceId'; import { getSystemChainTokenSymbolGeneralIndex } from './util/getTokenSymbolGeneralIndex'; import { sortMultiAssetsAscending } from './util/sortMultiAssetsAscending'; -import { getChainIdBySpecName } from '../createXcmTypes/util/getChainIdBySpecName'; -import { SYSTEM_PARACHAINS_IDS } from '../consts'; -import { BaseError } from '../errors'; export const SystemToPara: ICreateXcmType = { /** @@ -207,13 +207,15 @@ export const SystemToPara: ICreateXcmType = { const systemChainId = getChainIdBySpecName(registry, specName); if (!SYSTEM_PARACHAINS_IDS.includes(systemChainId)) { - throw new BaseError(`specName ${specName} did not match a valid system chain ID. Found ID ${systemChainId}`); + throw new BaseError( + `specName ${specName} did not match a valid system chain ID. Found ID ${systemChainId}` + ); } - + const assetIndex = getFeeAssetItemIndex( paysWithFeeDest, multiAssets, - specName, + specName ); return api.registry.createType('u32', assetIndex); @@ -244,7 +246,9 @@ export const createSystemToParaMultiAssets = ( const systemChainId = getChainIdBySpecName(registry, specName); if (!SYSTEM_PARACHAINS_IDS.includes(systemChainId)) { - throw new BaseError(`specName ${specName} did not match a valid system chain ID. Found ID ${systemChainId}`); + throw new BaseError( + `specName ${specName} did not match a valid system chain ID. Found ID ${systemChainId}` + ); } const { tokens } = registry.currentRelayRegistry[systemChainId]; @@ -256,7 +260,6 @@ export const createSystemToParaMultiAssets = ( const parsedAssetIdAsNumber = Number.parseInt(assetId); const isNotANumber = Number.isNaN(parsedAssetIdAsNumber); const isRelayNative = isRelayNativeAsset(tokens, assetId); - if (!isRelayNative && isNotANumber) { assetId = getSystemChainTokenSymbolGeneralIndex(assetId, specName); diff --git a/src/createXcmTypes/SystemToSystem.spec.ts b/src/createXcmTypes/SystemToSystem.spec.ts index 7b0cfc03..5dc64066 100644 --- a/src/createXcmTypes/SystemToSystem.spec.ts +++ b/src/createXcmTypes/SystemToSystem.spec.ts @@ -66,8 +66,8 @@ describe('SystemToSystem XcmVersioned Generation', () => { parents: 1, interior: { x1: { - parachain: 1000 - }, + parachain: 1000, + }, }, }, }; @@ -82,8 +82,8 @@ describe('SystemToSystem XcmVersioned Generation', () => { parents: 1, interior: { x1: { - parachain: 1002, - } + parachain: 1002, + }, }, }, }; @@ -110,8 +110,8 @@ describe('SystemToSystem XcmVersioned Generation', () => { concrete: { parents: 0, interior: { - x2: [{ palletInstance: 50 },{ generalIndex: 11 }] - } + x2: [{ palletInstance: 50 }, { generalIndex: 11 }], + }, }, }, fun: { @@ -155,18 +155,18 @@ describe('SystemToSystem XcmVersioned Generation', () => { }); it('Should error when asset ID is not found for V3', () => { - const expectedErrorMessage = 'bridge-hub-kusama has no associated token symbol usdc'; - - const err = () => SystemToSystem.createAssets( - mockSystemApi, - ['100'], - 3, - 'bridge-hub-kusama', - ['usdc'], - { registry } - ); - - + const expectedErrorMessage = + 'bridge-hub-kusama has no associated token symbol usdc'; + + const err = () => + SystemToSystem.createAssets( + mockSystemApi, + ['100'], + 3, + 'bridge-hub-kusama', + ['usdc'], + { registry } + ); expect(err).toThrowError(expectedErrorMessage); }); diff --git a/src/createXcmTypes/SystemToSystem.ts b/src/createXcmTypes/SystemToSystem.ts index cc205748..d8457678 100644 --- a/src/createXcmTypes/SystemToSystem.ts +++ b/src/createXcmTypes/SystemToSystem.ts @@ -11,6 +11,9 @@ import type { import type { XcmV3MultiassetMultiAssets } from '@polkadot/types/lookup'; import { isEthereumAddress } from '@polkadot/util-crypto'; +import { SYSTEM_PARACHAINS_IDS } from '../consts'; +import { getChainIdBySpecName } from '../createXcmTypes/util/getChainIdBySpecName'; +import { BaseError } from '../errors'; import type { Registry } from '../registry'; import { getFeeAssetItemIndex } from '../util/getFeeAssetItemIndex'; import { normalizeArrToStr } from '../util/normalizeArrToStr'; @@ -25,9 +28,6 @@ import { dedupeMultiAssets } from './util/dedupeMultiAssets'; import { fetchPalletInstanceId } from './util/fetchPalletInstanceId'; import { getSystemChainTokenSymbolGeneralIndex } from './util/getTokenSymbolGeneralIndex'; import { sortMultiAssetsAscending } from './util/sortMultiAssetsAscending'; -import { BaseError } from '../errors'; -import { SYSTEM_PARACHAINS_IDS } from '../consts'; -import { getChainIdBySpecName } from '../createXcmTypes/util/getChainIdBySpecName'; export const SystemToSystem: ICreateXcmType = { /** @@ -132,7 +132,7 @@ export const SystemToSystem: ICreateXcmType = { amounts, specName, assets, - registry, + registry ); if (xcmVersion === 2) { @@ -210,13 +210,15 @@ export const SystemToSystem: ICreateXcmType = { const systemChainId = getChainIdBySpecName(registry, specName); if (!SYSTEM_PARACHAINS_IDS.includes(systemChainId)) { - throw new BaseError(`specName ${specName} did not match a valid system chain ID. Found ID ${systemChainId}`); + throw new BaseError( + `specName ${specName} did not match a valid system chain ID. Found ID ${systemChainId}` + ); } const assetIndex = getFeeAssetItemIndex( paysWithFeeDest, multiAssets, - specName, + specName ); return api.registry.createType('u32', assetIndex); @@ -240,16 +242,18 @@ export const createSystemToSystemMultiAssets = ( amounts: string[], specName: string, assets: string[], - registry: Registry, + registry: Registry ): MultiAsset[] => { let palletId: string | undefined = undefined; let multiAssets = []; const systemChainId = getChainIdBySpecName(registry, specName); - if (!SYSTEM_PARACHAINS_IDS.includes(systemChainId)) { - throw new BaseError(`specName ${specName} did not match a valid system chain ID. Found ID ${systemChainId}`); - } + if (!SYSTEM_PARACHAINS_IDS.includes(systemChainId)) { + throw new BaseError( + `specName ${specName} did not match a valid system chain ID. Found ID ${systemChainId}` + ); + } const { tokens } = registry.currentRelayRegistry[systemChainId]; @@ -261,7 +265,6 @@ export const createSystemToSystemMultiAssets = ( const isNotANumber = Number.isNaN(parsedAssetIdAsNumber); const isRelayNative = isRelayNativeAsset(tokens, assetId); - if (!isRelayNative) { palletId = fetchPalletInstanceId(api); @@ -305,4 +308,4 @@ const isRelayNativeAsset = (tokens: string[], assetId: string): boolean => { } return false; -}; \ No newline at end of file +}; diff --git a/src/createXcmTypes/index.ts b/src/createXcmTypes/index.ts index 5636d59b..79c77749 100644 --- a/src/createXcmTypes/index.ts +++ b/src/createXcmTypes/index.ts @@ -3,9 +3,9 @@ import { Direction } from '../types'; import { RelayToPara } from './RelayToPara'; import { RelayToSystem } from './RelayToSystem'; -import { SystemToSystem } from './SystemToSystem'; import { SystemToPara } from './SystemToPara'; import { SystemToRelay } from './SystemToRelay'; +import { SystemToSystem } from './SystemToSystem'; import { ICreateXcmType } from './types'; type ICreateXcmTypeLookup = { diff --git a/src/createXcmTypes/util/getChainIdBySpecName.ts b/src/createXcmTypes/util/getChainIdBySpecName.ts index 209e2be9..cc85e0c4 100644 --- a/src/createXcmTypes/util/getChainIdBySpecName.ts +++ b/src/createXcmTypes/util/getChainIdBySpecName.ts @@ -1,15 +1,18 @@ // Copyright 2023 Parity Technologies (UK) Ltd. -import { Registry } from "../../registry"; +import { Registry } from '../../registry'; /** * returns a chains ID based on its relay chain and specName - * + * * @param registry Registry * @param specName string - * @returns + * @returns */ -export const getChainIdBySpecName = (registry: Registry, specName: string): string => { +export const getChainIdBySpecName = ( + registry: Registry, + specName: string +): string => { let result = ''; Object.entries(registry.currentRelayRegistry).forEach((chainInfo) => { @@ -19,4 +22,4 @@ export const getChainIdBySpecName = (registry: Registry, specName: string): stri }); return result; -} \ No newline at end of file +}; diff --git a/src/createXcmTypes/util/getTokenSymbolGeneralIndex.ts b/src/createXcmTypes/util/getTokenSymbolGeneralIndex.ts index 3f30de11..2292744a 100644 --- a/src/createXcmTypes/util/getTokenSymbolGeneralIndex.ts +++ b/src/createXcmTypes/util/getTokenSymbolGeneralIndex.ts @@ -1,8 +1,8 @@ // Copyright 2023 Parity Technologies (UK) Ltd. +import { SYSTEM_PARACHAINS_IDS } from '../../consts'; import { BaseError } from '../../errors'; import { Registry } from '../../registry'; -import { SYSTEM_PARACHAINS_IDS } from '../../consts'; import { getChainIdBySpecName } from './getChainIdBySpecName'; /** @@ -14,20 +14,24 @@ import { getChainIdBySpecName } from './getChainIdBySpecName'; */ export const getSystemChainTokenSymbolGeneralIndex = ( tokenSymbol: string, - specName: string, + specName: string ): string => { const newRegistry = new Registry(specName, {}); const systemChainId = getChainIdBySpecName(newRegistry, specName); if (!SYSTEM_PARACHAINS_IDS.includes(systemChainId)) { - throw new BaseError(`specName ${specName} did not match a valid system chain ID. Found ID ${systemChainId}`); + throw new BaseError( + `specName ${specName} did not match a valid system chain ID. Found ID ${systemChainId}` + ); } const { assetsInfo } = newRegistry.currentRelayRegistry[systemChainId]; if (Object.keys(assetsInfo).length === 0) { - throw new BaseError(`${specName} has no associated token symbol ${tokenSymbol}`); + throw new BaseError( + `${specName} has no associated token symbol ${tokenSymbol}` + ); } // get the corresponding asset id index from the assets registry diff --git a/src/errors/checkLocalTxInputs.spec.ts b/src/errors/checkLocalTxInputs.spec.ts index f21d1ced..65293293 100644 --- a/src/errors/checkLocalTxInputs.spec.ts +++ b/src/errors/checkLocalTxInputs.spec.ts @@ -20,25 +20,26 @@ describe('checkLocalTxInput', () => { expect(res).toEqual('Assets'); }); it('Should correctly throw an error for incorrect length on `assetIds`', () => { - const err = () => checkLocalTxInput(['1', '2'], ['10000'], specName, registry); + const err = () => + checkLocalTxInput(['1', '2'], ['10000'], specName, registry); expect(err).toThrowError( 'Local transactions must have the `assetIds` input be a length of 1 or 0, and the `amounts` input be a length of 1' ); }); it('Should correctly throw an error for incorrect length on `amounts`', () => { - const err = () => checkLocalTxInput(['1'], ['10000', '20000'], specName, registry); + const err = () => + checkLocalTxInput(['1'], ['10000', '20000'], specName, registry); expect(err).toThrowError( 'Local transactions must have the `assetIds` input be a length of 1 or 0, and the `amounts` input be a length of 1' ); }); it('Should correctly throw an error with an incorrect assetId', () => { const err = () => checkLocalTxInput(['TST'], ['10000'], specName, registry); - expect(err).toThrowError( - 'general index for assetId TST was not found' - ); + expect(err).toThrowError('general index for assetId TST was not found'); }); it("Should correctly throw an error when the assetId doesn't exist", () => { - const err = () => checkLocalTxInput(['9876111'], ['10000'], specName, registry); + const err = () => + checkLocalTxInput(['9876111'], ['10000'], specName, registry); expect(err).toThrowError( 'The assetId 9876111 does not exist in the registry.' ); diff --git a/src/errors/checkLocalTxInputs.ts b/src/errors/checkLocalTxInputs.ts index 1864628c..ad1a856b 100644 --- a/src/errors/checkLocalTxInputs.ts +++ b/src/errors/checkLocalTxInputs.ts @@ -1,9 +1,9 @@ // Copyright 2023 Parity Technologies (UK) Ltd. +import { getChainIdBySpecName } from '../createXcmTypes/util/getChainIdBySpecName'; +import { getSystemChainTokenSymbolGeneralIndex } from '../createXcmTypes/util/getTokenSymbolGeneralIndex'; import { Registry } from '../registry'; import { BaseError } from './BaseError'; -import { getSystemChainTokenSymbolGeneralIndex } from '../createXcmTypes/util/getTokenSymbolGeneralIndex'; -import { getChainIdBySpecName } from '../createXcmTypes/util/getChainIdBySpecName'; enum LocalTxType { Assets = 'Assets', @@ -43,18 +43,20 @@ export const checkLocalTxInput = ( let assetId = assetIds[0]; - const isNativeToken = systemParachainInfo.tokens.find((token) => token.toLowerCase() === assetId.toLowerCase()); + const isNativeToken = systemParachainInfo.tokens.find( + (token) => token.toLowerCase() === assetId.toLowerCase() + ); if (isNativeToken !== undefined) { return LocalTxType.Balances; } else { const isNotANumber = Number.isNaN(parseInt(assetId)); if (isNotANumber) { - assetId = getSystemChainTokenSymbolGeneralIndex(assetId, specName); + assetId = getSystemChainTokenSymbolGeneralIndex(assetId, specName); } - const isAssetAvailable = Object.keys( - systemParachainInfo.assetsInfo - ).find((asset) => asset.toLowerCase() === assetId.toLowerCase()); + const isAssetAvailable = Object.keys(systemParachainInfo.assetsInfo).find( + (asset) => asset.toLowerCase() === assetId.toLowerCase() + ); if (!isAssetAvailable) { throw new BaseError( `The assetId ${assetId} does not exist in the registry.` diff --git a/src/types.ts b/src/types.ts index 6ae29210..40c2a0b8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -292,7 +292,7 @@ export interface Target { export interface Args { id?: string; - target?: Target + target?: Target; dest?: Dest; value?: u32; } diff --git a/src/util/getFeeAssetItemIndex.spec.ts b/src/util/getFeeAssetItemIndex.spec.ts index f2d6ea27..a134e2b3 100644 --- a/src/util/getFeeAssetItemIndex.spec.ts +++ b/src/util/getFeeAssetItemIndex.spec.ts @@ -7,12 +7,11 @@ type Test = [ paysWithFeeDest: string, specName: string, multiAssets: MultiAsset[], - expected: number, + expected: number ]; describe('getFeeAssetItemIndex', () => { it('Should select and return the index of the correct multiassets when given their token symbols', () => { - const tests: Test[] = [ [ 'usdt', diff --git a/src/util/getFeeAssetItemIndex.ts b/src/util/getFeeAssetItemIndex.ts index a73df696..fb2a926e 100644 --- a/src/util/getFeeAssetItemIndex.ts +++ b/src/util/getFeeAssetItemIndex.ts @@ -15,7 +15,7 @@ import { NonRelayNativeInterior, RelayNativeInterior } from '../types'; export const getFeeAssetItemIndex = ( paysWithFeeDest: string, multiAssets: MultiAsset[], - specName: string, + specName: string ): number => { let result = 0; From ce47c3ab17633e550009e1078250b18645ff0399 Mon Sep 17 00:00:00 2001 From: marshacb Date: Tue, 27 Jun 2023 18:52:57 -0400 Subject: [PATCH 08/55] re-add cypress to lookupAssetId test --- src/registry/Registry.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/registry/Registry.spec.ts b/src/registry/Registry.spec.ts index a237f918..b75021de 100644 --- a/src/registry/Registry.spec.ts +++ b/src/registry/Registry.spec.ts @@ -36,6 +36,7 @@ describe('Registry', () => { '11': 'web3', '21': 'WBTC', '77': 'TRQ', + '99': 'Cypress', '100': 'WETH', '101': 'DOTMA', '123': '123', From 64d0c47c532002ace5ce0acad47dd915d0ebfd04 Mon Sep 17 00:00:00 2001 From: marshacb Date: Wed, 28 Jun 2023 08:56:09 -0400 Subject: [PATCH 09/55] update xcmDirections checks in AssetTransferApi to use enum --- src/AssetsTransferApi.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/AssetsTransferApi.ts b/src/AssetsTransferApi.ts index 504c8cfa..d762a280 100644 --- a/src/AssetsTransferApi.ts +++ b/src/AssetsTransferApi.ts @@ -142,7 +142,7 @@ export class AssetsTransferApi { isNativeRelayChainAsset = true; } if ( - xcmDirection === 'SystemToSystem' && + xcmDirection === Direction.SystemToSystem && localAssetIdIsNotANumber && !isNativeRelayChainAsset ) { @@ -471,9 +471,9 @@ export class AssetsTransferApi { private fetchAssetType(xcmDirection: Direction): AssetType { if ( - xcmDirection === 'RelayToSystem' || - xcmDirection === 'SystemToRelay' || - xcmDirection === 'SystemToSystem' + xcmDirection === Direction.RelayToSystem || + xcmDirection === Direction.SystemToRelay || + xcmDirection === Direction.SystemToSystem ) { return AssetType.Native; } @@ -483,7 +483,7 @@ export class AssetsTransferApi { * parachains then this logic will change. But for now all assets, and native tokens * transferred from a System parachain to a parachain it should use a reserve transfer. */ - if (xcmDirection === 'RelayToPara' || xcmDirection === 'SystemToPara') { + if (xcmDirection === Direction.RelayToPara || xcmDirection === Direction.SystemToPara) { return AssetType.Foreign; } From cfba4d8b6e8fca8affa089185f4e24e216ec8e57 Mon Sep 17 00:00:00 2001 From: marshacb Date: Mon, 3 Jul 2023 11:37:26 -0400 Subject: [PATCH 10/55] update SystemToSystem integration tests --- examples/systemToSystem.ts | 53 ++++ src/AssetsTransferApi.ts | 25 +- src/errors/checkXcmTxInputs.spec.ts | 27 +- src/errors/checkXcmTxInputs.ts | 117 +++++++- .../AssetsTransferApi.spec.ts | 266 ++++++++++++++++++ 5 files changed, 464 insertions(+), 24 deletions(-) create mode 100644 examples/systemToSystem.ts diff --git a/examples/systemToSystem.ts b/examples/systemToSystem.ts new file mode 100644 index 00000000..b9cd31ba --- /dev/null +++ b/examples/systemToSystem.ts @@ -0,0 +1,53 @@ +/** + * When importing from @substrate/asset-transfer-api it would look like the following + * + * import { AssetsTransferApi, constructApiPromise } from '@substrate/asset-transfer-api' + */ +import { AssetsTransferApi, constructApiPromise } from '../src'; +import { TxResult } from '../src/types'; +import { GREEN, PURPLE, RESET } from './colors'; + +/** + * In this example we are creating a call to send 1 WND from a Westmint (System Parachain) account + * to a Westend Collectives (System Chain) account, where the `xcmVersion` is set to 2, and the `isLimited` declaring that + * it will be `unlimited` since there is no `weightLimit` option as well. + * + * NOTE: When `isLimited` is true it will use the `limited` version of the either `reserveAssetTransfer`, or `teleportAssets`. + */ +const main = async () => { + const { api, specName, safeXcmVersion } = await constructApiPromise( + 'wss://westend-asset-hub-rpc.polkadot.io' + ); + const assetApi = new AssetsTransferApi(api, specName, safeXcmVersion); + + let callInfo: TxResult<'call'>; + try { + callInfo = await assetApi.createTransferTransaction( + '1001', // NOTE: The destination id is `1001` noting that we are sending to the collectives/encointer System parachain + '5EWNeodpcQ6iYibJ3jmWVe85nsok1EDG8Kk3aFg8ZzpfY1qX', + ['WND'], + ['1000000000000'], + { + format: 'call', + isLimited: true, + xcmVersion: 2, + } + ); + + console.log(callInfo); + } catch (e) { + console.error(e); + throw Error(e as string); + } + + const decoded = assetApi.decodeExtrinsic(callInfo.tx, 'call'); + console.log( + `\n${PURPLE}The following decoded tx:\n${GREEN} ${JSON.stringify( + JSON.parse(decoded), + null, + 4 + )}${RESET}` + ); +}; + +main().finally(() => process.exit()); diff --git a/src/AssetsTransferApi.ts b/src/AssetsTransferApi.ts index d762a280..3c8336c9 100644 --- a/src/AssetsTransferApi.ts +++ b/src/AssetsTransferApi.ts @@ -34,6 +34,7 @@ import { checkXcmTxInputs, checkXcmVersion, } from './errors'; +import { containsNativeRelayAsset } from './errors/checkXcmTxInputs'; import { Registry } from './registry'; import { sanitizeAddress } from './sanitize/sanitizeAddress'; import { @@ -123,6 +124,9 @@ export class AssetsTransferApi { destChainId === '0' && RELAY_CHAIN_NAMES.includes(_specName.toLowerCase()); + const relayChainID = RELAY_CHAIN_IDS[0]; + const nativeRelayChainAsset = + registry.currentRelayRegistry[relayChainID].tokens[0]; const xcmDirection = this.establishDirection(destChainId, _specName); /** * Create a local asset transfer on a system parachain @@ -131,9 +135,6 @@ export class AssetsTransferApi { let assetId = assetIds[0]; const amount = amounts[0]; const localAssetIdIsNotANumber = Number.isNaN(parseInt(assetId)); - const relayChainID = RELAY_CHAIN_IDS[0]; - const nativeRelayChainAsset = - registry.currentRelayRegistry[relayChainID].tokens[0]; let isNativeRelayChainAsset = false; if ( assetIds.length === 0 || @@ -141,6 +142,7 @@ export class AssetsTransferApi { ) { isNativeRelayChainAsset = true; } + if ( xcmDirection === Direction.SystemToSystem && localAssetIdIsNotANumber && @@ -151,6 +153,7 @@ export class AssetsTransferApi { // throws an error if the general index is not found assetId = getSystemChainTokenSymbolGeneralIndex(assetId, _specName); } + /** * This will throw a BaseError if the inputs are incorrect and don't * fit the constraints for creating a local asset transfer. @@ -231,7 +234,12 @@ export class AssetsTransferApi { let txMethod: Methods; let transaction: SubmittableExtrinsic<'promise', ISubmittableResult>; - if (assetType === AssetType.Foreign) { + if ( + assetType === AssetType.Foreign || + (assetType === AssetType.Native && + xcmDirection === Direction.SystemToSystem && + !containsNativeRelayAsset(assetIds, nativeRelayChainAsset)) + ) { if (opts?.isLimited) { txMethod = 'limitedReserveTransferAssets'; transaction = limitedReserveTransferAssets( @@ -483,7 +491,10 @@ export class AssetsTransferApi { * parachains then this logic will change. But for now all assets, and native tokens * transferred from a System parachain to a parachain it should use a reserve transfer. */ - if (xcmDirection === Direction.RelayToPara || xcmDirection === Direction.SystemToPara) { + if ( + xcmDirection === Direction.RelayToPara || + xcmDirection === Direction.SystemToPara + ) { return AssetType.Foreign; } @@ -655,8 +666,8 @@ export class AssetsTransferApi { /** * Return the specName of the destination chainId * - * @param destChainId - * @param registry + * @param destChainId string + * @param registry Registry * @returns */ private getDestinationSpecName(destId: string, registry: Registry): string { diff --git a/src/errors/checkXcmTxInputs.spec.ts b/src/errors/checkXcmTxInputs.spec.ts index cae354a7..e5af045c 100644 --- a/src/errors/checkXcmTxInputs.spec.ts +++ b/src/errors/checkXcmTxInputs.spec.ts @@ -5,6 +5,7 @@ import { Direction } from '../types'; import { checkAssetIdInput, checkAssetsAmountMatch, + checkIfNativeRelayChainAssetPresentInMultiAssetIdList, checkRelayAmountsLength, checkRelayAssetIdLength, } from './checkXcmTxInputs'; @@ -21,7 +22,8 @@ const runTests = (tests: Test[]) => { currentRegistry, specName, destChainId, - direction + direction, + registry ); expect(err).toThrow(errorMessage); } @@ -199,7 +201,8 @@ describe('checkAssetIds', () => { currentRegistry, specName, destChainId, - direction + direction, + registry ); expect(err).toThrow(errorMessage); } @@ -241,7 +244,8 @@ describe('checkAssetIds', () => { currentRegistry, specName, destChainId, - direction + direction, + registry ); expect(err).toThrow(errorMessage); } @@ -276,9 +280,24 @@ describe('checkAssetIds', () => { currentRegistry, specName, destChainId, - direction + direction, + registry ); expect(err).toThrowError(errorMessage); } }); }); + +describe('checkIfNativeRelayChainAssetPresentInMultiAssetIdList', () => { + it('Should error when the relay native asset and system assets are in the same assetIds list when direction', () => { + const expectErrorMessage = + 'Found the relay chains native asset in list ksm,usdc. assetIds list must be empty or only contain the relay chain asset for direction SystemToSystem'; + const assetIds = ['ksm', 'usdc']; + const specName = 'statemine'; + const registry = new Registry(specName, {}); + + const err = () => + checkIfNativeRelayChainAssetPresentInMultiAssetIdList(assetIds, registry); + expect(err).toThrowError(expectErrorMessage); + }); +}); diff --git a/src/errors/checkXcmTxInputs.ts b/src/errors/checkXcmTxInputs.ts index 161aab09..2d99540e 100644 --- a/src/errors/checkXcmTxInputs.ts +++ b/src/errors/checkXcmTxInputs.ts @@ -1,4 +1,5 @@ -import { RELAY_CHAIN_IDS, SYSTEM_PARACHAINS_IDS } from '../consts'; +import { RELAY_CHAIN_IDS } from '../consts'; +import { getChainIdBySpecName } from '../createXcmTypes/util/getChainIdBySpecName'; import { Registry } from '../registry'; import type { ChainInfo } from '../registry/types'; import { Direction } from '../types'; @@ -69,6 +70,59 @@ const checkIfAssetIdIsEmptyOrBlankSpace = (assetId: string) => { ); } }; + +/** + * checks if assetIds contain the current relay chains native asset + * + * @param assetIds string[] + * @param relayChainAsset string + * @returns boolean + */ +export const containsNativeRelayAsset = ( + assetIds: string[], + relayChainAsset: string +): boolean => { + // We assume when the assetId's input is empty that the native token is to be transferred. + if (assetIds.length === 0) { + return true; + } + + for (let i = 0; i < assetIds.length; i++) { + const assetId = assetIds[i]; + + if (assetId.toLowerCase() === relayChainAsset.toLowerCase()) { + return true; + } + } + + return false; +}; + +/** + * if direction is SystemToSystem, assetIds should contain either only the relay chains + * native asset or only assets native to the system chain and not both + * + * @param assetIds string[] + * @param registry Registry + */ +export const checkIfNativeRelayChainAssetPresentInMultiAssetIdList = ( + assetIds: string[], + registry: Registry +) => { + const relayChainID = RELAY_CHAIN_IDS[0]; + const nativeRelayChainAsset = + registry.currentRelayRegistry[relayChainID].tokens[0]; + + if ( + assetIds.length > 1 && + containsNativeRelayAsset(assetIds, nativeRelayChainAsset) + ) { + throw new BaseError( + `Found the relay chains native asset in list ${assetIds.toString()}. assetIds list must be empty or only contain the relay chain asset for direction SystemToSystem` + ); + } +}; + /** * This will check the given assetId and ensure that it is the native token of the relay chain * @@ -169,10 +223,20 @@ const checkSystemToRelayAssetId = ( const checkSystemToParaAssetId = ( assetId: string, specName: string, - relayChainInfo: ChainInfo + relayChainInfo: ChainInfo, + registry: Registry +) => { + checkIsValidSystemChainAssetId(assetId, specName, relayChainInfo, registry); +}; + +export const checkIsValidSystemChainAssetId = ( + assetId: string, + specName: string, + relayChainInfo: ChainInfo, + registry: Registry ) => { - const systemParachainId = SYSTEM_PARACHAINS_IDS[0]; - const systemParachainInfo = relayChainInfo[systemParachainId]; + const systemChainId = getChainIdBySpecName(registry, specName); + const systemParachainInfo = relayChainInfo[systemChainId]; if (typeof assetId === 'string') { // check if assetId is a number @@ -226,11 +290,12 @@ const checkSystemToParaAssetId = ( const assetMessageInfo = tokenSymbolsMatched.map( (token) => `assetId: ${token.id} symbol: ${token.symbol}` ); + const regex = new RegExp(',', 'g'); const message = - `Multiple assets found with symbol ${assetId}:\n${assetMessageInfo.toString()}\nPlease retry using an assetId rather than the token symbol + `Multiple assets found with symbol ${assetId}:\n${assetMessageInfo.toString()}\nPlease retry using an assetId rather than the token symbol. ` .trim() - .replace(',', '\n'); + .replace(regex, '\n'); throw new BaseError(message); } else if (tokenSymbolsMatched.length === 1) { @@ -247,6 +312,21 @@ const checkSystemToParaAssetId = ( } }; +/** + * This will check the given assetId and ensure that it is a valid system chain asset or relay chain native token + * + * @param assetId + * @param relayChainInfo + */ +const checkSystemToSystemAssetId = ( + assetId: string, + specName: string, + relayChainInfo: ChainInfo, + registry: Registry +) => { + checkIsValidSystemChainAssetId(assetId, specName, relayChainInfo, registry); +}; + /** * This will check the given assetIds and ensure they are either valid integers as strings * or known token symbols @@ -261,7 +341,8 @@ export const checkAssetIdInput = ( relayChainInfo: ChainInfo, specName: string, _destChainId: string, - xcmDirection: Direction + xcmDirection: Direction, + registry: Registry ) => { for (let i = 0; i < assetIds.length; i++) { const assetId = assetIds[i]; @@ -281,7 +362,11 @@ export const checkAssetIdInput = ( } if (xcmDirection === Direction.SystemToPara) { - checkSystemToParaAssetId(assetId, specName, relayChainInfo); + checkSystemToParaAssetId(assetId, specName, relayChainInfo, registry); + } + + if (xcmDirection === Direction.SystemToSystem) { + checkSystemToSystemAssetId(assetId, specName, relayChainInfo, registry); } } }; @@ -313,25 +398,31 @@ export const checkXcmTxInputs = ( relayChainInfo, specName, destChainId, - xcmDirection + xcmDirection, + registry ); - if (xcmDirection === 'RelayToSystem') { + if (xcmDirection === Direction.RelayToSystem) { checkRelayAssetIdLength(assetIds); checkRelayAmountsLength(amounts); } - if (xcmDirection === 'RelayToPara') { + if (xcmDirection === Direction.RelayToPara) { checkRelayAssetIdLength(assetIds); checkRelayAmountsLength(amounts); } - if (xcmDirection === 'SystemToRelay') { + if (xcmDirection === Direction.SystemToRelay) { checkRelayAssetIdLength(assetIds); checkRelayAmountsLength(amounts); } - if (xcmDirection === 'SystemToPara') { + if (xcmDirection === Direction.SystemToPara) { + checkAssetsAmountMatch(assetIds, amounts); + } + + if (xcmDirection === Direction.SystemToSystem) { + checkIfNativeRelayChainAssetPresentInMultiAssetIdList(assetIds, registry); checkAssetsAmountMatch(assetIds, amounts); } }; diff --git a/src/integrationTests/AssetsTransferApi.spec.ts b/src/integrationTests/AssetsTransferApi.spec.ts index 6535ca6e..3af6685b 100644 --- a/src/integrationTests/AssetsTransferApi.spec.ts +++ b/src/integrationTests/AssetsTransferApi.spec.ts @@ -403,6 +403,272 @@ describe('AssetTransferApi Integration Tests', () => { }); }); }); + + describe('SystemToSystem', () => { + const foreignBaseSystemCreateTx = async ( + format: T, + isLimited: boolean, + xcmVersion: number + ): Promise> => { + return await systemAssetsApi.createTransferTransaction( + '1001', // collectives system parachain + '0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b', + ['1', '2'], + ['100', '100'], + { + format, + isLimited, + xcmVersion, + } + ); + }; + const nativeBaseSystemCreateTx = async ( + format: T, + isLimited: boolean, + xcmVersion: number + ): Promise> => { + return await systemAssetsApi.createTransferTransaction( + '1002', // bridge-hub system parachain + '0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b', + ['KSM'], + ['100'], + { + format, + isLimited, + xcmVersion, + } + ); + }; + describe('V2', () => { + it('Should correctly build a call for a limitedReserveTransferAsset for V2', async () => { + const res = await foreignBaseSystemCreateTx('call', true, 2); + expect(res).toEqual({ + dest: 'encointer-parachain', + origin: 'statemine', + direction: 'SystemToSystem', + format: 'call', + method: 'limitedReserveTransferAssets', + tx: '0x1f0801010100a50f0100010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b010800000204320504009101000002043205080091010000000000', + xcmVersion: 2, + }); + }); + it('Should correctly build a payload for a limitedReserveTransferAsset for V2', async () => { + const res = await foreignBaseSystemCreateTx('payload', true, 2); + expect(res).toEqual({ + dest: 'encointer-parachain', + origin: 'statemine', + direction: 'SystemToSystem', + format: 'payload', + method: 'limitedReserveTransferAssets', + tx: '0x21011f0801010100a50f0100010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b010800000204320504009101000002043205080091010000000000450228000100000000cc240000040000000000000000000000000000000000000000000000000000000000000000000000be2554aa8a0151eb4d706308c47d16996af391e4c5e499c7cbef24259b7d4503', + xcmVersion: 2, + }); + }); + it('Should correctly build a submittable extrinsic for a limitedReserveTransferAsset for V2', async () => { + const res = await foreignBaseSystemCreateTx('submittable', true, 2); + expect(res.tx.toRawType()).toEqual('Extrinsic'); + }); + it('Should correctly build a call for a reserveTransferAsset for V2', async () => { + const res = await foreignBaseSystemCreateTx('call', false, 2); + expect(res).toEqual({ + dest: 'encointer-parachain', + origin: 'statemine', + direction: 'SystemToSystem', + format: 'call', + method: 'reserveTransferAssets', + tx: '0x1f0201010100a50f0100010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b0108000002043205040091010000020432050800910100000000', + xcmVersion: 2, + }); + }); + it('Should correctly build a payload for a reserveTransferAsset for V2', async () => { + const res = await foreignBaseSystemCreateTx('payload', false, 2); + expect(res).toEqual({ + dest: 'encointer-parachain', + origin: 'statemine', + direction: 'SystemToSystem', + format: 'payload', + method: 'reserveTransferAssets', + tx: '0x1d011f0201010100a50f0100010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b0108000002043205040091010000020432050800910100000000450228000100000000cc240000040000000000000000000000000000000000000000000000000000000000000000000000be2554aa8a0151eb4d706308c47d16996af391e4c5e499c7cbef24259b7d4503', + xcmVersion: 2, + }); + }); + it('Should correctly build a submittable extrinsic for a limitedReserveTransferAsset for V2', async () => { + const res = await foreignBaseSystemCreateTx('submittable', false, 2); + expect(res.tx.toRawType()).toEqual('Extrinsic'); + }); + it('Should correctly build a call for a limitedTeleportAssets for V2 when its a native token', async () => { + const res = await nativeBaseSystemCreateTx('call', true, 2); + expect(res).toEqual({ + dest: 'bridge-hub-kusama', + origin: 'statemine', + direction: 'SystemToSystem', + format: 'call', + method: 'limitedTeleportAssets', + tx: '0x1f0901010100a90f0100010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b01040001000091010000000000', + xcmVersion: 2, + }); + }); + it('Should correctly build a payload for a limitedTeleportAssets for V2 when its a native token', async () => { + const res = await nativeBaseSystemCreateTx('payload', true, 2); + expect(res).toEqual({ + dest: 'bridge-hub-kusama', + origin: 'statemine', + direction: 'SystemToSystem', + format: 'payload', + method: 'limitedTeleportAssets', + tx: '0xe81f0901010100a90f0100010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b01040001000091010000000000450228000100000000cc240000040000000000000000000000000000000000000000000000000000000000000000000000be2554aa8a0151eb4d706308c47d16996af391e4c5e499c7cbef24259b7d4503', + xcmVersion: 2, + }); + }); + it('Should correctly build a submittable extrinsic for a limitedTeleportAssets for V2 when its a native token', async () => { + const res = await nativeBaseSystemCreateTx('submittable', true, 2); + expect(res.tx.toRawType()).toEqual('Extrinsic'); + }); + it('Should correctly build a call for teleportAssets for V2 when its a native token', async () => { + const res = await nativeBaseSystemCreateTx('call', false, 2); + expect(res).toEqual({ + dest: 'bridge-hub-kusama', + origin: 'statemine', + direction: 'SystemToSystem', + format: 'call', + method: 'teleportAssets', + tx: '0x1f0101010100a90f0100010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b010400010000910100000000', + xcmVersion: 2, + }); + }); + it('Should correctly build a payload for teleportAssets for V2 when its a native token', async () => { + const res = await nativeBaseSystemCreateTx('payload', false, 2); + expect(res).toEqual({ + dest: 'bridge-hub-kusama', + origin: 'statemine', + direction: 'SystemToSystem', + format: 'payload', + method: 'teleportAssets', + tx: '0xe41f0101010100a90f0100010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b010400010000910100000000450228000100000000cc240000040000000000000000000000000000000000000000000000000000000000000000000000be2554aa8a0151eb4d706308c47d16996af391e4c5e499c7cbef24259b7d4503', + xcmVersion: 2, + }); + }); + it('Should correctly build a submittable extrinsic for a teleportAssets for V2 when its a native token', async () => { + const res = await nativeBaseSystemCreateTx('submittable', false, 2); + expect(res.tx.toRawType()).toEqual('Extrinsic'); + }); + }); + describe('V3', () => { + it('Should correctly build a call for a limitedReserveTransferAsset for V3', async () => { + const res = await foreignBaseSystemCreateTx('call', true, 3); + expect(res).toEqual({ + dest: 'encointer-parachain', + origin: 'statemine', + direction: 'SystemToSystem', + format: 'call', + method: 'limitedReserveTransferAssets', + tx: '0x1f0803010100a50f0300010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b030800000204320504009101000002043205080091010000000000', + xcmVersion: 3, + }); + }); + it('Should correctly build a payload for a limitedReserveTransferAsset for V3', async () => { + const res = await foreignBaseSystemCreateTx('payload', true, 3); + expect(res).toEqual({ + dest: 'encointer-parachain', + origin: 'statemine', + direction: 'SystemToSystem', + format: 'payload', + method: 'limitedReserveTransferAssets', + tx: '0x21011f0803010100a50f0300010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b030800000204320504009101000002043205080091010000000000450228000100000000cc240000040000000000000000000000000000000000000000000000000000000000000000000000be2554aa8a0151eb4d706308c47d16996af391e4c5e499c7cbef24259b7d4503', + xcmVersion: 3, + }); + }); + it('Should correctly build a submittable extrinsic for a limitedReserveTransferAsset for V3', async () => { + const res = await foreignBaseSystemCreateTx('submittable', true, 3); + expect(res.tx.toRawType()).toEqual('Extrinsic'); + }); + it('Should correctly build a call for a reserveTransferAsset for V3', async () => { + const res = await foreignBaseSystemCreateTx('call', false, 3); + expect(res).toEqual({ + dest: 'encointer-parachain', + origin: 'statemine', + direction: 'SystemToSystem', + format: 'call', + method: 'reserveTransferAssets', + tx: '0x1f0203010100a50f0300010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b0308000002043205040091010000020432050800910100000000', + xcmVersion: 3, + }); + }); + it('Should correctly build a payload for a reserveTransferAsset for V3', async () => { + const res = await foreignBaseSystemCreateTx('payload', false, 3); + expect(res).toEqual({ + dest: 'encointer-parachain', + origin: 'statemine', + direction: 'SystemToSystem', + format: 'payload', + method: 'reserveTransferAssets', + tx: '0x1d011f0203010100a50f0300010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b0308000002043205040091010000020432050800910100000000450228000100000000cc240000040000000000000000000000000000000000000000000000000000000000000000000000be2554aa8a0151eb4d706308c47d16996af391e4c5e499c7cbef24259b7d4503', + xcmVersion: 3, + }); + }); + it('Should correctly build a submittable extrinsic for a reserveTransferAssets for V3', async () => { + const res = await foreignBaseSystemCreateTx('submittable', false, 3); + expect(res.tx.toRawType()).toEqual('Extrinsic'); + }); + it('Should correctly build a call for a teleportAssets for V3 when the token is native', async () => { + const res = await nativeBaseSystemCreateTx('call', false, 3); + expect(res).toEqual({ + dest: 'bridge-hub-kusama', + origin: 'statemine', + direction: 'SystemToSystem', + format: 'call', + method: 'teleportAssets', + tx: '0x1f0103010100a90f0300010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b030400010000910100000000', + xcmVersion: 3, + }); + }); + it('Should correctly build a payload for a teleportAssets for V3 when the token is native', async () => { + const res = await nativeBaseSystemCreateTx('payload', false, 3); + expect(res).toEqual({ + dest: 'bridge-hub-kusama', + origin: 'statemine', + direction: 'SystemToSystem', + format: 'payload', + method: 'teleportAssets', + tx: '0xe41f0103010100a90f0300010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b030400010000910100000000450228000100000000cc240000040000000000000000000000000000000000000000000000000000000000000000000000be2554aa8a0151eb4d706308c47d16996af391e4c5e499c7cbef24259b7d4503', + xcmVersion: 3, + }); + }); + it('Should correctly build a submittable extrinsic for a teleportAssets for V3 when the token is native', async () => { + const res = await nativeBaseSystemCreateTx('submittable', false, 3); + expect(res.tx.toRawType()).toEqual('Extrinsic'); + }); + it('Should correctly build a call for limitedTeleportAssets for V3 when the token is native', async () => { + const res = await nativeBaseSystemCreateTx('call', true, 3); + expect(res).toEqual({ + dest: 'bridge-hub-kusama', + origin: 'statemine', + direction: 'SystemToSystem', + format: 'call', + method: 'limitedTeleportAssets', + tx: '0x1f0903010100a90f0300010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b03040001000091010000000000', + xcmVersion: 3, + }); + }); + it('Should correctly build a payload for limitedTeleportAssets for V3 when the token is native', async () => { + const res = await nativeBaseSystemCreateTx('payload', true, 3); + expect(res).toEqual({ + dest: 'bridge-hub-kusama', + origin: 'statemine', + direction: 'SystemToSystem', + format: 'payload', + method: 'limitedTeleportAssets', + tx: '0xe81f0903010100a90f0300010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b03040001000091010000000000450228000100000000cc240000040000000000000000000000000000000000000000000000000000000000000000000000be2554aa8a0151eb4d706308c47d16996af391e4c5e499c7cbef24259b7d4503', + xcmVersion: 3, + }); + }); + it('Should correctly build a submittable extrinsic for a limitedTeleportAssets for V3', async () => { + const res = await nativeBaseSystemCreateTx('submittable', true, 3); + expect(res.tx.toRawType()).toEqual('Extrinsic'); + }); + }); + }); + describe('RelayToPara', () => { const baseRelayCreateTx = async ( format: T, From 5e7d332a1415a796d8855544df29f1ace245d991 Mon Sep 17 00:00:00 2001 From: marshacb Date: Mon, 3 Jul 2023 11:46:27 -0400 Subject: [PATCH 11/55] lint --- src/errors/checkXcmTxInputs.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/errors/checkXcmTxInputs.ts b/src/errors/checkXcmTxInputs.ts index 1aab3728..71fa79f0 100644 --- a/src/errors/checkXcmTxInputs.ts +++ b/src/errors/checkXcmTxInputs.ts @@ -392,13 +392,7 @@ export const checkXcmTxInputs = ( /** * Checks to ensure that assetId's are either valid integer numbers or native asset token symbols */ - checkAssetIdInput( - assetIds, - relayChainInfo, - specName, - xcmDirection, - registry - ); + checkAssetIdInput(assetIds, relayChainInfo, specName, xcmDirection, registry); if (xcmDirection === Direction.RelayToSystem) { checkRelayAssetIdLength(assetIds); From 811fc60060e433e977ff3f654ad210a83cab85f4 Mon Sep 17 00:00:00 2001 From: marshacb Date: Thu, 6 Jul 2023 09:33:54 -0400 Subject: [PATCH 12/55] update SystemToSystem fetchAssetType tests --- src/AssetsTransferApi.spec.ts | 9 +++++++++ src/AssetsTransferApi.ts | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/AssetsTransferApi.spec.ts b/src/AssetsTransferApi.spec.ts index 59a11086..932d2385 100644 --- a/src/AssetsTransferApi.spec.ts +++ b/src/AssetsTransferApi.spec.ts @@ -110,6 +110,15 @@ describe('AssetTransferAPI', () => { expect(assetType).toEqual('Native'); }); }); + describe('SystemToSystem', () => { + it('Should corectly return Native', () => { + const assetType = systemAssetsApi['fetchAssetType']( + Direction.SystemToRelay + ); + + expect(assetType).toEqual('Native'); + }); + }); describe('RelayToSystem', () => { it('Should correctly return Native', () => { const assetType = systemAssetsApi['fetchAssetType']( diff --git a/src/AssetsTransferApi.ts b/src/AssetsTransferApi.ts index ddd77e8b..13e865d5 100644 --- a/src/AssetsTransferApi.ts +++ b/src/AssetsTransferApi.ts @@ -661,7 +661,7 @@ export class AssetsTransferApi { * * @param destChainId string * @param registry Registry - * @returns + * @returns string */ private getDestinationSpecName(destId: string, registry: Registry): string { if (destId === '0') { From fc8048c7dae47da4128ec359c181328cee6edb01 Mon Sep 17 00:00:00 2001 From: marshacb Date: Thu, 6 Jul 2023 09:38:01 -0400 Subject: [PATCH 13/55] update AssetTransferApi establishDirection unit test for system to system --- src/AssetsTransferApi.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AssetsTransferApi.spec.ts b/src/AssetsTransferApi.spec.ts index 932d2385..85631bb3 100644 --- a/src/AssetsTransferApi.spec.ts +++ b/src/AssetsTransferApi.spec.ts @@ -26,7 +26,7 @@ const relayAssetsApi = new AssetsTransferApi(adjustedMockRelayApi, 'kusama', 2); describe('AssetTransferAPI', () => { describe('establishDirection', () => { it('Should correctly determine direction for SystemToSystem', () => { - const res = relayAssetsApi['establishDirection']('1000', 'statemint'); + const res = systemAssetsApi['establishDirection']('1000', 'statemint'); expect(res).toEqual('SystemToSystem'); }); it('Should correctly determine direction for SystemToPara', () => { @@ -113,7 +113,7 @@ describe('AssetTransferAPI', () => { describe('SystemToSystem', () => { it('Should corectly return Native', () => { const assetType = systemAssetsApi['fetchAssetType']( - Direction.SystemToRelay + Direction.SystemToSystem ); expect(assetType).toEqual('Native'); From c452575dd4210074424eec00ac4cfc05ece64217 Mon Sep 17 00:00:00 2001 From: marshacb Date: Thu, 6 Jul 2023 10:25:57 -0400 Subject: [PATCH 14/55] update checkIsValidSystemChainAssetId to accept xcm direction --- src/errors/checkXcmTxInputs.spec.ts | 53 +++++++++++++++++++++++++---- src/errors/checkXcmTxInputs.ts | 45 +++++++++++++++++++----- 2 files changed, 82 insertions(+), 16 deletions(-) diff --git a/src/errors/checkXcmTxInputs.spec.ts b/src/errors/checkXcmTxInputs.spec.ts index b11b1254..7cb0329e 100644 --- a/src/errors/checkXcmTxInputs.spec.ts +++ b/src/errors/checkXcmTxInputs.spec.ts @@ -159,19 +159,19 @@ describe('checkAssetIds', () => { 'Statemint', ['1337', 'DOT', '3500000'], Direction.SystemToPara, - `System to Para: integer assetId 3500000 not found in Statemint`, + `SystemToPara: integer assetId 3500000 not found in Statemint`, ], [ 'Statemine', ['KSM', '8', 'stateMineDoge'], Direction.SystemToPara, - `System to Para: assetId stateMineDoge not found for system parachain Statemine`, + `SystemToPara: assetId stateMineDoge not found for system parachain Statemine`, ], [ 'Westmint', ['WND', '250'], Direction.SystemToPara, - `System to Para: integer assetId 250 not found in Westmint`, + `SystemToPara: integer assetId 250 not found in Westmint`, ], ]; @@ -198,19 +198,19 @@ describe('checkAssetIds', () => { 'Statemint', ['1337', 'xcDOT'], Direction.SystemToPara, - `System to Para: assetId xcDOT not found for system parachain Statemint`, + `SystemToPara: assetId xcDOT not found for system parachain Statemint`, ], [ 'Statemine', ['KSM', 'xcMOVR'], Direction.SystemToPara, - `System to Para: assetId xcMOVR not found for system parachain Statemine`, + `SystemToPara: assetId xcMOVR not found for system parachain Statemine`, ], [ 'Westmint', ['WND', 'Test Westend'], Direction.SystemToPara, - `System to Para: assetId Test Westend not found for system parachain Westmint`, + `SystemToPara: assetId Test Westend not found for system parachain Westmint`, ], ]; @@ -263,10 +263,49 @@ describe('checkAssetIds', () => { expect(err).toThrowError(errorMessage); } }); + + it('Should error when direction is SystemToSystem and the string assetId is not found in the system parachains tokens or assets', () => { + const tests: Test[] = [ + [ + 'Statemint', + ['1337', 'xcDOT'], + Direction.SystemToSystem, + `SystemToSystem: assetId xcDOT not found for system parachain Statemint`, + ], + [ + 'Statemine', + ['KSM', 'xcMOVR'], + Direction.SystemToSystem, + `SystemToSystem: assetId xcMOVR not found for system parachain Statemine`, + ], + [ + 'Westmint', + ['WND', 'Test Westend'], + Direction.SystemToSystem, + `SystemToSystem: assetId Test Westend not found for system parachain Westmint`, + ], + ]; + + for (const test of tests) { + const [specName, testInputs, direction, errorMessage] = test; + const registry = new Registry(specName, {}); + const currentRegistry = registry.currentRelayRegistry; + + const err = () => + checkAssetIdInput( + testInputs, + currentRegistry, + specName, + direction, + registry + ); + expect(err).toThrowError(errorMessage); + } + }); }); describe('checkIfNativeRelayChainAssetPresentInMultiAssetIdList', () => { - it('Should error when the relay native asset and system assets are in the same assetIds list when direction', () => { + it('Should error when the relay native asset and system assets are in the same assetIds list when direction is SystemToSystem', () => { const expectErrorMessage = 'Found the relay chains native asset in list ksm,usdc. assetIds list must be empty or only contain the relay chain asset for direction SystemToSystem'; const assetIds = ['ksm', 'usdc']; diff --git a/src/errors/checkXcmTxInputs.ts b/src/errors/checkXcmTxInputs.ts index 71fa79f0..8de4e3be 100644 --- a/src/errors/checkXcmTxInputs.ts +++ b/src/errors/checkXcmTxInputs.ts @@ -224,16 +224,24 @@ const checkSystemToParaAssetId = ( assetId: string, specName: string, relayChainInfo: ChainInfo, - registry: Registry + registry: Registry, + xcmDirection: Direction ) => { - checkIsValidSystemChainAssetId(assetId, specName, relayChainInfo, registry); + checkIsValidSystemChainAssetId( + assetId, + specName, + relayChainInfo, + registry, + xcmDirection + ); }; export const checkIsValidSystemChainAssetId = ( assetId: string, specName: string, relayChainInfo: ChainInfo, - registry: Registry + registry: Registry, + xcmDirection: Direction ) => { const systemChainId = getChainIdBySpecName(registry, specName); const systemParachainInfo = relayChainInfo[systemChainId]; @@ -251,7 +259,7 @@ export const checkIsValidSystemChainAssetId = ( if (assetSymbol === undefined) { throw new BaseError( - `System to Para: integer assetId ${assetId} not found in ${specName}` + `${xcmDirection.toString()}: integer assetId ${assetId} not found in ${specName}` ); } } else { @@ -305,7 +313,7 @@ export const checkIsValidSystemChainAssetId = ( // if no native token for the system parachain was matched, throw an error if (!isValidTokenSymbol) { throw new BaseError( - `System to Para: assetId ${assetId} not found for system parachain ${specName}` + `${xcmDirection.toString()}: assetId ${assetId} not found for system parachain ${specName}` ); } } @@ -322,9 +330,16 @@ const checkSystemToSystemAssetId = ( assetId: string, specName: string, relayChainInfo: ChainInfo, - registry: Registry + registry: Registry, + xcmDirection: Direction ) => { - checkIsValidSystemChainAssetId(assetId, specName, relayChainInfo, registry); + checkIsValidSystemChainAssetId( + assetId, + specName, + relayChainInfo, + registry, + xcmDirection + ); }; /** @@ -362,11 +377,23 @@ export const checkAssetIdInput = ( } if (xcmDirection === Direction.SystemToPara) { - checkSystemToParaAssetId(assetId, specName, relayChainInfo, registry); + checkSystemToParaAssetId( + assetId, + specName, + relayChainInfo, + registry, + xcmDirection + ); } if (xcmDirection === Direction.SystemToSystem) { - checkSystemToSystemAssetId(assetId, specName, relayChainInfo, registry); + checkSystemToSystemAssetId( + assetId, + specName, + relayChainInfo, + registry, + xcmDirection + ); } } }; From 4cd1a9b5679c9c8653141f8491f43ced0cd12f86 Mon Sep 17 00:00:00 2001 From: marshacb Date: Thu, 6 Jul 2023 10:54:38 -0400 Subject: [PATCH 15/55] add tests for getChainidBySpecName --- .../util/getChainIdBySpecName.spec.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/createXcmTypes/util/getChainIdBySpecName.spec.ts diff --git a/src/createXcmTypes/util/getChainIdBySpecName.spec.ts b/src/createXcmTypes/util/getChainIdBySpecName.spec.ts new file mode 100644 index 00000000..c6a7baa4 --- /dev/null +++ b/src/createXcmTypes/util/getChainIdBySpecName.spec.ts @@ -0,0 +1,24 @@ +// Copyright 2023 Parity Technologies (UK) Ltd. + +import { Registry } from '../../registry'; +import { getChainIdBySpecName } from './getChainIdBySpecName'; + +type Test = [expected: string, specName: string, registry: Registry]; + +describe('getChainIdBySpecName', () => { + it('should return the correct chainId when given a valid specName', () => { + const tests: Test[] = [ + ['0', 'kusama', new Registry('kusama', {})], + ['1000', 'statemine', new Registry('statemine', {})], + ['1001', 'collectives', new Registry('collectives', {})], + ['1002', 'bridge-hub-kusama', new Registry('bridge-hub-kusama', {})], + ]; + + for (const test of tests) { + const [expected, specName, registry] = test; + + const result = getChainIdBySpecName(registry, specName); + expect(result).toEqual(expected); + } + }); +}); From 4c11e79d7ab2d10b8fdca1c4859c90be17dfbf68 Mon Sep 17 00:00:00 2001 From: marshacb Date: Thu, 6 Jul 2023 14:06:13 -0400 Subject: [PATCH 16/55] lint --- src/createXcmTypes/SystemToSystem.ts | 3 +-- src/errors/checkXcmTxInputs.spec.ts | 8 +++++++- src/errors/checkXcmTxInputs.ts | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/createXcmTypes/SystemToSystem.ts b/src/createXcmTypes/SystemToSystem.ts index 1862c0ff..d8511945 100644 --- a/src/createXcmTypes/SystemToSystem.ts +++ b/src/createXcmTypes/SystemToSystem.ts @@ -18,7 +18,6 @@ import type { Registry } from '../registry'; import { getFeeAssetItemIndex } from '../util/getFeeAssetItemIndex'; import { normalizeArrToStr } from '../util/normalizeArrToStr'; import { MultiAsset, MultiAssetInterior } from './../types'; -import { isRelayNativeAsset } from './util/isRelayNativeAsset'; import { CreateAssetsOpts, CreateFeeAssetItemOpts, @@ -28,6 +27,7 @@ import { import { dedupeMultiAssets } from './util/dedupeMultiAssets'; import { fetchPalletInstanceId } from './util/fetchPalletInstanceId'; import { getSystemChainTokenSymbolGeneralIndex } from './util/getTokenSymbolGeneralIndex'; +import { isRelayNativeAsset } from './util/isRelayNativeAsset'; import { sortMultiAssetsAscending } from './util/sortMultiAssetsAscending'; export const SystemToSystem: ICreateXcmType = { @@ -300,4 +300,3 @@ export const createSystemToSystemMultiAssets = ( return sortedAndDedupedMultiAssets; }; - diff --git a/src/errors/checkXcmTxInputs.spec.ts b/src/errors/checkXcmTxInputs.spec.ts index 7b61809e..94c4829f 100644 --- a/src/errors/checkXcmTxInputs.spec.ts +++ b/src/errors/checkXcmTxInputs.spec.ts @@ -330,7 +330,13 @@ describe('checkAssetIds', () => { const currentRegistry = registry.currentRelayRegistry; const err = () => - checkAssetIdInput(testInputs, currentRegistry, specName, direction, registry); + checkAssetIdInput( + testInputs, + currentRegistry, + specName, + direction, + registry + ); expect(err).toThrow(errorMessage); } }); diff --git a/src/errors/checkXcmTxInputs.ts b/src/errors/checkXcmTxInputs.ts index 4a580a11..58b5585a 100644 --- a/src/errors/checkXcmTxInputs.ts +++ b/src/errors/checkXcmTxInputs.ts @@ -501,7 +501,7 @@ export const checkXcmTxInputs = ( if (xcmDirection === Direction.SystemToSystem) { checkIfNativeRelayChainAssetPresentInMultiAssetIdList(assetIds, registry); } - + if (xcmDirection === Direction.ParaToSystem) { checkAssetsAmountMatch(assetIds, amounts); } From 90a0c64c0ce0a6860baa29e82774f278751b3c3e Mon Sep 17 00:00:00 2001 From: marshacb Date: Thu, 6 Jul 2023 14:08:29 -0400 Subject: [PATCH 17/55] update docs --- docs/assets/search.js | 2 +- docs/classes/AssetsTransferApi.html | 8 +++---- docs/enums/Direction.html | 28 +++++++++++++++++-------- docs/functions/constructApiPromise.html | 2 +- docs/interfaces/ApiInfo.html | 2 +- docs/interfaces/TransferArgsOpts.html | 16 +++++++------- docs/interfaces/TxResult.html | 16 +++++++------- docs/types/ConstructedFormat.html | 2 +- docs/types/Format.html | 2 +- docs/types/LocalTransferTypes.html | 2 +- docs/types/Methods.html | 2 +- 11 files changed, 46 insertions(+), 36 deletions(-) diff --git a/docs/assets/search.js b/docs/assets/search.js index 8ee79a7c..607c51d5 100644 --- a/docs/assets/search.js +++ b/docs/assets/search.js @@ -1 +1 @@ -window.searchData = JSON.parse("{\"rows\":[{\"kind\":128,\"name\":\"AssetsTransferApi\",\"url\":\"classes/AssetsTransferApi.html\",\"classes\":\"\"},{\"kind\":2048,\"name\":\"createTransferTransaction\",\"url\":\"classes/AssetsTransferApi.html#createTransferTransaction\",\"classes\":\"\",\"parent\":\"AssetsTransferApi\"},{\"kind\":2048,\"name\":\"fetchFeeInfo\",\"url\":\"classes/AssetsTransferApi.html#fetchFeeInfo\",\"classes\":\"\",\"parent\":\"AssetsTransferApi\"},{\"kind\":2048,\"name\":\"decodeExtrinsic\",\"url\":\"classes/AssetsTransferApi.html#decodeExtrinsic\",\"classes\":\"\",\"parent\":\"AssetsTransferApi\"},{\"kind\":256,\"name\":\"ApiInfo\",\"url\":\"interfaces/ApiInfo.html\",\"classes\":\"\"},{\"kind\":64,\"name\":\"constructApiPromise\",\"url\":\"functions/constructApiPromise.html\",\"classes\":\"\"},{\"kind\":8,\"name\":\"Direction\",\"url\":\"enums/Direction.html\",\"classes\":\"\"},{\"kind\":16,\"name\":\"SystemToPara\",\"url\":\"enums/Direction.html#SystemToPara\",\"classes\":\"\",\"parent\":\"Direction\"},{\"kind\":16,\"name\":\"SystemToRelay\",\"url\":\"enums/Direction.html#SystemToRelay\",\"classes\":\"\",\"parent\":\"Direction\"},{\"kind\":16,\"name\":\"ParaToPara\",\"url\":\"enums/Direction.html#ParaToPara\",\"classes\":\"\",\"parent\":\"Direction\"},{\"kind\":16,\"name\":\"ParaToRelay\",\"url\":\"enums/Direction.html#ParaToRelay\",\"classes\":\"\",\"parent\":\"Direction\"},{\"kind\":16,\"name\":\"ParaToSystem\",\"url\":\"enums/Direction.html#ParaToSystem\",\"classes\":\"\",\"parent\":\"Direction\"},{\"kind\":16,\"name\":\"RelayToSystem\",\"url\":\"enums/Direction.html#RelayToSystem\",\"classes\":\"\",\"parent\":\"Direction\"},{\"kind\":16,\"name\":\"RelayToPara\",\"url\":\"enums/Direction.html#RelayToPara\",\"classes\":\"\",\"parent\":\"Direction\"},{\"kind\":4194304,\"name\":\"Format\",\"url\":\"types/Format.html\",\"classes\":\"\"},{\"kind\":4194304,\"name\":\"ConstructedFormat\",\"url\":\"types/ConstructedFormat.html\",\"classes\":\"\"},{\"kind\":4194304,\"name\":\"LocalTransferTypes\",\"url\":\"types/LocalTransferTypes.html\",\"classes\":\"\"},{\"kind\":4194304,\"name\":\"Methods\",\"url\":\"types/Methods.html\",\"classes\":\"\"},{\"kind\":256,\"name\":\"TxResult\",\"url\":\"interfaces/TxResult.html\",\"classes\":\"\"},{\"kind\":1024,\"name\":\"dest\",\"url\":\"interfaces/TxResult.html#dest\",\"classes\":\"\",\"parent\":\"TxResult\"},{\"kind\":1024,\"name\":\"origin\",\"url\":\"interfaces/TxResult.html#origin\",\"classes\":\"\",\"parent\":\"TxResult\"},{\"kind\":1024,\"name\":\"format\",\"url\":\"interfaces/TxResult.html#format\",\"classes\":\"\",\"parent\":\"TxResult\"},{\"kind\":1024,\"name\":\"xcmVersion\",\"url\":\"interfaces/TxResult.html#xcmVersion\",\"classes\":\"\",\"parent\":\"TxResult\"},{\"kind\":1024,\"name\":\"direction\",\"url\":\"interfaces/TxResult.html#direction\",\"classes\":\"\",\"parent\":\"TxResult\"},{\"kind\":1024,\"name\":\"method\",\"url\":\"interfaces/TxResult.html#method\",\"classes\":\"\",\"parent\":\"TxResult\"},{\"kind\":1024,\"name\":\"tx\",\"url\":\"interfaces/TxResult.html#tx\",\"classes\":\"\",\"parent\":\"TxResult\"},{\"kind\":256,\"name\":\"TransferArgsOpts\",\"url\":\"interfaces/TransferArgsOpts.html\",\"classes\":\"\"},{\"kind\":1024,\"name\":\"format\",\"url\":\"interfaces/TransferArgsOpts.html#format\",\"classes\":\"\",\"parent\":\"TransferArgsOpts\"},{\"kind\":1024,\"name\":\"paysWithFeeOrigin\",\"url\":\"interfaces/TransferArgsOpts.html#paysWithFeeOrigin\",\"classes\":\"\",\"parent\":\"TransferArgsOpts\"},{\"kind\":1024,\"name\":\"paysWithFeeDest\",\"url\":\"interfaces/TransferArgsOpts.html#paysWithFeeDest\",\"classes\":\"\",\"parent\":\"TransferArgsOpts\"},{\"kind\":1024,\"name\":\"isLimited\",\"url\":\"interfaces/TransferArgsOpts.html#isLimited\",\"classes\":\"\",\"parent\":\"TransferArgsOpts\"},{\"kind\":1024,\"name\":\"weightLimit\",\"url\":\"interfaces/TransferArgsOpts.html#weightLimit\",\"classes\":\"\",\"parent\":\"TransferArgsOpts\"},{\"kind\":1024,\"name\":\"xcmVersion\",\"url\":\"interfaces/TransferArgsOpts.html#xcmVersion\",\"classes\":\"\",\"parent\":\"TransferArgsOpts\"},{\"kind\":1024,\"name\":\"keepAlive\",\"url\":\"interfaces/TransferArgsOpts.html#keepAlive\",\"classes\":\"\",\"parent\":\"TransferArgsOpts\"}],\"index\":{\"version\":\"2.3.9\",\"fields\":[\"name\",\"comment\"],\"fieldVectors\":[[\"name/0\",[0,31.499]],[\"comment/0\",[]],[\"name/1\",[1,31.499]],[\"comment/1\",[]],[\"name/2\",[2,31.499]],[\"comment/2\",[]],[\"name/3\",[3,31.499]],[\"comment/3\",[]],[\"name/4\",[4,31.499]],[\"comment/4\",[]],[\"name/5\",[5,31.499]],[\"comment/5\",[]],[\"name/6\",[6,26.391]],[\"comment/6\",[]],[\"name/7\",[7,31.499]],[\"comment/7\",[]],[\"name/8\",[8,31.499]],[\"comment/8\",[]],[\"name/9\",[9,31.499]],[\"comment/9\",[]],[\"name/10\",[10,31.499]],[\"comment/10\",[]],[\"name/11\",[11,31.499]],[\"comment/11\",[]],[\"name/12\",[12,31.499]],[\"comment/12\",[]],[\"name/13\",[13,31.499]],[\"comment/13\",[]],[\"name/14\",[14,23.026]],[\"comment/14\",[]],[\"name/15\",[15,31.499]],[\"comment/15\",[]],[\"name/16\",[16,31.499]],[\"comment/16\",[]],[\"name/17\",[17,31.499]],[\"comment/17\",[]],[\"name/18\",[18,31.499]],[\"comment/18\",[]],[\"name/19\",[19,31.499]],[\"comment/19\",[]],[\"name/20\",[20,31.499]],[\"comment/20\",[]],[\"name/21\",[14,23.026]],[\"comment/21\",[]],[\"name/22\",[21,26.391]],[\"comment/22\",[]],[\"name/23\",[6,26.391]],[\"comment/23\",[]],[\"name/24\",[22,31.499]],[\"comment/24\",[]],[\"name/25\",[23,31.499]],[\"comment/25\",[]],[\"name/26\",[24,31.499]],[\"comment/26\",[]],[\"name/27\",[14,23.026]],[\"comment/27\",[]],[\"name/28\",[25,31.499]],[\"comment/28\",[]],[\"name/29\",[26,31.499]],[\"comment/29\",[]],[\"name/30\",[27,31.499]],[\"comment/30\",[]],[\"name/31\",[28,31.499]],[\"comment/31\",[]],[\"name/32\",[21,26.391]],[\"comment/32\",[]],[\"name/33\",[29,31.499]],[\"comment/33\",[]]],\"invertedIndex\":[[\"apiinfo\",{\"_index\":4,\"name\":{\"4\":{}},\"comment\":{}}],[\"assetstransferapi\",{\"_index\":0,\"name\":{\"0\":{}},\"comment\":{}}],[\"constructapipromise\",{\"_index\":5,\"name\":{\"5\":{}},\"comment\":{}}],[\"constructedformat\",{\"_index\":15,\"name\":{\"15\":{}},\"comment\":{}}],[\"createtransfertransaction\",{\"_index\":1,\"name\":{\"1\":{}},\"comment\":{}}],[\"decodeextrinsic\",{\"_index\":3,\"name\":{\"3\":{}},\"comment\":{}}],[\"dest\",{\"_index\":19,\"name\":{\"19\":{}},\"comment\":{}}],[\"direction\",{\"_index\":6,\"name\":{\"6\":{},\"23\":{}},\"comment\":{}}],[\"fetchfeeinfo\",{\"_index\":2,\"name\":{\"2\":{}},\"comment\":{}}],[\"format\",{\"_index\":14,\"name\":{\"14\":{},\"21\":{},\"27\":{}},\"comment\":{}}],[\"islimited\",{\"_index\":27,\"name\":{\"30\":{}},\"comment\":{}}],[\"keepalive\",{\"_index\":29,\"name\":{\"33\":{}},\"comment\":{}}],[\"localtransfertypes\",{\"_index\":16,\"name\":{\"16\":{}},\"comment\":{}}],[\"method\",{\"_index\":22,\"name\":{\"24\":{}},\"comment\":{}}],[\"methods\",{\"_index\":17,\"name\":{\"17\":{}},\"comment\":{}}],[\"origin\",{\"_index\":20,\"name\":{\"20\":{}},\"comment\":{}}],[\"paratopara\",{\"_index\":9,\"name\":{\"9\":{}},\"comment\":{}}],[\"paratorelay\",{\"_index\":10,\"name\":{\"10\":{}},\"comment\":{}}],[\"paratosystem\",{\"_index\":11,\"name\":{\"11\":{}},\"comment\":{}}],[\"payswithfeedest\",{\"_index\":26,\"name\":{\"29\":{}},\"comment\":{}}],[\"payswithfeeorigin\",{\"_index\":25,\"name\":{\"28\":{}},\"comment\":{}}],[\"relaytopara\",{\"_index\":13,\"name\":{\"13\":{}},\"comment\":{}}],[\"relaytosystem\",{\"_index\":12,\"name\":{\"12\":{}},\"comment\":{}}],[\"systemtopara\",{\"_index\":7,\"name\":{\"7\":{}},\"comment\":{}}],[\"systemtorelay\",{\"_index\":8,\"name\":{\"8\":{}},\"comment\":{}}],[\"transferargsopts\",{\"_index\":24,\"name\":{\"26\":{}},\"comment\":{}}],[\"tx\",{\"_index\":23,\"name\":{\"25\":{}},\"comment\":{}}],[\"txresult\",{\"_index\":18,\"name\":{\"18\":{}},\"comment\":{}}],[\"weightlimit\",{\"_index\":28,\"name\":{\"31\":{}},\"comment\":{}}],[\"xcmversion\",{\"_index\":21,\"name\":{\"22\":{},\"32\":{}},\"comment\":{}}]],\"pipeline\":[]}}"); \ No newline at end of file +window.searchData = JSON.parse("{\"rows\":[{\"kind\":128,\"name\":\"AssetsTransferApi\",\"url\":\"classes/AssetsTransferApi.html\",\"classes\":\"\"},{\"kind\":2048,\"name\":\"createTransferTransaction\",\"url\":\"classes/AssetsTransferApi.html#createTransferTransaction\",\"classes\":\"\",\"parent\":\"AssetsTransferApi\"},{\"kind\":2048,\"name\":\"fetchFeeInfo\",\"url\":\"classes/AssetsTransferApi.html#fetchFeeInfo\",\"classes\":\"\",\"parent\":\"AssetsTransferApi\"},{\"kind\":2048,\"name\":\"decodeExtrinsic\",\"url\":\"classes/AssetsTransferApi.html#decodeExtrinsic\",\"classes\":\"\",\"parent\":\"AssetsTransferApi\"},{\"kind\":256,\"name\":\"ApiInfo\",\"url\":\"interfaces/ApiInfo.html\",\"classes\":\"\"},{\"kind\":64,\"name\":\"constructApiPromise\",\"url\":\"functions/constructApiPromise.html\",\"classes\":\"\"},{\"kind\":8,\"name\":\"Direction\",\"url\":\"enums/Direction.html\",\"classes\":\"\"},{\"kind\":16,\"name\":\"SystemToPara\",\"url\":\"enums/Direction.html#SystemToPara\",\"classes\":\"\",\"parent\":\"Direction\"},{\"kind\":16,\"name\":\"SystemToRelay\",\"url\":\"enums/Direction.html#SystemToRelay\",\"classes\":\"\",\"parent\":\"Direction\"},{\"kind\":16,\"name\":\"SystemToSystem\",\"url\":\"enums/Direction.html#SystemToSystem\",\"classes\":\"\",\"parent\":\"Direction\"},{\"kind\":16,\"name\":\"ParaToPara\",\"url\":\"enums/Direction.html#ParaToPara\",\"classes\":\"\",\"parent\":\"Direction\"},{\"kind\":16,\"name\":\"ParaToRelay\",\"url\":\"enums/Direction.html#ParaToRelay\",\"classes\":\"\",\"parent\":\"Direction\"},{\"kind\":16,\"name\":\"ParaToSystem\",\"url\":\"enums/Direction.html#ParaToSystem\",\"classes\":\"\",\"parent\":\"Direction\"},{\"kind\":16,\"name\":\"RelayToSystem\",\"url\":\"enums/Direction.html#RelayToSystem\",\"classes\":\"\",\"parent\":\"Direction\"},{\"kind\":16,\"name\":\"RelayToPara\",\"url\":\"enums/Direction.html#RelayToPara\",\"classes\":\"\",\"parent\":\"Direction\"},{\"kind\":4194304,\"name\":\"Format\",\"url\":\"types/Format.html\",\"classes\":\"\"},{\"kind\":4194304,\"name\":\"ConstructedFormat\",\"url\":\"types/ConstructedFormat.html\",\"classes\":\"\"},{\"kind\":4194304,\"name\":\"LocalTransferTypes\",\"url\":\"types/LocalTransferTypes.html\",\"classes\":\"\"},{\"kind\":4194304,\"name\":\"Methods\",\"url\":\"types/Methods.html\",\"classes\":\"\"},{\"kind\":256,\"name\":\"TxResult\",\"url\":\"interfaces/TxResult.html\",\"classes\":\"\"},{\"kind\":1024,\"name\":\"dest\",\"url\":\"interfaces/TxResult.html#dest\",\"classes\":\"\",\"parent\":\"TxResult\"},{\"kind\":1024,\"name\":\"origin\",\"url\":\"interfaces/TxResult.html#origin\",\"classes\":\"\",\"parent\":\"TxResult\"},{\"kind\":1024,\"name\":\"format\",\"url\":\"interfaces/TxResult.html#format\",\"classes\":\"\",\"parent\":\"TxResult\"},{\"kind\":1024,\"name\":\"xcmVersion\",\"url\":\"interfaces/TxResult.html#xcmVersion\",\"classes\":\"\",\"parent\":\"TxResult\"},{\"kind\":1024,\"name\":\"direction\",\"url\":\"interfaces/TxResult.html#direction\",\"classes\":\"\",\"parent\":\"TxResult\"},{\"kind\":1024,\"name\":\"method\",\"url\":\"interfaces/TxResult.html#method\",\"classes\":\"\",\"parent\":\"TxResult\"},{\"kind\":1024,\"name\":\"tx\",\"url\":\"interfaces/TxResult.html#tx\",\"classes\":\"\",\"parent\":\"TxResult\"},{\"kind\":256,\"name\":\"TransferArgsOpts\",\"url\":\"interfaces/TransferArgsOpts.html\",\"classes\":\"\"},{\"kind\":1024,\"name\":\"format\",\"url\":\"interfaces/TransferArgsOpts.html#format\",\"classes\":\"\",\"parent\":\"TransferArgsOpts\"},{\"kind\":1024,\"name\":\"paysWithFeeOrigin\",\"url\":\"interfaces/TransferArgsOpts.html#paysWithFeeOrigin\",\"classes\":\"\",\"parent\":\"TransferArgsOpts\"},{\"kind\":1024,\"name\":\"paysWithFeeDest\",\"url\":\"interfaces/TransferArgsOpts.html#paysWithFeeDest\",\"classes\":\"\",\"parent\":\"TransferArgsOpts\"},{\"kind\":1024,\"name\":\"isLimited\",\"url\":\"interfaces/TransferArgsOpts.html#isLimited\",\"classes\":\"\",\"parent\":\"TransferArgsOpts\"},{\"kind\":1024,\"name\":\"weightLimit\",\"url\":\"interfaces/TransferArgsOpts.html#weightLimit\",\"classes\":\"\",\"parent\":\"TransferArgsOpts\"},{\"kind\":1024,\"name\":\"xcmVersion\",\"url\":\"interfaces/TransferArgsOpts.html#xcmVersion\",\"classes\":\"\",\"parent\":\"TransferArgsOpts\"},{\"kind\":1024,\"name\":\"keepAlive\",\"url\":\"interfaces/TransferArgsOpts.html#keepAlive\",\"classes\":\"\",\"parent\":\"TransferArgsOpts\"}],\"index\":{\"version\":\"2.3.9\",\"fields\":[\"name\",\"comment\"],\"fieldVectors\":[[\"name/0\",[0,31.781]],[\"comment/0\",[]],[\"name/1\",[1,31.781]],[\"comment/1\",[]],[\"name/2\",[2,31.781]],[\"comment/2\",[]],[\"name/3\",[3,31.781]],[\"comment/3\",[]],[\"name/4\",[4,31.781]],[\"comment/4\",[]],[\"name/5\",[5,31.781]],[\"comment/5\",[]],[\"name/6\",[6,26.672]],[\"comment/6\",[]],[\"name/7\",[7,31.781]],[\"comment/7\",[]],[\"name/8\",[8,31.781]],[\"comment/8\",[]],[\"name/9\",[9,31.781]],[\"comment/9\",[]],[\"name/10\",[10,31.781]],[\"comment/10\",[]],[\"name/11\",[11,31.781]],[\"comment/11\",[]],[\"name/12\",[12,31.781]],[\"comment/12\",[]],[\"name/13\",[13,31.781]],[\"comment/13\",[]],[\"name/14\",[14,31.781]],[\"comment/14\",[]],[\"name/15\",[15,23.308]],[\"comment/15\",[]],[\"name/16\",[16,31.781]],[\"comment/16\",[]],[\"name/17\",[17,31.781]],[\"comment/17\",[]],[\"name/18\",[18,31.781]],[\"comment/18\",[]],[\"name/19\",[19,31.781]],[\"comment/19\",[]],[\"name/20\",[20,31.781]],[\"comment/20\",[]],[\"name/21\",[21,31.781]],[\"comment/21\",[]],[\"name/22\",[15,23.308]],[\"comment/22\",[]],[\"name/23\",[22,26.672]],[\"comment/23\",[]],[\"name/24\",[6,26.672]],[\"comment/24\",[]],[\"name/25\",[23,31.781]],[\"comment/25\",[]],[\"name/26\",[24,31.781]],[\"comment/26\",[]],[\"name/27\",[25,31.781]],[\"comment/27\",[]],[\"name/28\",[15,23.308]],[\"comment/28\",[]],[\"name/29\",[26,31.781]],[\"comment/29\",[]],[\"name/30\",[27,31.781]],[\"comment/30\",[]],[\"name/31\",[28,31.781]],[\"comment/31\",[]],[\"name/32\",[29,31.781]],[\"comment/32\",[]],[\"name/33\",[22,26.672]],[\"comment/33\",[]],[\"name/34\",[30,31.781]],[\"comment/34\",[]]],\"invertedIndex\":[[\"apiinfo\",{\"_index\":4,\"name\":{\"4\":{}},\"comment\":{}}],[\"assetstransferapi\",{\"_index\":0,\"name\":{\"0\":{}},\"comment\":{}}],[\"constructapipromise\",{\"_index\":5,\"name\":{\"5\":{}},\"comment\":{}}],[\"constructedformat\",{\"_index\":16,\"name\":{\"16\":{}},\"comment\":{}}],[\"createtransfertransaction\",{\"_index\":1,\"name\":{\"1\":{}},\"comment\":{}}],[\"decodeextrinsic\",{\"_index\":3,\"name\":{\"3\":{}},\"comment\":{}}],[\"dest\",{\"_index\":20,\"name\":{\"20\":{}},\"comment\":{}}],[\"direction\",{\"_index\":6,\"name\":{\"6\":{},\"24\":{}},\"comment\":{}}],[\"fetchfeeinfo\",{\"_index\":2,\"name\":{\"2\":{}},\"comment\":{}}],[\"format\",{\"_index\":15,\"name\":{\"15\":{},\"22\":{},\"28\":{}},\"comment\":{}}],[\"islimited\",{\"_index\":28,\"name\":{\"31\":{}},\"comment\":{}}],[\"keepalive\",{\"_index\":30,\"name\":{\"34\":{}},\"comment\":{}}],[\"localtransfertypes\",{\"_index\":17,\"name\":{\"17\":{}},\"comment\":{}}],[\"method\",{\"_index\":23,\"name\":{\"25\":{}},\"comment\":{}}],[\"methods\",{\"_index\":18,\"name\":{\"18\":{}},\"comment\":{}}],[\"origin\",{\"_index\":21,\"name\":{\"21\":{}},\"comment\":{}}],[\"paratopara\",{\"_index\":10,\"name\":{\"10\":{}},\"comment\":{}}],[\"paratorelay\",{\"_index\":11,\"name\":{\"11\":{}},\"comment\":{}}],[\"paratosystem\",{\"_index\":12,\"name\":{\"12\":{}},\"comment\":{}}],[\"payswithfeedest\",{\"_index\":27,\"name\":{\"30\":{}},\"comment\":{}}],[\"payswithfeeorigin\",{\"_index\":26,\"name\":{\"29\":{}},\"comment\":{}}],[\"relaytopara\",{\"_index\":14,\"name\":{\"14\":{}},\"comment\":{}}],[\"relaytosystem\",{\"_index\":13,\"name\":{\"13\":{}},\"comment\":{}}],[\"systemtopara\",{\"_index\":7,\"name\":{\"7\":{}},\"comment\":{}}],[\"systemtorelay\",{\"_index\":8,\"name\":{\"8\":{}},\"comment\":{}}],[\"systemtosystem\",{\"_index\":9,\"name\":{\"9\":{}},\"comment\":{}}],[\"transferargsopts\",{\"_index\":25,\"name\":{\"27\":{}},\"comment\":{}}],[\"tx\",{\"_index\":24,\"name\":{\"26\":{}},\"comment\":{}}],[\"txresult\",{\"_index\":19,\"name\":{\"19\":{}},\"comment\":{}}],[\"weightlimit\",{\"_index\":29,\"name\":{\"32\":{}},\"comment\":{}}],[\"xcmversion\",{\"_index\":22,\"name\":{\"23\":{},\"33\":{}},\"comment\":{}}]],\"pipeline\":[]}}"); \ No newline at end of file diff --git a/docs/classes/AssetsTransferApi.html b/docs/classes/AssetsTransferApi.html index b5b8100d..2e3bfa16 100644 --- a/docs/classes/AssetsTransferApi.html +++ b/docs/classes/AssetsTransferApi.html @@ -25,7 +25,7 @@

Hierarchy

  • AssetsTransferApi
+
  • Defined in AssetsTransferApi.ts:63
  • @@ -83,7 +83,7 @@
    Optional Returns Promise<TxResult<T>>
    +
  • Defined in AssetsTransferApi.ts:93
  • +
  • Defined in AssetsTransferApi.ts:503
    • @@ -141,7 +141,7 @@
      format: Returns Promise<null | RuntimeDispatchInfo | RuntimeDispatchInfoV1>
    +
  • Defined in AssetsTransferApi.ts:314
  • +
  • Defined in types.ts:29
  • @@ -35,6 +35,7 @@

    Enumeration Members

    RelayToSystem SystemToPara SystemToRelay +SystemToSystem

    Enumeration Members

    @@ -45,7 +46,7 @@
    +
  • Defined in types.ts:45
  • ParaToRelay: "ParaToRelay"
    @@ -53,7 +54,7 @@
    +
  • Defined in types.ts:49
  • ParaToSystem: "ParaToSystem"
    @@ -61,7 +62,7 @@
    +
  • Defined in types.ts:53
  • RelayToPara: "RelayToPara"
    @@ -69,7 +70,7 @@
    +
  • Defined in types.ts:61
  • RelayToSystem: "RelayToSystem"
    @@ -77,7 +78,7 @@
    +
  • Defined in types.ts:57
  • SystemToPara: "SystemToPara"
    @@ -85,7 +86,7 @@
    +
  • Defined in types.ts:33
  • SystemToRelay: "SystemToRelay"
    @@ -93,7 +94,15 @@
    +
  • Defined in types.ts:37
  • +
    + +
    SystemToSystem: "SystemToSystem"
    +

    System parachain to System parachain chain.

    +
    +
    +
  • Defined in constructApiPromise.ts:24
  • +
  • Defined in types.ts:143
  • xcmVersion: null | number
    @@ -103,7 +103,7 @@

    The xcm version that was used to construct the tx.

    +
  • Defined in types.ts:131
  • +
  • Defined in types.ts:75
  • +
  • Defined in types.ts:91
  • +
  • Defined in types.ts:100
  • +
  • Defined in types.ts:32
  • @@ -46,7 +46,7 @@
    +
  • Defined in types.ts:48
  • ParaToRelay: "ParaToRelay"
    @@ -54,7 +54,7 @@
    +
  • Defined in types.ts:52
  • ParaToSystem: "ParaToSystem"
    @@ -62,7 +62,7 @@
    +
  • Defined in types.ts:56
  • RelayToPara: "RelayToPara"
    @@ -70,7 +70,7 @@
    +
  • Defined in types.ts:64
  • RelayToSystem: "RelayToSystem"
    @@ -78,7 +78,7 @@
    +
  • Defined in types.ts:60
  • SystemToPara: "SystemToPara"
    @@ -86,7 +86,7 @@
    +
  • Defined in types.ts:36
  • SystemToRelay: "SystemToRelay"
    @@ -94,7 +94,7 @@
    +
  • Defined in types.ts:40
  • SystemToSystem: "SystemToSystem"
    @@ -102,7 +102,7 @@
    +
  • Defined in types.ts:44
  • +
  • Defined in types.ts:153
  • xcmVersion: null | number
    @@ -103,7 +103,7 @@

    The xcm version that was used to construct the tx.

    +
  • Defined in types.ts:141
  • +
  • Defined in types.ts:83
  • +
  • Defined in types.ts:99
  • +
  • Defined in types.ts:110