JAMM DEX supports two exact amount swap modes: Exact Input and Exact Output. These modes meet different trading needs, allowing users to precisely control either the input or output amount of swaps.
Exact Input Swaps
Basic Concept
Exact input swaps allow users to specify the exact input amount, and the system calculates and returns the corresponding output amount. This is the most commonly used swap mode.
Features:
Users know exactly how many tokens they will pay
Output amount is calculated based on current market price
Requires setting minimum output amount for slippage protection
Implementation
Token to Token Exact Input
asyncfunctionswapExactTokensForTokens(tokenIn,tokenOut,amountIn,slippagePercent,userAddress,signer){constrouter=newethers.Contract(ROUTER_ADDRESS,routerABI,signer); // 1. Query expected outputconstpath= [tokenIn,tokenOut];constfees= [100];// 1% fee rateconstamounts=awaitrouter.getAmountsOut(amountIn,path,fees);constexpectedOutput=amounts[1]; // 2. Calculate minimum output (slippage protection)constslippageBps=Math.floor(slippagePercent*100);// Convert to basis pointsconstamountOutMin=expectedOutput.mul(10000-slippageBps).div(10000); // 3. Set deadlineconstdeadline=Math.floor(Date.now() /1000) +60*20;// 20 minutes // 4. Execute swapconsttx=awaitrouter.swapExactTokensForTokens(amountIn,amountOutMin,path,fees,userAddress,ethers.constants.AddressZero,// No referrerdeadline );console.log("Exact input swap submitted:",tx.hash);constreceipt=awaittx.wait();return{transactionHash:tx.hash,blockNumber:receipt.blockNumber,expectedOutput,actualOutput:awaitgetActualOutput(receipt) // Parse actual output from events};}
JU to Token Exact Input
Token to JU Exact Input
Exact Output Swaps
Basic Concept
Exact output swaps allow users to specify the exact output amount, and the system calculates and requires the corresponding input amount. This mode is suitable for scenarios where you need to receive a precise amount of tokens.
Features:
Users know exactly how many tokens they will receive
Input amount is calculated based on current market price
Requires setting maximum input amount for slippage protection
Implementation
Token to Token Exact Output
JU to Token Exact Output
Token to JU Exact Output
Advanced Features
Multi-Hop Exact Swaps
Batch Exact Swaps
Price Calculation and Preview
Exact Input Price Preview
Exact Output Price Preview
Price Impact Calculation
Utility Functions
Swap Result Parsing
Slippage Calculator
Best Practices
1. Swap Mode Selection
2. Dynamic Slippage Adjustment
3. Pre-Swap Validation
Summary
Exact amount swaps are a core feature of JAMM DEX. This guide covers:
class SlippageCalculator {
static calculateMinOutput(expectedOutput, slippagePercent) {
const slippageBps = Math.floor(slippagePercent * 100);
return expectedOutput.mul(10000 - slippageBps).div(10000);
}
static calculateMaxInput(requiredInput, slippagePercent) {
const slippageBps = Math.floor(slippagePercent * 100);
return requiredInput.mul(10000 + slippageBps).div(10000);
}
static calculateActualSlippage(expected, actual, isInput = false) {
if (isInput) {
// For input, actual should be less than or equal to expected
if (actual.gt(expected)) {
return ethers.BigNumber.from(0); // No slippage, better than expected
}
return expected.sub(actual).mul(10000).div(expected);
} else {
// For output, actual should be greater than or equal to expected
if (actual.gt(expected)) {
return ethers.BigNumber.from(0); // No slippage, better than expected
}
return expected.sub(actual).mul(10000).div(expected);
}
}
}
function chooseSwapMode(userIntent, marketConditions) {
if (userIntent.type === 'SPEND_EXACT') {
// User wants to spend exact amount of tokens
return 'EXACT_INPUT';
} else if (userIntent.type === 'RECEIVE_EXACT') {
// User wants to receive exact amount of tokens
return 'EXACT_OUTPUT';
} else if (marketConditions.volatility === 'HIGH') {
// High volatility market, exact input is safer
return 'EXACT_INPUT';
} else {
// Default to exact input
return 'EXACT_INPUT';
}
}
function calculateDynamicSlippage(priceImpact, marketVolatility, tradeSize) {
let baseSlippage = 0.5; // 0.5% base slippage
// Adjust based on price impact
if (priceImpact > 200) { // Greater than 2%
baseSlippage += 1.0;
} else if (priceImpact > 100) { // Greater than 1%
baseSlippage += 0.5;
}
// Adjust based on market volatility
baseSlippage += marketVolatility * 0.5;
// Adjust based on trade size
if (tradeSize === 'LARGE') {
baseSlippage += 0.5;
}
return Math.min(baseSlippage, 5.0); // Maximum 5% slippage
}
async function validateSwap(swapParams) {
const validations = [];
// Validate token addresses
if (!ethers.utils.isAddress(swapParams.tokenIn) || !ethers.utils.isAddress(swapParams.tokenOut)) {
validations.push("Invalid token addresses");
}
// Validate amounts
if (swapParams.amount.lte(0)) {
validations.push("Swap amount must be greater than 0");
}
// Validate slippage
if (swapParams.slippage < 0 || swapParams.slippage > 50) {
validations.push("Slippage must be between 0-50%");
}
// Validate deadline
if (swapParams.deadline <= Math.floor(Date.now() / 1000)) {
validations.push("Deadline has expired");
}
// Validate pair exists
const factory = new ethers.Contract(FACTORY_ADDRESS, factoryABI, provider);
const pairAddress = await factory.getPair(swapParams.tokenIn, swapParams.tokenOut, swapParams.fee);
if (pairAddress === ethers.constants.AddressZero) {
validations.push("Trading pair does not exist");
}
return validations;
}