Skip to content

Commit

Permalink
refactor: fee calculation logic and improve modularity.
Browse files Browse the repository at this point in the history
  • Loading branch information
TarekkMA committed Jan 6, 2025
1 parent 66aff79 commit 6ca5fce
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 31 deletions.
30 changes: 19 additions & 11 deletions test/helpers/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
type BlockRangeOption,
EXTRINSIC_BASE_WEIGHT,
WEIGHT_PER_GAS,
calculateFeePortions,
mapExtrinsics,
} from "@moonwall/util";
import type { ApiPromise } from "@polkadot/api";
Expand All @@ -17,6 +16,8 @@ import type { AccountId20, Block } from "@polkadot/types/interfaces/runtime/type
import chalk from "chalk";
import type { Debugger } from "debug";
import Debug from "debug";
import { calculateFeePortions, split } from "./fees.ts";
import { getFeesTreasuryProportion } from "./parameters.ts";

const debug = Debug("test:blocks");

Expand Down Expand Up @@ -149,6 +150,8 @@ export const verifyBlockFees = async (
? (event.data[0] as DispatchInfo)
: (event.data[1] as DispatchInfo);

const feesTreasuryProportion = await getFeesTreasuryProportion(context);

// We are only interested in fee paying extrinsics:
// Either ethereum transactions or signed extrinsics with fees (substrate tx)
if (
Expand Down Expand Up @@ -191,24 +194,29 @@ export const verifyBlockFees = async (
effectiveTipPerGas = 0n;
}

// Calculate the fees paid for base fee independently from tip fee. Both are subject
// to 80/20 split (burn/treasury) but calculating these over the sum of the two
// Calculate the fees paid for base fee independently of tip fee. Both are subject
// to split between (burn/treasury) but calculating these over the sum of the two
// rather than independently leads to off-by-one errors.
const baseFeesPaid = gasUsed * baseFeePerGas;
const tipAsFeesPaid = gasUsed * effectiveTipPerGas;

// TODO: [calculateFeePortions] needs to be updated.
const baseFeePortions = calculateFeePortions(baseFeesPaid);
// we send tips to collator
// const tipFeePortions = calculateFeePortions(tipAsFeesPaid);
const { burnt: baseFeePortionsBurnt } = calculateFeePortions(
feesTreasuryProportion,
baseFeesPaid
);

txFees += baseFeesPaid + tipAsFeesPaid;
txBurnt += baseFeePortions.burnt;
// txBurnt += tipFeePortions.burnt;
txBurnt += baseFeePortionsBurnt;
} else {
// For a regular substrate tx, we use the partialFee
const feePortions = calculateFeePortions(fee.partialFee.toBigInt());
const tipPortions = calculateFeePortions(extrinsic.tip.toBigInt());
const feePortions = calculateFeePortions(
feesTreasuryProportion,
fee.partialFee.toBigInt()
);
const tipPortions = calculateFeePortions(
extrinsic.tip.toBigInt(),
feesTreasuryProportion
);
txFees += fee.partialFee.toBigInt() + extrinsic.tip.toBigInt();
txBurnt += feePortions.burnt + tipPortions.burnt;

Expand Down
31 changes: 31 additions & 0 deletions test/helpers/fees.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { BN } from "@polkadot/util";

/// Recreation of fees.ration(burn_part, treasury_part)
export const split = (value: BN, part1: BN, part2: BN): [BN, BN] => {
const total = part1.add(part2);
if (total.eq(new BN(0)) || value.eq(new BN(0))) {
return [new BN(0), new BN(0)];
}
const part1BN = value.mul(part1).div(total);
const part2BN = value.sub(part1BN);
return [part1BN, part2BN];
};

export const calculateFeePortions = (
feesTreasuryProportion: bigint,
fees: bigint
): {
burnt: bigint;
treasury: bigint;
} => {
const feesBN = new BN(fees.toString());
const treasuryPartBN = new BN(feesTreasuryProportion.toString());
const burntPartBN = new BN(1e9).sub(treasuryPartBN);

const [burntBN, treasuryBN] = split(feesBN, burntPartBN, treasuryPartBN);

return {
burnt: BigInt(burntBN.toString()),
treasury: BigInt(treasuryBN.toString()),
};
};
2 changes: 2 additions & 0 deletions test/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ export * from "./voting";
export * from "./wormhole";
export * from "./xcm";
export * from "./tracingFns";
export * from "./fees.ts";
export * from "./parameters.ts";
14 changes: 14 additions & 0 deletions test/helpers/parameters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { DevModeContext } from "@moonwall/cli";

export const getFeesTreasuryProportion = async (context: DevModeContext): Promise<bigint> => {
const parameter = await context.polkadotJs().query.parameters.parameters({
RuntimeConfig: "FeesTreasuryProportion",
});

// 20% default value
let feesTreasuryProportion = 200_000_000n;
if (parameter.isSome) {
feesTreasuryProportion = parameter.value.asRuntimeConfig.asFeesTreasuryProportion.toBigInt();
}
return feesTreasuryProportion;
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from "@moonwall/util";
import { parameterType, UNIT } from "./test-parameters";
import { BN } from "@polkadot/util";
import { calculateFeePortions } from "../../../../helpers";

interface TestCase {
proportion: Perbill;
Expand All @@ -18,17 +19,6 @@ interface TestCase {
tipAmount: bigint;
}

// Recreation on fees.ration(burn_part, treasury_part)
const split = (value: BN, part1: BN, part2: BN): [BN, BN] => {
const total = part1.add(part2);
if (total.eq(new BN(0)) || value.eq(new BN(0))) {
return [new BN(0), new BN(0)];
}
const part1BN = value.mul(part1).div(total);
const part2BN = value.sub(part1BN);
return [part1BN, part2BN];
};

describeSuite({
id: "DTemp03",
title: "Parameters - RuntimeConfig",
Expand Down Expand Up @@ -80,10 +70,9 @@ describeSuite({
];

for (const t of testCases) {
const burnProportion = new Perbill(new BN(1e9).sub(t.proportion.value()));

const treasuryPerbill = new BN(1e9).sub(t.proportion.value());
const treasuryPercentage = t.proportion.value().toNumber() / 1e7;
const burnPercentage = burnProportion.value().toNumber() / 1e7;
const burnPercentage = 100 - treasuryPercentage;

const calcTreasuryIncrease = (feeWithTip: bigint, tip?: bigint): bigint => {
const issuanceDecrease = calcIssuanceDecrease(feeWithTip, tip);
Expand All @@ -92,13 +81,9 @@ describeSuite({
};
const calcIssuanceDecrease = (feeWithTip: bigint, tip?: bigint): bigint => {
const feeWithTipBN = new BN(feeWithTip.toString());
const [burnFeeWithTipPart, _treasuryFeeWithTipPart] = split(
feeWithTipBN,
burnProportion.value(),
t.proportion.value()
);
const { burnt } = calculateFeePortions(treasuryPerbill, feeWithTipBN);

return BigInt(burnFeeWithTipPart.toString());
return BigInt(burnt.toString());
};

for (const txnType of TransactionTypes) {
Expand Down

0 comments on commit 6ca5fce

Please sign in to comment.