Skip to content

Commit

Permalink
refactor Batcher Fee reduction (#43)
Browse files Browse the repository at this point in the history
* refactor Batcher Fee reduction

* update docs

* env for testnet

---------

Co-authored-by: Mingggggg <[email protected]>
Co-authored-by: Ha Quang Minh <[email protected]>
  • Loading branch information
3 people authored Nov 6, 2024
1 parent 425261a commit 0df20dd
Show file tree
Hide file tree
Showing 8 changed files with 662 additions and 425 deletions.
2 changes: 1 addition & 1 deletion docs/transaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ This documentation provides details on how to interact with the **Stableswap** a

Currently, everyone who swaps on the Minswap DEX pays a 2 $ADA fee to execute the DEX order. To increase the utility of the $MIN token within the platform, $MIN holders are entitled to a discount on this 2 $ADA Batcher Fee. More details about this can be found in the [Minswap Official Docs](https://docs.minswap.org/min-token/usdmin-tokenomics/trading-fee-discount).

Technically, the Batcher Fee Discount is calculated based on the ADA-MIN LP Tokens and MIN tokens that users are holding. This calculation is handled by the [calculateBatcherFee](../src/batcher-fee-reduction/calculate.ts) function.
Technically, the Batcher Fee Discount is calculated based on the ADA-MIN LP Tokens and MIN tokens that users are holding. This calculation is handled by the [BatcherFee.finalizeFee](../src/batcher-fee-reduction/calculate.ts#L11) function.

If you are transacting through the `Stableswap` or `DexV2` classes, the transaction is automatically constructed with the Batcher Fee Discount if you are eligible for it.

Expand Down
152 changes: 103 additions & 49 deletions src/batcher-fee-reduction/calculate.ts
Original file line number Diff line number Diff line change
@@ -1,60 +1,114 @@
import BigNumber from "bignumber.js";
import { Assets, UTxO } from "lucid-cardano";

import { NetworkEnvironment } from "../types/network";
import {
BATCHER_FEE_CONFIG,
getActiveBatcherFee,
getReducedBatcherFee,
BatcherFeeConfig,
BatcherFeeReductionConfig,
DexVersion,
} from "./configs.internal";
import { DexVersion } from "./types.internal";

export function calculateBatcherFee({
utxos,
orderAssets,
dexVersion,
networkEnv,
}: {
dexVersion: DexVersion;
utxos: UTxO[];
orderAssets: Assets;
networkEnv: NetworkEnvironment;
}): {
batcherFee: bigint;
reductionAssets: Assets;
} {
const reductionAssets: Assets = {};
const standardFee = BATCHER_FEE_CONFIG[networkEnv][dexVersion].standardFee;
const activeBatcherFeeConfig = getActiveBatcherFee(networkEnv, dexVersion);
if (!activeBatcherFeeConfig) {
return {
batcherFee: standardFee,
reductionAssets,
};
}
const totalAssets: Assets = {};
for (const u of utxos) {
for (const [asset, amount] of Object.entries(u.assets)) {
if (asset in totalAssets) {
totalAssets[asset] += amount;
} else {
totalAssets[asset] = amount;

export namespace BatcherFee {
export function getFinalFee({
config,
reductionAssets,
}: {
config: BatcherFeeReductionConfig;
reductionAssets: Assets;
}): bigint {
if (Object.keys(reductionAssets).length === 0) {
return config.maxFee;
}
const { assets, minFee } = config;
// Calculate total amount ratio through each reduction asset
// The ratio is: current amount in wallet / maximum amount
let totalReductionAmountRatio = new BigNumber(0);
for (const { asset, maximumAmount } of assets) {
if (asset in reductionAssets) {
const reductionAmount = new BigNumber(reductionAssets[asset].toString())
.div(maximumAmount.toString());
totalReductionAmountRatio =
totalReductionAmountRatio.plus(reductionAmount);
}
}

// Maximum ratio is 1
const maximumReductionAmountRatio = totalReductionAmountRatio.isGreaterThanOrEqualTo(new BigNumber(1))
? new BigNumber(1)
: totalReductionAmountRatio;

const maximumReduction = new BigNumber(config.maxFee.toString())
.minus(minFee.toString())
.div(config.maxFee.toString())
.multipliedBy(100);

// Apply the ratio to calculate batcher fee reduction
const totalReduction = new BigNumber(maximumReduction).multipliedBy(maximumReductionAmountRatio).div(100);

// New batcher fee = (1 - reduction) * DEFAULT BATCHER FEE
const finalFee = new BigNumber(1)
.minus(totalReduction)
.multipliedBy(new BigNumber(config.maxFee.toString()))
.toFixed(0);

return BigInt(finalFee);
}
for (const { asset } of activeBatcherFeeConfig.assets) {
if (asset in totalAssets) {
reductionAssets[asset] = totalAssets[asset];
if (asset in orderAssets) {
reductionAssets[asset] -= orderAssets[asset];

export function finalizeFee({
networkEnv,
currentDate,
dexVersion,
utxos,
orderAssets
}: {
networkEnv: NetworkEnvironment;
currentDate: Date,
dexVersion: DexVersion;
utxos: UTxO[];
orderAssets: Assets;
}): {
batcherFee: bigint;
reductionAssets: Assets;
} {
const defaultFee = BatcherFeeConfig.CONFIG[networkEnv][dexVersion].defaultFee;
const activeReductionConfig = BatcherFeeConfig.getActiveConfig({
networkEnv,
dexVersion,
currentDate
});

if (activeReductionConfig === undefined) {
return {
batcherFee: defaultFee,
reductionAssets: {}
}
}

const reductionAssets: Assets = {};
const totalAssets: Assets = {};
for (const u of utxos) {
for (const [asset, amount] of Object.entries(u.assets)) {
if (asset in totalAssets) {
totalAssets[asset] += amount;
} else {
totalAssets[asset] = amount;
}
}
}
for (const { asset } of activeReductionConfig.assets) {
if (asset in totalAssets) {
reductionAssets[asset] = totalAssets[asset];
if (asset in orderAssets) {
reductionAssets[asset] -= orderAssets[asset];
}
}
}
return {
batcherFee: getFinalFee({
config: activeReductionConfig,
reductionAssets: reductionAssets
}),
reductionAssets: reductionAssets,
};
}
return {
batcherFee: getReducedBatcherFee(
standardFee,
activeBatcherFeeConfig,
reductionAssets
),
reductionAssets: reductionAssets,
};
}
}
Loading

0 comments on commit 0df20dd

Please sign in to comment.