Skip to content

Commit

Permalink
fix: add polkadot delivery fee estimate methods from upstream
Browse files Browse the repository at this point in the history
  • Loading branch information
bvotteler committed Feb 27, 2024
1 parent ce203b8 commit e6e795b
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 8 deletions.
26 changes: 18 additions & 8 deletions src/adapters/polkadot.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AnyApi, FixedPointNumber as FN } from "@acala-network/sdk-core";
import { Storage } from "@acala-network/sdk/utils/storage";
import { Observable, combineLatest, map } from "rxjs";
import { Observable, combineLatest, map, from } from "rxjs";

import { DeriveBalancesAll } from "@polkadot/api-derive/balances/types";
import { SubmittableExtrinsic } from "@polkadot/api/types";
Expand All @@ -16,6 +16,7 @@ import {
CrossChainRouterConfigs,
CrossChainTransferParams,
} from "../types";
import { getPolkadotXcmDeliveryFee } from "src/utils/get-xcm-delivery-fee";

export const polkadotRoutersConfig: Omit<CrossChainRouterConfigs, "from">[] = [
{
Expand Down Expand Up @@ -142,29 +143,38 @@ class BasePolkadotAdapter extends BaseCrossChainAdapter {
public subscribeMaxInput(
token: string,
address: string,
_to: ChainName
to: ChainName
): Observable<FN> {
if (!this.balanceAdapter) {
throw new ApiNotFound(this.chain.id);
}

return combineLatest({
txFee: this.estimateTxFee({
amount: FN.ZERO,
to,
token,
address,
signer: address,
}),
balance: this.balanceAdapter
.subscribeBalance(token, address)
.pipe(map((i) => i.available)),
deliveryFee: from(
getPolkadotXcmDeliveryFee(this.chain.id as ChainName, to, this.api)
),
}).pipe(
map(({ balance }) => {
map(({ balance, txFee, deliveryFee }) => {
const tokenMeta = this.balanceAdapter?.getToken(token);
// fixed fee of 0.05 ksm or DOT until we get paymentinfo to work again
const fee = FN.fromInner(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
0.05 * Math.pow(10, tokenMeta!.decimals),
tokenMeta?.decimals
const feeFactor = 1.2;
const fee = FN.fromInner(txFee, tokenMeta?.decimals).mul(
new FN(feeFactor)
);

// always minus ed
return balance
.minus(fee)
.minus(deliveryFee)
.minus(FN.fromInner(tokenMeta?.ed || "0", tokenMeta?.decimals));
})
);
Expand Down
116 changes: 116 additions & 0 deletions src/utils/get-xcm-delivery-fee.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { AnyApi, FixedPointNumber } from "@acala-network/sdk-core";
import { XcmVersionedXcm } from "@polkadot/types/lookup";
import { Codec, Observable } from "@polkadot/types/types";
import { firstValueFrom } from "rxjs";

import { ChainName, chains } from "../configs";

// refer to https://github.com/albertov19/xcmTools/blob/main/calculateKusamaDeliveryFees.ts
// delivery_fee_factor * (base_fee + encoded_msg_len * per_byte_fee)
// TODO: when most chains added xcm delivery fee, may move these to bridge package

/**
* Only for polkadot and kusama dmp for now
*/
export async function getPolkadotXcmDeliveryFee(
from: ChainName,
to: ChainName,
fromApi?: AnyApi
) {
if (from !== "polkadot" && from !== "kusama") {
throw new Error("from chain must be polkadot or kusama");
}
if (!fromApi) return FixedPointNumber.ZERO;
const decimal = fromApi?.registry.chainDecimals[0];
const paraID = chains[to].paraChainId;

// https://github.com/polkadot-fellows/runtimes/blob/16635f6abda9c5fe4b62231d632ab6f6695b48f7/system-parachains/constants/src/polkadot.rs#L60C29-L60C43
// https://github.com/polkadot-fellows/runtimes/blob/16635f6abda9c5fe4b62231d632ab6f6695b48f7/system-parachains/constants/src/kusama.rs#L38
const UNITS =
from === "polkadot" ? BigInt(10000000000) : BigInt(1000000000000);
const QUID = UNITS / BigInt(30);
const CENTS = QUID / BigInt(100);
// const GRAND = QUID / BigInt(1000);
const MILLICENTS = CENTS / BigInt(1000);

const byteFee = BigInt(10) * MILLICENTS;
const baseDeliveryFee = BigInt(3) * CENTS;

const exampleXcm: XcmVersionedXcm = fromApi?.createType(
"XcmVersionedXcm",
exampleXcmMessage
) as any;
const xcmBytes = exampleXcm.toU8a();

const deliveryFeeFactor: Codec = await (fromApi?.type === "rxjs"
? firstValueFrom(
fromApi?.query.dmp.deliveryFeeFactor(
BigInt(paraID)
) as Observable<Codec>
)
: (fromApi?.query.dmp.deliveryFeeFactor(BigInt(paraID)) as Promise<Codec>));

const convDeliveryFeeFactor =
BigInt(deliveryFeeFactor.toString()) / BigInt(10 ** 18);

const fee =
convDeliveryFeeFactor *
(baseDeliveryFee + BigInt(xcmBytes.length) * byteFee);

return FixedPointNumber.fromInner(fee.toString(), decimal).mul(
new FixedPointNumber(1.2) // add some buffer
);
}

const exampleXcmMessage = {
V3: [
{
WithdrawAsset: [
{
assets: [
{
ConcreteFungible: {
id: "Here",
amount: "20000000000000",
},
},
],
effects: [
{
BuyExecution: {
fees: "0",
weight_limit: {
Unlimited: null,
},
},
},
{
DepositAsset: {
assets: "All",
dest: {
X1: {
Parachain: "2000",
},
},
},
},
{
DepositReserveAsset: {
assets: "All",
dest: {
X1: {
AccountId32: {
network: "Any",
id: "0x76c7e05b8ee00557f8f7e11f283aacd3bbee59c1d9fd588ebbe1b6c435fe504c",
},
},
},
effects: [],
},
},
],
},
],
},
],
};

0 comments on commit e6e795b

Please sign in to comment.