Skip to content

Commit

Permalink
normalize extrinsic build for xcm versions
Browse files Browse the repository at this point in the history
  • Loading branch information
mmaurello committed Nov 12, 2024
1 parent fe5b688 commit 6b7142d
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 83 deletions.
38 changes: 38 additions & 0 deletions packages/builder/src/extrinsic/ExtrinsicBuilder.utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { SubmittableExtrinsicFunction } from '@polkadot/api/types';
import { getTypeDef } from '@polkadot/types';
import type { AnyJson } from '@polkadot/types/types';
import { u8aToHex } from '@polkadot/util';
import { decodeAddress } from '@polkadot/util-crypto';
import { XcmVersion } from './ExtrinsicBuilder.interfaces';
Expand Down Expand Up @@ -61,3 +62,40 @@ export function getExtrinsicAccount(address: string) {
},
};
}

export function isXcmV4(xcmVersion: XcmVersion): boolean {
return xcmVersion >= XcmVersion.v4;
}

export function normalizeX1(
xcmVersion: XcmVersion,
versionedObject: Record<string, AnyJson>,
) {
if (!isXcmV4(xcmVersion)) {
return versionedObject;
}
const normalizedAssetType = { ...versionedObject };
console.log('normalizedAssetType', normalizedAssetType);
const interior = normalizedAssetType.interior;
if (interior && typeof interior === 'object' && !Array.isArray(interior)) {
const key = 'X1' in interior ? 'X1' : 'x1' in interior ? 'x1' : null;
if (key && !Array.isArray(interior[key])) {
interior[key] = [interior[key]];
}
}

return normalizedAssetType;
}

export function normalizeConcrete(
xcmVersion: XcmVersion,
versionedObject: object,
) {
return isXcmV4(xcmVersion) ? versionedObject : applyConcreteWrapper;
}

