Skip to content

Commit

Permalink
Apply XcmPaymentApi fees in transactions to Moonbeam / Moonriver / Mo…
Browse files Browse the repository at this point in the history
…onbase-Alpha (#351)

* -wip- initial commit and initial configs

* -wip- extract common code

* -wip- fix some types

* -wip- TODOs and refactoring

* -wip- group all in a single function

* -wip- apply to all Acala and Hydration routes

* -wip- apply to manta routes

* apply xcmv4 and solution for registered asset id for ERC20s

* sort assets, handle different palletInstances and apply to several configs

* remove unused property

* remove logs

* remove deleted routes from snapshots

* apply new configuration to Kusama chains

* add changeset

* remove assetTypeUnitsPerSecond function since it is not used now

* remove assetTypeUnitsPerSecond function since it is not used now

* apply PR reviews
  • Loading branch information
mmaurello authored Sep 24, 2024
1 parent 59027cf commit 2a7ed04
Show file tree
Hide file tree
Showing 60 changed files with 700 additions and 231 deletions.
8 changes: 8 additions & 0 deletions .changeset/young-mice-shout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@moonbeam-network/xcm-builder': minor
'@moonbeam-network/xcm-config': minor
'@moonbeam-network/xcm-types': minor
'@moonbeam-network/xcm-sdk': minor
---

Implement XcmPaymentApi to calculate fees for routes going to Moonbeam / Moonriver / Moonbase-Alpha
10 changes: 6 additions & 4 deletions mkdocs/docs/contribute.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Follow these steps:
3. Add your asset to the `assetsList` array at the end of the file

!!! note
Assets are listed in alphabetical order. Please make sure you follow this order when adding new assets.
Assets are listed in alphabetical order. Please make sure you follow this order when adding new assets.

## Add a Chain

Expand Down Expand Up @@ -120,7 +120,7 @@ To add a chain, take the following steps:
4. Add the newly created chain to the `chainsList` array at the end of the file

!!! note
Chains are listed in alphabetical order. Please make sure you follow this order when adding new chains.
Chains are listed in alphabetical order. Please make sure you follow this order when adding new chains.

Now that you've added the chain, you can continue to the next section to add the assets that this chain supports.

Expand Down Expand Up @@ -242,7 +242,7 @@ Assuming that all of the required pallets and methods are already supported, you
4. Add the newly created chain configurations to the `chainsConfigList` in the `xcm-sdk/blob/main/packages/config/src/configs/index.ts` file

!!! note
Chain configurations are listed in alphabetical order. Please follow this order when adding new chain configurations.
Chain configurations are listed in alphabetical order. Please follow this order when adding new chain configurations.

For example, to add support to transfer USDT from the Polkadot Asset Hub to Moonbeam, the Polkadot Asset Hub configuration file is as follows:

Expand All @@ -267,7 +267,9 @@ export const polkadotAssetHubConfig = new ChainConfig({
balance: BalanceBuilder().substrate().assets().account(),
destination: moonbeam,
destinationFee: {
amount: FeeBuilder().assetManager().assetTypeUnitsPerSecond(),
amount: FeeBuilder()
.xcmPaymentApi()
.xcmPaymentFee({ isAssetReserveChain: false }),
asset: usdt,
balance: BalanceBuilder().substrate().assets().account(),
},
Expand Down
14 changes: 10 additions & 4 deletions mkdocs/docs/reference/interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Defines an asset's key and symbol used on the asset's origin chain.
Defines properties related to an asset, including `Asset` properties, the decimals and symbol of the asset, and the amount an associated source or destination address has of the asset.

!!! note
A few utility methods are available for working with the `AssetAmount` class that converts the amount to various formats. Please refer to the [Methods for Asset Conversions](./methods.md#asset-utilities) section.
A few utility methods are available for working with the `AssetAmount` class that converts the amount to various formats. Please refer to the [Methods for Asset Conversions](./methods.md#asset-utilities) section.

**Attributes**

Expand Down Expand Up @@ -692,7 +692,9 @@ Defines a chain's configurations, including information for each chain's support
balance: BalanceBuilder().substrate().assets().account(),
destination: moonbeam,
destinationFee: {
amount: FeeBuilder().assetManager().assetTypeUnitsPerSecond(),
amount: FeeBuilder()
.xcmPaymentApi()
.xcmPaymentFee({ isAssetReserveChain: false }),
asset: usdt,
balance: BalanceBuilder().substrate().assets().account(),
},
Expand Down Expand Up @@ -762,7 +764,9 @@ Defines an asset's configurations for a source chain and includes information ab
balance: BalanceBuilder().substrate().assets().account(),
destination: moonbeam,
destinationFee: {
amount: FeeBuilder().assetManager().assetTypeUnitsPerSecond(),
amount: FeeBuilder()
.xcmPaymentApi()
.xcmPaymentFee({ isAssetReserveChain: false }),
asset: usdt,
balance: BalanceBuilder().substrate().assets().account(),
},
Expand Down Expand Up @@ -832,7 +836,9 @@ Defines the fees for a particular asset on the destination chain.
{
asset: dot,
balance: BalanceBuilder().substrate().system().account(),
amount: FeeBuilder().assetManager().assetTypeUnitsPerSecond(),
amount: amount: FeeBuilder()
.xcmPaymentApi()
.xcmPaymentFee({ isAssetReserveChain: false }),
}
```

Expand Down
20 changes: 18 additions & 2 deletions packages/builder/src/fee/FeeBuilder.interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
import { ChainAssetId } from '@moonbeam-network/xcm-types';
import { AnyParachain, ChainAssetId } from '@moonbeam-network/xcm-types';
import { ApiPromise } from '@polkadot/api';
import { Enum } from '@polkadot/types';
import { StagingXcmV3MultiLocation } from '@polkadot/types/lookup';
import { SubstrateCallConfig } from '../types/substrate/SubstrateCallConfig';

export interface FeeConfigBuilder {
build: (params: FeeConfigBuilderPrams) => SubstrateCallConfig;
}

export interface FeeConfigBuilderPrams {
asset: ChainAssetId;
address: string;
api: ApiPromise;
feeAsset: ChainAssetId;
transferAsset: ChainAssetId;
chain: AnyParachain;
}

export interface XcmPaymentFeeProps {
isAssetReserveChain: boolean;
shouldTransferAssetPrecedeAsset?: boolean;
}

export interface MoonbeamRuntimeXcmConfigAssetType extends Enum {
readonly isXcm: boolean;
readonly asXcm: StagingXcmV3MultiLocation;
readonly type: 'Xcm';
}
68 changes: 47 additions & 21 deletions packages/builder/src/fee/FeeBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,67 @@
/* eslint-disable sort-keys */
/* eslint-disable @typescript-eslint/no-use-before-define */

import { Option, u128 } from '@polkadot/types';
import { SubstrateCallConfig } from '../types/substrate/SubstrateCallConfig';
import { FeeConfigBuilder } from './FeeBuilder.interfaces';
import { FeeConfigBuilder, XcmPaymentFeeProps } from './FeeBuilder.interfaces';
import {
getBuyExecutionInstruction,
getClearOriginInstruction,
getDepositAssetInstruction,
getFeeForXcmInstructionsAndAsset,
getReserveAssetDepositedInstruction,
getSetTopicInstruction,
getVersionedAssetId,
getWithdrawAssetInstruction,
} from './FeeBuilder.utils';

export function FeeBuilder() {
return {
assetManager,
xcmPaymentApi,
};
}

function assetManager() {
function xcmPaymentApi() {
return {
assetTypeUnitsPerSecond: (weight = 1_000_000_000): FeeConfigBuilder => ({
build: ({ api, asset }) =>
xcmPaymentFee: ({
isAssetReserveChain,
shouldTransferAssetPrecedeAsset = false,
}: XcmPaymentFeeProps): FeeConfigBuilder => ({
build: ({ address, api, feeAsset, chain, transferAsset }) =>
new SubstrateCallConfig({
api,
call: async (): Promise<bigint> => {
const type = (await api.query.assetManager.assetIdType(
asset,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
)) as unknown as Option<any>;
const versionedAssetId = await getVersionedAssetId(
api,
feeAsset,
chain,
);
const versionedTransferAssetId = await getVersionedAssetId(
api,
transferAsset,
chain,
);
const versionedAssets = shouldTransferAssetPrecedeAsset
? [versionedTransferAssetId, versionedAssetId]
: [versionedAssetId, versionedTransferAssetId];

if (type.isNone) {
throw new Error(`No asset type found for asset ${asset}`);
}
const assets =
feeAsset === transferAsset ? [versionedAssetId] : versionedAssets;

const unwrappedType = type.unwrap();
const instructions = [
isAssetReserveChain
? getWithdrawAssetInstruction(assets)
: getReserveAssetDepositedInstruction(assets),
getClearOriginInstruction(),
getBuyExecutionInstruction(versionedAssetId),
getDepositAssetInstruction(address, assets),
getSetTopicInstruction(),
];

const res = (await api.query.assetManager.assetTypeUnitsPerSecond(
unwrappedType,
)) as unknown as Option<u128>;

const unitsPerSecond = res.unwrapOrDefault().toBigInt();

return (BigInt(weight) * unitsPerSecond) / BigInt(10 ** 12);
return getFeeForXcmInstructionsAndAsset(
api,
instructions,
versionedAssetId,
);
},
}),
}),
Expand Down
Loading

0 comments on commit 2a7ed04

Please sign in to comment.