JAMMLibrary
Overview
JAMMLibrary is the core calculation library of JAMM DEX, providing various mathematical calculations and utility functions required by the AMM system. It contains key functions such as token address sorting, trading pair address calculation, reserve queries, and price calculations, serving as the mathematical foundation of the entire protocol.
Library Function Categories
JAMMLibrary mainly contains the following categories of functions:
Address handling functions
Reserve query functions
Price calculation functions
Multi-hop path calculation functions
Address Handling Functions
Token Address Sorting
function sortTokens(
address tokenA,
address tokenB
) internal pure returns (address token0, address token1) {
require(tokenA != tokenB, "JAMMLibrary: IDENTICAL_ADDRESSES");
(token0, token1) = tokenA < tokenB
? (tokenA, tokenB)
: (tokenB, tokenA);
require(token0 != address(0), "JAMMLibrary: ZERO_ADDRESS");
}
Function Description:
Ensure two token addresses are not identical
Sort by address size, smaller address becomes token0
Verify token0 is not zero address
Return sorted address pair
Purpose:
Ensure trading pair uniqueness
Standardize token order in trading pairs
Provide consistent input for CREATE2 address calculation
Trading Pair Address Calculation
function pairFor(
address factory,
address tokenA,
address tokenB,
uint24 fee
) internal pure returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = address(
uint160(
uint256(
keccak256(
abi.encodePacked(
hex"ff",
factory,
keccak256(abi.encodePacked(token0, token1, fee)),
INIT_CODE_PAIR_HASH // Actual hash value determined at deployment
)
)
)
)
);
}
CREATE2 Address Calculation:
0xff
: CREATE2 opcode prefixfactory
: Factory contract addresssalt
: Hash value composed of token0, token1, and feeINIT_CODE_PAIR_HASH
: Initialization code hash of JAMMPair contract (actual value determined at deployment)
Features:
Deterministic address generation
Calculate address without calling Factory contract
Support offline address pre-calculation
Reserve Query Functions
Get Reserves
function getReserves(
address factory,
address tokenA,
address tokenB,
uint24 fee
) internal view returns (uint reserveA, uint reserveB) {
(address token0, ) = sortTokens(tokenA, tokenB);
address pair = pairFor(factory, tokenA, tokenB, fee);
(uint reserve0, uint reserve1, ) = IJAMMPair(pair).getReserves();
(reserveA, reserveB) = tokenA == token0
? (reserve0, reserve1)
: (reserve1, reserve0);
}
Function Flow:
Sort token addresses
Calculate trading pair address
Call trading pair contract to get reserves
Return corresponding reserves based on token order
Return Values:
reserveA
: Reserve amount of tokenAreserveB
: Reserve amount of tokenB
Price Calculation Functions
Proportional Calculation
function quote(
uint amountA,
uint reserveA,
uint reserveB
) internal pure returns (uint amountB) {
require(amountA > 0, "JAMMLibrary: INSUFFICIENT_AMOUNT");
require(
reserveA > 0 && reserveB > 0,
"JAMMLibrary: INSUFFICIENT_LIQUIDITY"
);
amountB = (amountA * reserveB) / reserveA;
}
Calculation Formula:
amountB = amountA × reserveB / reserveA
Purpose:
Calculate optimal ratio when adding liquidity
Price queries and display
Proportional calculation when removing liquidity
Output Amount Calculation
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"
);
uint amountInWithFee = amountIn * (10000 - fee);
uint numerator = amountInWithFee * reserveOut;
uint denominator = reserveIn * 10000 + amountInWithFee;
amountOut = numerator / denominator;
}
Calculation Formula:
amountInWithFee = amountIn × (10000 - fee)
amountOut = (amountInWithFee × reserveOut) / (reserveIn × 10000 + amountInWithFee)
Fee Handling:
Deduct trading fee from input amount
Fee expressed in basis points (10000 = 100%)
Amount after fee deduction participates in AMM calculation
Input Amount Calculation
function getAmountIn(
uint amountOut,
uint reserveIn,
uint reserveOut,
uint24 fee
) internal pure returns (uint amountIn) {
require(amountOut > 0, "JAMMLibrary: INSUFFICIENT_OUTPUT_AMOUNT");
require(
reserveIn > 0 && reserveOut > 0,
"JAMMLibrary: INSUFFICIENT_LIQUIDITY"
);
uint numerator = reserveIn * amountOut * 10000;
uint denominator = (reserveOut - amountOut) * (10000 - fee);
amountIn = (numerator / denominator) + 1;
}
Calculation Formula:
amountIn = (reserveIn × amountOut × 10000) / ((reserveOut - amountOut) × (10000 - fee)) + 1
Precision Handling:
Add 1 to result to ensure sufficient input amount
Avoid swap failures due to precision loss
Multi-hop Path Calculation
Multi-hop Output Calculation
function getAmountsOut(
address factory,
uint amountIn,
address[] memory path,
uint24[] memory fees
) internal view returns (uint[] memory amounts) {
require(path.length >= 2, "JAMMLibrary: INVALID_PATH");
amounts = new uint[](path.length);
amounts[0] = amountIn;
for (uint i; i < path.length - 1; i++) {
(uint reserveIn, uint reserveOut) = getReserves(
factory,
path[i],
path[i + 1],
fees[i]
);
amounts[i + 1] = getAmountOut(
amounts[i],
reserveIn,
reserveOut,
fees[i]
);
}
}
Calculation Flow:
Verify path length is at least 2
Initialize amounts array, first element is input amount
Iterate through each hop in the path
Get reserves for current hop
Calculate output amount for current hop
Output amount becomes input for next hop
Multi-hop Input Calculation
function getAmountsIn(
address factory,
uint amountOut,
address[] memory path,
uint24[] memory fees
) internal view returns (uint[] memory amounts) {
require(path.length >= 2, "JAMMLibrary: INVALID_PATH");
amounts = new uint[](path.length);
amounts[amounts.length - 1] = amountOut;
for (uint i = path.length - 1; i > 0; i--) {
(uint reserveIn, uint reserveOut) = getReserves(
factory,
path[i - 1],
path[i],
fees[i - 1]
);
amounts[i - 1] = getAmountIn(
amounts[i],
reserveIn,
reserveOut,
fees[i - 1]
);
}
}
Calculation Flow:
Verify path length
Initialize amounts array, last element is desired output amount
Iterate backward through the path
Get reserves for current hop
Calculate required input amount for current hop
Continue forward calculation until first hop
Usage Examples
Basic Price Queries
// Calculate proportional amount
const amountB = await JAMMLibrary.quote(
ethers.utils.parseEther("1"), // 1 tokenA
reserveA,
reserveB
);
// Calculate swap output
const amountOut = await JAMMLibrary.getAmountOut(
ethers.utils.parseEther("1"), // Input 1 token
reserveIn,
reserveOut,
100 // 1% fee rate
);
// Calculate required input
const amountIn = await JAMMLibrary.getAmountIn(
ethers.utils.parseEther("1"), // Desired output 1 token
reserveIn,
reserveOut,
100 // 1% fee rate
);
Multi-hop Path Calculation
// Calculate multi-hop output
const path = [tokenA, tokenB, tokenC];
const fees = [100, 200]; // 1% and 2% fee rates
const amountIn = ethers.utils.parseEther("1");
const amounts = await JAMMLibrary.getAmountsOut(
factoryAddress,
amountIn,
path,
fees
);
console.log("Input amount:", ethers.utils.formatEther(amounts[0]));
console.log("Intermediate amount:", ethers.utils.formatEther(amounts[1]));
console.log("Output amount:", ethers.utils.formatEther(amounts[2]));
// Calculate multi-hop input
const amountOut = ethers.utils.parseEther("1");
const amountsIn = await JAMMLibrary.getAmountsIn(
factoryAddress,
amountOut,
path,
fees
);
console.log("Required input:", ethers.utils.formatEther(amountsIn[0]));
Address Calculation
// Calculate trading pair address
const pairAddress = await JAMMLibrary.pairFor(
factoryAddress,
tokenA,
tokenB,
100 // 1% fee rate
);
// Get reserves
const [reserveA, reserveB] = await JAMMLibrary.getReserves(
factoryAddress,
tokenA,
tokenB,
100
);
Mathematical Principles
AMM Pricing Formula
JAMM DEX uses the constant product formula:
x × y = k
When considering fees:
(x + Δx × (1 - fee)) × (y - Δy) = k
Where:
x
,y
: Reserves before swapΔx
: Input amountΔy
: Output amountfee
: Trading fee rate
Price Impact
Price impact can be calculated using the following formula:
Price Impact = 1 - (Actual Price / Theoretical Price)
Where:
Actual Price = Δy / Δx
Theoretical Price = y / x
Slippage Calculation
Slippage is the difference between expected and actual execution price:
Slippage = |Actual Output - Expected Output| / Expected Output
Last updated