function applyConcreteWrapper(versionedObject: object) {
return {
Concrete: { ...versionedObject },
};
}
97 changes: 49 additions & 48 deletions packages/builder/src/extrinsic/pallets/polkadotXcm/polkadotXcm.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { ExtrinsicConfig } from '../../../types/substrate/ExtrinsicConfig';
import type { ExtrinsicConfigBuilder } from '../../ExtrinsicBuilder.interfaces';
import {
getExtrinsicArgumentVersion,
normalizeConcrete,
} from '../../ExtrinsicBuilder.utils';
import {
getPolkadotXcmExtrinsicArgs,
shouldFeeAssetPrecedeAsset,
Expand Down Expand Up @@ -75,25 +79,24 @@ export function polkadotXcm() {
func,
getArgs: (extrinsicFunction) => {
const isAssetDifferent = !params.asset.isSame(params.fee);
const version = getExtrinsicArgumentVersion(extrinsicFunction);

const assets = [
{
id: {
Concrete: {
parents: 0,
interior: {
X2: [
{
PalletInstance:
params.asset.getAssetPalletInstance(),
},
{
GeneralIndex: params.asset.getAssetId(),
},
],
},
id: normalizeConcrete(version, {
parents: 0,
interior: {
X2: [
{
PalletInstance:
params.asset.getAssetPalletInstance(),
},
{
GeneralIndex: params.asset.getAssetId(),
},
],
},
},
}),
fun: {
Fungible: params.asset.amount,
},
Expand All @@ -105,22 +108,19 @@ export function polkadotXcm() {

if (isAssetDifferent) {
const feeAsset = {
id: {
Concrete: {
parents: 0,
interior: {
X2: [
{
PalletInstance:
params.fee.getAssetPalletInstance(),
},
{
GeneralIndex: params.fee.getAssetId(),
},
],
},
id: normalizeConcrete(version, {
parents: 0,
interior: {
X2: [
{
PalletInstance: params.fee.getAssetPalletInstance(),
},
{
GeneralIndex: params.fee.getAssetId(),
},
],
},
},
}),
fun: {
Fungible: params.fee.amount,
},
Expand Down Expand Up @@ -153,34 +153,35 @@ export function polkadotXcm() {
new ExtrinsicConfig({
module: pallet,
func,
getArgs: (extrinsicFunction) =>
getPolkadotXcmExtrinsicArgs({
getArgs: (extrinsicFunction) => {
const version = getExtrinsicArgumentVersion(extrinsicFunction);

return getPolkadotXcmExtrinsicArgs({
...params,
func: extrinsicFunction,
asset: [
{
id: {
Concrete: {
parents: 1,
interior: {
X2: [
{
Parachain: params.destination.parachainId,
},
{
PalletInstance:
params.asset.getAssetPalletInstance(),
},
],
},
id: normalizeConcrete(version, {
parents: 1,
interior: {
X2: [
{
Parachain: params.destination.parachainId,
},
{
PalletInstance:
params.asset.getAssetPalletInstance(),
},
],
},
},
}),
fun: {
Fungible: params.asset.amount,
},
},
],
}),
});
},
}),
}),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { Parents } from '../../ExtrinsicBuilder.interfaces';
import {
getExtrinsicAccount,
getExtrinsicArgumentVersion,
normalizeX1,
} from '../../ExtrinsicBuilder.utils';

export interface GetExtrinsicParams extends BuilderParams {
Expand All @@ -27,22 +28,22 @@ export function getPolkadotXcmExtrinsicArgs({

return [
{
[version]: {
[version]: normalizeX1(version, {
parents,
interior: {
X1: {
Parachain: destination.parachainId,
},
},
},
}),
},
{
[version]: {
[version]: normalizeX1(version, {
parents: 0,
interior: {
X1: getExtrinsicAccount(destinationAddress),
},
},
}),
},
{
[version]: asset,
Expand Down
39 changes: 8 additions & 31 deletions packages/builder/src/fee/FeeBuilder.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type {
ChainAsset,
ChainAssetId,
} from '@moonbeam-network/xcm-types';
import { isHexString } from '@moonbeam-network/xcm-utils';
import type { ApiPromise } from '@polkadot/api';
import type { Option, Result, u128 } from '@polkadot/types';
import type {
Expand All @@ -12,6 +11,10 @@ import type {
} from '@polkadot/types/interfaces';
import type { AnyJson } from '@polkadot/types/types';
import { XcmVersion } from '../extrinsic';
import {
normalizeConcrete,
normalizeX1,
} from '../extrinsic/ExtrinsicBuilder.utils';
import type { MoonbeamRuntimeXcmConfigAssetType } from './FeeBuilder.interfaces';

const DEFAULT_AMOUNT = 10 ** 6;
Expand All @@ -24,23 +27,6 @@ function isXcmV4() {
return XCM_VERSION === XcmVersion.v4;
}

function normalizeX1(assetType: Record<string, AnyJson>) {
if (!isXcmV4()) {
return assetType;
}
const normalizedAssetType = { ...assetType };
if (
normalizedAssetType.interior &&
typeof normalizedAssetType.interior === 'object' &&
'x1' in normalizedAssetType.interior
) {
if (!Array.isArray(normalizedAssetType.interior.x1)) {
normalizedAssetType.interior.x1 = [normalizedAssetType.interior.x1];
}
}
return normalizedAssetType;
}

export function getWithdrawAssetInstruction(assetTypes: object[]) {
return {
WithdrawAsset: assetTypes.map((assetType) => ({
Expand Down Expand Up @@ -121,12 +107,6 @@ export function getSetTopicInstruction() {
};
}

function applyConcreteWrapper(id: object) {
return {
Concrete: { ...id },
};
}

// TODO this is for Moonbeam, when applying to all we have to
// configure the multilocation of the native asset in the chain
function getNativeAssetId(palletInstanceNumber: number | undefined): object {
Expand All @@ -145,8 +125,7 @@ function getNativeAssetId(palletInstanceNumber: number | undefined): object {
},
parents: '0',
};

return isXcmV4() ? id : applyConcreteWrapper(id);
return normalizeConcrete(XCM_VERSION, id);
}

function getConcreteAssetIdWithAccountKey20(
Expand Down Expand Up @@ -175,7 +154,7 @@ function getConcreteAssetIdWithAccountKey20(
},
parents: '0',
};
return isXcmV4() ? id : applyConcreteWrapper(id);
return normalizeConcrete(XCM_VERSION, id);
}

export async function getAssetIdType(
Expand Down Expand Up @@ -212,11 +191,9 @@ export async function getVersionedAssetId(
const assetType = await getAssetIdType(api, assetId);
const assetTypeObject = assetType.unwrap().asXcm.toJSON();

const normalizedAssetTypeObject = normalizeX1(assetTypeObject);
const normalizedAssetTypeObject = normalizeX1(XCM_VERSION, assetTypeObject);

return isXcmV4()
? normalizedAssetTypeObject
: applyConcreteWrapper(normalizedAssetTypeObject);
return normalizeConcrete(XCM_VERSION, normalizedAssetTypeObject);
}

export async function getFeeForXcmInstructionsAndAsset(
Expand Down

0 comments on commit 6b7142d

Please sign in to comment.