Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: support construction of teleports for parachains' primary native assets to AssetHub #267

Merged
58 changes: 58 additions & 0 deletions examples/paraToSystemParachainPrimaryNative.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* When importing from @substrate/asset-transfer-api it would look like the following
*
* import { AssetsTransferApi, constructApiPromise } from '@substrate/asset-transfer-api'
TarikGul marked this conversation as resolved.
Show resolved Hide resolved
*/
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 MOVR from a Moonriver (Parachain) account
* to a Kusama Asset Hub (System Parachain) account, where the `xcmVersion` is set to 3, and `isLimited` is false declaring that
* it will allow `unlimited` weight for the tx.
*
* NOTE: When `isLimited` is true it will expect for refTime and proofSize to be provided as additional arguments.
*/
const main = async () => {
const { api, specName, safeXcmVersion } = await constructApiPromise(
'wss://moonriver.api.onfinality.io/public-ws'
);
const assetApi = new AssetsTransferApi(api, specName, safeXcmVersion);
let callInfo: TxResult<'call'>;
try {
callInfo = await assetApi.createTransferTransaction(
'1000',
'0xc4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a063',
['movr'], // Note: since it is the primary asset of Moonriver that is being sent to AssetHub, it will be a `teleportAssets` call
['1000000000000'],
{
format: 'call',
isLimited: false,
xcmVersion: 3,
}
);

console.log(
`${PURPLE}The following call data that is returned:\n${GREEN}${JSON.stringify(
callInfo,
null,
4
)}`
);
} 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());
25 changes: 25 additions & 0 deletions src/AssetsTransferApi.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ describe('AssetTransferAPI', () => {
Direction.RelayToSystem,
AssetType.Native,
false,
false,
relayAssetsApi.registry
);

Expand All @@ -217,6 +218,7 @@ describe('AssetTransferAPI', () => {
Direction.RelayToPara,
AssetType.Native,
false,
false,
relayAssetsApi.registry
);

Expand All @@ -232,6 +234,7 @@ describe('AssetTransferAPI', () => {
Direction.SystemToRelay,
AssetType.Native,
false,
false,
systemAssetsApi.registry
);

Expand All @@ -247,6 +250,7 @@ describe('AssetTransferAPI', () => {
Direction.SystemToSystem,
AssetType.Native,
false,
false,
systemAssetsApi.registry
);

Expand All @@ -261,6 +265,7 @@ describe('AssetTransferAPI', () => {
Direction.SystemToSystem,
AssetType.Foreign,
true,
false,
systemAssetsApi.registry
);

Expand All @@ -278,6 +283,7 @@ describe('AssetTransferAPI', () => {
Direction.SystemToPara,
AssetType.Foreign,
true,
false,
systemAssetsApi.registry
);

Expand All @@ -293,6 +299,7 @@ describe('AssetTransferAPI', () => {
Direction.SystemToPara,
AssetType.Foreign,
true,
false,
systemAssetsApi.registry
);

Expand All @@ -308,6 +315,7 @@ describe('AssetTransferAPI', () => {
Direction.ParaToRelay,
AssetType.Foreign,
false,
false,
moonriverAssetsApi.registry
);

Expand All @@ -323,6 +331,21 @@ describe('AssetTransferAPI', () => {
Direction.ParaToSystem,
AssetType.Foreign,
true,
false,
moonriverAssetsApi.registry
);

expect(assetCallType).toEqual('Teleport');
});
it('Should correctly return Teleport when sending the parachains native asset', () => {
const assetCallType = moonriverAssetsApi['fetchCallType'](
'2023',
'1000',
['movr'],
Direction.ParaToSystem,
AssetType.Foreign,
true,
true,
moonriverAssetsApi.registry
);

Expand All @@ -336,6 +359,7 @@ describe('AssetTransferAPI', () => {
Direction.ParaToSystem,
AssetType.Foreign,
true,
false,
moonriverAssetsApi.registry
);

Expand All @@ -351,6 +375,7 @@ describe('AssetTransferAPI', () => {
Direction.ParaToPara,
AssetType.Foreign,
true,
false,
moonriverAssetsApi.registry
);

Expand Down
20 changes: 16 additions & 4 deletions src/AssetsTransferApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
import { assetIdsContainRelayAsset } from './createXcmTypes/util/assetIdsContainsRelayAsset';
import { getAssetId } from './createXcmTypes/util/getAssetId';
import { getChainIdBySpecName } from './createXcmTypes/util/getChainIdBySpecName';
import { isParachainPrimaryNativeAsset } from './createXcmTypes/util/isParachainPrimaryNativeAsset';
import { isSystemChain } from './createXcmTypes/util/isSystemChain';
import { multiLocationAssetIsParachainsNativeAsset } from './createXcmTypes/util/multiLocationAssetIsParachainsNativeAsset';
import {
Expand Down Expand Up @@ -165,10 +166,17 @@ export class AssetsTransferApi {
);
const isForeignAssetsTransfer: boolean =
this.checkIsForeignAssetTransfer(assetIds);
const isPrimaryParachainNativeAsset = isParachainPrimaryNativeAsset(
registry,
_specName,
xcmDirection,
assetIds[0]
);
const xcmPallet = establishXcmPallet(
_api,
xcmDirection,
isForeignAssetsTransfer
isForeignAssetsTransfer,
isPrimaryParachainNativeAsset
);

/**
Expand Down Expand Up @@ -307,6 +315,7 @@ export class AssetsTransferApi {
registry,
isForeignAssetsTransfer,
isLiquidTokenTransfer,
isPrimaryParachainNativeAsset,
{
xcmVersion,
paysWithFeeDest,
Expand All @@ -326,6 +335,7 @@ export class AssetsTransferApi {
xcmDirection,
assetType,
isForeignAssetsTransfer,
isPrimaryParachainNativeAsset,
registry
);

Expand Down Expand Up @@ -715,6 +725,7 @@ export class AssetsTransferApi {
xcmDirection: Direction,
assetType: AssetType,
isForeignAssetsTransfer: boolean,
isParachainPrimaryNativeAsset: boolean,
registry: Registry
): AssetCallType {
// relay to system -> teleport
Expand Down Expand Up @@ -808,9 +819,10 @@ export class AssetsTransferApi {

// para to system only when the assets are native to origin -> teleport
if (
xcmDirection === Direction.ParaToSystem &&
!assetIdsContainRelayAsset(assetIds, registry) &&
originIsMultiLocationsNativeChain
(xcmDirection === Direction.ParaToSystem &&
!assetIdsContainRelayAsset(assetIds, registry) &&
originIsMultiLocationsNativeChain) ||
isParachainPrimaryNativeAsset
) {
return AssetCallType.Teleport;
}
Expand Down
11 changes: 7 additions & 4 deletions src/createXcmCalls/util/establishXcmPallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ export enum XcmPalletName {
export const establishXcmPallet = (
api: ApiPromise,
direction?: Direction,
isForeignAssetsTransfer?: boolean
isForeignAssetsTransfer?: boolean,
isParachainPrimaryNativeAsset?: boolean
): XcmPalletName => {
// checks for the existence of the xTokens pallet
// for direction ParaToSystem, if it exists and the tx is
Expand All @@ -30,7 +31,8 @@ export const establishXcmPallet = (
isXTokensParaToSystemNonForeignAssetsPalletTx(
api,
direction,
isForeignAssetsTransfer
isForeignAssetsTransfer,
isParachainPrimaryNativeAsset
)
) {
return XcmPalletName.xTokens;
Expand All @@ -56,11 +58,12 @@ export const establishXcmPallet = (
const isXTokensParaToSystemNonForeignAssetsPalletTx = (
api: ApiPromise,
direction?: Direction,
isForeignAssetsTransfer?: boolean
isForeignAssetsTransfer?: boolean,
isParachainPrimaryNativeAsset?: boolean
): boolean => {
if (
isForeignAssetsTransfer != undefined &&
!isForeignAssetsTransfer &&
!isParachainPrimaryNativeAsset &&
direction &&
direction === Direction.ParaToSystem &&
api.tx.xTokens
Expand Down
Loading