Skip to content

Slippage

Andrew Dmytrenko edited this page Sep 26, 2024 · 12 revisions

When trading on a decentralized exchange (DEX) like PancakeSwap V3, it's important to understand how slippage and minimum output (minimumOut) affect your transactions. This page will explain what slippage is, how it works, and how you can calculate and set a minimum output amount to protect your trades.

what-is-slippage_body

What is Slippage?

Slippage occurs when the final price of a trade is different from the price you expected due to rapid changes in token prices or insufficient liquidity. On PancakeSwap V3, trades are executed based on the best available price at the time, but if the market moves while your trade is being processed, you may receive fewer tokens than anticipated.

For example, if you’re swapping tokens and expect to get 100 tokens, but due to slippage, you might end up receiving only 98 or 99 tokens. Slippage can happen because other users are making trades at the same time, or the market is volatile and moving quickly.

How to Protect Yourself from Slippage?

High volatility or low liquidity can result in trades executing at less favorable prices. To protect yourself from slippage, you can specify a minimum amount of tokens you're willing to accept in a swap, known as the amountOutMinimum.

This ensures that the transaction will only execute if the amount of tokens received is greater than or equal to this minimum. If the market price moves unfavorably and the received amount falls below the amountOutMinimum, the transaction will fail, preventing you from incurring a greater loss than you anticipated.

Setting the Minimum Amount (amountOutMinimum)

The amountOutMinimum is calculated by applying a slippage tolerance to the quoted amount of tokens you expect to receive from the trade. This gives you a buffer against unfavorable price movements.

Formula to Calculate amountOutMinimum:

amountOutMinimum = expectedAmount * (1 - slippage)

Where:

  • expectedAmount - The expected amount of tokens you'll receive based on the current exchange rate (quoted by the DEX)
  • slippage - The acceptable slippage tolerance, expressed as a percentage (e.g., for 1% slippage, use 0.01)

Example:

Suppose you're swapping 1 BNB for MEME tokens on a DEX, and you expect to receive 100 MEME tokens. You want to protect yourself from a 2% price slippage.

  • expectedAmount - 100 MEME tokens (quoted by the exchange)
  • slippage - 2% or 0.02
amountOutMinimum = 100 * (1 - 0.02) = 100 * 0.98 = 98 MEME tokens

In this case, you'd set amountOutMinimum to 98 MEME tokens. If the trade executes and results in fewer than 98 MEME tokens, the transaction will revert, ensuring you don’t get a worse deal than you intended.

// Typescript example
import { ethers } from "ethers";

const expectedAmount = ethers.parseUnits("100", 18); // 100 MEME tokens
const slippageTolerance = 0.02; // 2% slippage

// Calculate amountOutMinimum
const amountOutMinimum = expectedAmount.mul(ethers.BigNumber.from(100).sub(ethers.BigNumber.from(slippageTolerance * 100))).div(100);

console.log(`Amount Out Minimum: ${amountOutMinimum.toString()} MEME tokens`);

Practical Use in BNBPartyFactory:

In the context of the BNBPartyFactory, understanding and implementing slippage management through the amountOutMinimum is crucial for ensuring that trades executed via the smart contract meet user expectations. Here’s how it works within the joinParty and leaveParty functions of the BNBPartyFactory contract:

Here’s how to implement the slippage calculation and call the joinParty and leaveParty functions in TypeScript:

Slippage Calculation Function

import { ethers } from "ethers";

// Function to calculate amountOutMinimum
function calculateAmountOutMinimum(expectedAmount: ethers.BigNumber, slippageTolerance: number): ethers.BigNumber {
    const slippageFactor = ethers.BigNumber.from((1 - slippageTolerance).toFixed(2).split('.')[1]);
    return expectedAmount.mul(100 - slippageFactor.toNumber()).div(100);
}

Calling joinParty

async function joinParty(tokenOut: string, amountIn: ethers.BigNumber, slippageTolerance: number) {
    const expectedAmount = await getExpectedAmount(tokenOut); // Implement this function to get expected amount
    const amountOutMinimum = calculateAmountOutMinimum(expectedAmount, slippageTolerance);
    
    const params = {
        tokenOut,
        amountOutMinimum: amountOutMinimum.toString(),
    };

    const tx = await bnbPartyFactoryContract.joinParty(params.tokenOut, params.amountOutMinimum, {
        value: amountIn, // BNB sent in the transaction
    });

    await tx.wait(); // Wait for the transaction to be mined
    console.log(`Joined party and received a minimum of ${params.amountOutMinimum} tokens.`);
}

Calling leaveParty

async function leaveParty(tokenIn: string, amountIn: ethers.BigNumber, slippageTolerance: number) {
    const expectedAmount = await getExpectedAmountForBNB(tokenIn); // Implement this function to get expected BNB amount
    const amountOutMinimum = calculateAmountOutMinimum(expectedAmount, slippageTolerance);
    
    const params = {
        tokenIn,
        amountIn: amountIn.toString(),
        amountOutMinimum: amountOutMinimum.toString(),
    };

    const tx = await bnbPartyFactoryContract.leaveParty(params.tokenIn, params.amountIn, params.amountOutMinimum);
    await tx.wait(); // Wait for the transaction to be mined
    console.log(`Left party and received a minimum of ${params.amountOutMinimum} BNB.`);
}

Example Usage

(async () => {
    const tokenOutAddress = "0x..."; // Replace with actual token address
    const tokenInAddress = "0x..."; // Replace with actual token address
    const amountIn = ethers.utils.parseEther("1.0"); // 1 BNB
    const slippageTolerance = 0.02; // 2%

    await joinParty(tokenOutAddress, amountIn, slippageTolerance);
    await leaveParty(tokenInAddress, ethers.utils.parseUnits("100", 18), slippageTolerance); // Assuming leaving 100 tokens
})();

Notes:

  • Ensure you implement the getExpectedAmount and getExpectedAmountForBNB functions to retrieve the expected amounts from the DEX or contract logic.
  • Adjust the ethers and contract references as needed based on your project's setup.
  • Handle exceptions and errors in a real application for robustness.