Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion tests/tests/test-fees/test-fee-multiplier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import {
} from "../../util/xcm";
import { expectOk } from "../../util/expect";
import { KeyringPair } from "@substrate/txwrapper-core";
import { TARGET_FILL_AMOUNT } from "../../util/constants";
import { GLMR, TARGET_FILL_AMOUNT, WEIGHT_FEE } from "../../util/constants";
import { verifyLatestBlockFees } from "../../util/block";

// Note on the values from 'transactionPayment.nextFeeMultiplier': this storage item is actually a
// FixedU128, which is basically a u128 with an implicit denominator of 10^18. However, this
Expand Down Expand Up @@ -425,3 +426,42 @@ describeDevMoonbeam("Fee Multiplier - XCM Executions", (context) => {
expect(initialValue.eq(postValue), "Fee Multiplier has changed between blocks").to.be.true;
});
});

describeDevMoonbeam("TransactionPayment Runtime Queries", (context) => {
it("should be able to query length fee", async function () {
// this test is really meant to show that `queryLengthToFee()` works, but for the inquisitive,
// this is how our length fee is calculated:
// fee = N**3 + N * 1_000_000_000 (where N: size_in_bytes):
const numBytes = 1n;
const coefficient = 1_000_000_000n;
const exponent = 3n;
const expected = numBytes ** exponent + numBytes * coefficient;

const adjusted_length_fee =
await context.polkadotApi.call.transactionPaymentApi.queryLengthToFee(numBytes);
expect(adjusted_length_fee.toBigInt()).to.eq(expected);
});

it("should be able to query weight fee", async function () {
const adjusted_weight_fee =
await context.polkadotApi.call.transactionPaymentApi.queryWeightToFee({
refTime: 1,
proofSize: 1,
});
expect(adjusted_weight_fee.toBigInt()).to.eq(WEIGHT_FEE);
});

it("should be able to calculate entire fee", async function () {
const tx = await context.polkadotApi.tx.balances.transfer(alith.address, GLMR).signAsync(alith);
const result = await context.createBlock(tx);
await verifyLatestBlockFees(context);
});

it("should be able to calculate entire fee including tip", async function () {
const tx = await context.polkadotApi.tx.balances
.transfer(alith.address, GLMR)
.signAsync(alith, { tip: 123 });
const result = await context.createBlock(tx);
await verifyLatestBlockFees(context);
});
});
44 changes: 39 additions & 5 deletions tests/util/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
import { FrameSystemEventRecord, SpWeightsWeightV2Weight } from "@polkadot/types/lookup";
import { u32, u64, u128, Option } from "@polkadot/types";
import { expect } from "chai";
import { WEIGHT_PER_GAS } from "./constants";

import { EXTRINSIC_BASE_WEIGHT, WEIGHT_PER_GAS } from "./constants";
import { DevTestContext } from "./setup-dev-tests";
import { rateLimiter } from "./common";
import type { Block, AccountId20 } from "@polkadot/types/interfaces/runtime/types";
Expand Down Expand Up @@ -138,7 +139,9 @@ export const verifyBlockFees = async (
let blockBurnt = 0n;

// iterate over every extrinsic
for (const { events, extrinsic, fee } of blockDetails.txWithEvents) {
for (const txWithEvents of blockDetails.txWithEvents) {
let { events, extrinsic, fee } = txWithEvents;

// This hash will only exist if the transaction was executed through ethereum.
let ethereumAddress = "";

Expand Down Expand Up @@ -217,9 +220,40 @@ export const verifyBlockFees = async (
txBurnt += tipFeePortions.burnt;
} else {
// For a regular substrate tx, we use the partialFee
let feePortions = calculateFeePortions(fee.partialFee.toBigInt());
txFees = fee.partialFee.toBigInt();
txBurnt += feePortions.burnt;
const feePortions = calculateFeePortions(fee.partialFee.toBigInt());
const tipPortions = calculateFeePortions(extrinsic.tip.toBigInt());
txFees += fee.partialFee.toBigInt() + extrinsic.tip.toBigInt();
txBurnt += feePortions.burnt + tipPortions.burnt;

// verify entire substrate txn fee
const apiAt = await context.polkadotApi.at(previousBlockHash);
const lengthFee = (
(await apiAt.call.transactionPaymentApi.queryLengthToFee(
extrinsic.encodedLength
)) as any
).toBigInt();

const unadjustedWeightFee = (
(await apiAt.call.transactionPaymentApi.queryWeightToFee({
refTime: fee.weight,
proofSize: 0n,
})) as any
).toBigInt();
const multiplier = await apiAt.query.transactionPayment.nextFeeMultiplier();
const denominator = 1_000_000_000_000_000_000n;
const weightFee = (unadjustedWeightFee * multiplier.toBigInt()) / denominator;

const baseFee = (
(await apiAt.call.transactionPaymentApi.queryWeightToFee({
refTime: EXTRINSIC_BASE_WEIGHT,
proofSize: 0n,
})) as any
).toBigInt();

const tip = extrinsic.tip.toBigInt();
const expectedPartialFee = lengthFee + weightFee + baseFee;

expect(expectedPartialFee).to.eq(fee.partialFee.toBigInt());
}

blockFees += txFees;
Expand Down