Fee Structure
Overview
JAMM DEX implements a flexible, multi-tier fee system, allowing different trading pairs to select an appropriate fee level based on their characteristics. This design provides an optimized trading experience for assets with varying risk and liquidity profiles.
Fee Tiers
Supported Fees
Four preset fee tiers are defined in JAMMFactory.sol
:
// Supported fee tiers
uint24 public constant FEE_0_5_PERCENT = 50; // 0.5% fee
uint24 public constant FEE_1_PERCENT = 100; // 1.0% fee
uint24 public constant FEE_2_PERCENT = 200; // 2.0% fee
uint24 public constant FEE_3_PERCENT = 300; // 3.0% fee
Fee Validation
When a pair is created, the system validates the fee tier:
// from JAMMFactory.sol
require(
fee == FEE_0_5_PERCENT ||
fee == FEE_1_PERCENT ||
fee == FEE_2_PERCENT ||
fee == FEE_3_PERCENT,
"JAMMFactory: INVALID_FEE"
);
Fee Calculation
Trading Fees
Trading fees are deducted from the input token when calculating the swap amount. This logic is implemented in JAMMLibrary.sol
:
// from JAMMLibrary.sol
function getAmountOut(
uint amountIn,
uint reserveIn,
uint reserveOut,
uint24 fee
) internal pure returns (uint amountOut) {
require(amountIn > 0, "JAMMLibrary: INSUFFICIENT_INPUT_AMOUNT");
require(reserveIn > 0 && reserveOut > 0, "JAMMLibrary: INSUFFICIENT_LIQUIDITY");
// Fee is deducted from the input amount
uint amountInWithFee = amountIn * (10000 - fee);
uint numerator = amountInWithFee * reserveOut;
uint denominator = reserveIn * 10000 + amountInWithFee;
amountOut = numerator / denominator;
}
Fee Distribution Mechanism
JAMM DEX features a unique dual fee distribution mechanism, implemented in the _collectFee
function in JAMMPair.sol
, which depends on whether a referrer is present:
// from JAMMPair.sol
function _collectFee(
uint amount0In,
uint amount1In,
address _referrer
) private {
address referrer = IJAMMFactory(factory).referrer(tx.origin);
address feeTo = IJAMMFactory(factory).feeTo();
if (_referrer == address(0) && referrer == address(0)) {
// Case 1: No referrer
_safeTransferFee(token0, feeTo, (amount0In * fee) / 50000);
_safeTransferFee(token1, feeTo, (amount1In * fee) / 50000);
} else {
// Case 2: With referrer
_safeTransferFee(token0, feeTo, (amount0In * fee) / 100000);
_safeTransferFee(token1, feeTo, (amount1In * fee) / 100000);
if (referrer != address(0)) {
_safeTransferFee(token0, referrer, (amount0In * fee) / 100000);
_safeTransferFee(token1, referrer, (amount1In * fee) / 100000);
} else {
IJAMMFactory(factory).setReferrer(_referrer);
_safeTransferFee(token0, _referrer, (amount0In * fee) / 100000);
_safeTransferFee(token1, _referrer, (amount1In * fee) / 100000);
}
}
}
Fee Distribution Explained
Case 1: No Referrer
Protocol Fee: Collects
(amountIn * fee) / 50000
from the input token.Referrer Fee: 0.
Case 2: With Referrer
Protocol Fee: Collects
(amountIn * fee) / 100000
from the input token.Referrer Fee: Collects
(amountIn * fee) / 100000
from the input token.The fee is split evenly between the protocol and the referrer.
Protocol Fee Mechanism
In addition to direct trading fees, JAMM DEX can also collect a protocol fee by minting new LP tokens. This fee is sent to the mintTo
address and is managed by the _mintFee
function.
// from JAMMPair.sol
function _mintFee(
uint112 _reserve0,
uint112 _reserve1
) private returns (bool feeOn) {
address mintTo = IJAMMFactory(factory).mintTo();
feeOn = mintTo != address(0);
uint _kLast = kLast;
if (feeOn) {
if (_kLast != 0) {
uint rootK = Math.sqrt(uint(_reserve0) * uint(_reserve1));
uint rootKLast = Math.sqrt(_kLast);
if (rootK > rootKLast) {
// calculate liquidity to mint as protocol fee
uint numerator = totalSupply * (rootK - rootKLast) * 8;
uint denominator = rootK * 17 + rootKLast * 8;
uint liquidity = numerator / denominator;
if (liquidity > 0) _mint(mintTo, liquidity);
}
}
} else if (_kLast != 0) {
kLast = 0;
}
}
Protocol Fee Calculation
The protocol fee is calculated based on the growth of the liquidity pool (increase in the k
value). When the total value of the pool grows due to accumulated trading fees, the protocol mints a proportional amount of new LP tokens as revenue.
Constant Product Validation (K-Value Check)
After each swap, the system verifies the constant product formula to ensure balance after fees are deducted. The swap
function in JAMMPair.sol
includes this check:
// from JAMMPair.sol
{
balance0 = IERC20(token0).balanceOf(address(this));
balance1 = IERC20(token1).balanceOf(address(this));
// adjust balances for fee calculation
uint balance0Adjusted = (balance0 * 10000 - (amount0In * fee * 4) / 5);
uint balance1Adjusted = (balance1 * 10000 - (amount1In * fee * 4) / 5);
// ensure the product of adjusted balances is not less than the previous reserves product
require(
balance0Adjusted * balance1Adjusted >=
uint(_reserve0) * uint(_reserve1) * (10000 ** 2),
"JAMM: K"
);
}
Fee Tier Selection Guide
0.5% Fee
Use Case: Stablecoin pairs (e.g., USDC/USDT), highly liquid and low-volatility assets.
Characteristics: Lowest trading cost, suitable for large trades and arbitrage.
1.0% Fee
Use Case: Mainstream token pairs (e.g., JU/USDC), medium-volatility assets.
Characteristics: Standard fee level, balancing user cost and LP returns.
2.0% Fee
Use Case: Medium-risk token pairs, new project tokens.
Characteristics: Provides higher returns for LPs to compensate for higher impermanent loss risk.
3.0% Fee
Use Case: High-risk, high-volatility tokens, niche or experimental tokens.
Characteristics: Highest LP returns to compensate for high risk and impermanent loss.
Fee Event
Every fee transfer triggers a Fee
event:
// from JAMMPair.sol
event Fee(
address indexed sender,
address indexed referrer,
address token,
uint amount
);
function _safeTransferFee(address token, address to, uint value) private {
_safeTransfer(token, to, value);
if (value > 0) {
emit Fee(tx.origin, to, token, value);
}
}
This event logs the details of the fee distribution, allowing for on-chain data analysis and tracking.
Summary
The JAMM DEX fee structure has the following features:
Multi-Tier Fees: Four predefined fee tiers meet the needs of different assets.
Referral Incentives: A unique fee-sharing mechanism encourages community promotion.
Protocol Sustainability: Protocol fees collected by minting LP tokens ensure long-term development.
Transparency: All fee calculations and distributions are performed publicly on-chain.
Flexibility: Allows for the selection of the most appropriate fee tier for different types of asset pairs.
Understanding the fee structure is crucial for optimizing trading costs and maximizing LP returns.