Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

Building an AMM: The Constant Product Swap

Hello! Welcome to the third lesson in our "Fungible Tokens & DeFi Primitives" module.

Introduction

In our previous lessons, we built a feature-rich ERC-20 token and then enhanced it with EIP-2612 permit functionality for gasless approvals. We now have a token that is not only functional but also offers a great user experience for DApp integrations.

The natural next step is to use this token in a core DeFi protocol. Today, we're going to build the engine of a decentralized exchange (DEX), one of the most fundamental building blocks in the DeFi ecosystem.

Unlike traditional exchanges that rely on order books to match buyers and sellers, many DEXs use a novel approach called an Automated Market Maker (AMM).

Learning Outcome: By the end of this lesson, you will be able to implement the core swap logic of an Automated Market Maker (AMM) using the constant product formula (x * y = k).

We will explore this simple but powerful formula, understand the mathematics behind a token swap, and translate that logic into a Solidity smart contract.

1. The Constant Product Formula: x * y = k

The most common type of AMM is the Constant Product Market Maker (CPMM), popularized by Uniswap. Its operation is governed by a single, elegant formula:

Where:

  • x is the quantity (reserve) of Token A in the liquidity pool.
  • y is the quantity (reserve) of Token B in the liquidity pool.
  • k is the "constant product." During a swap, the reserves x and y change, but their product k must remain constant.

This formula describes a hyperbola. Any trade moves the pool's state from one point on this curve to another.

The x * y = k curve. A swap involves moving from one point on the curve (e.g., with reserves x₀, y₀) to another (x₁, y₁), where x₀y₀ = x₁y₁. The amount of token 1 sold (Δx) results in receiving an amount of token 0 (Δy).

The core idea is that as you remove one asset from the pool, its price relative to the other asset increases exponentially, ensuring the pool can theoretically never run out of liquidity.

2. The Mathematics of a Swap

Let's derive the formula to calculate how many tokens you get out for a given input. Suppose you are swapping Δx of Token X for some amount Δy of Token Y.

  • Initial state: x * y = k
  • After your swap: You add Δx to the pool, and the pool sends you Δy. The new reserves are (x + Δx) and (y - Δy).
  • The invariant: The constant product k must be maintained, so: (x + Δx) * (y - Δy) = k

Our goal is to solve for Δy (the amount of token Y you receive).

To see the full derivation, let's watch a short video that breaks down the algebra.

Constant Product AMM Math | DeFi

The video 'Constant Product AMM Math' from the Smart Contract Programmer channel provides a clear, step-by-step derivation of the swap output formula.

Please watch the first section, 'Constant Product AMM Introduction and Swapping Math' (00:00 - 05:48). Focus on how the x * y = k invariant is used to solve for dY (which we are calling Δy).

As the video demonstrates, by rearranging the equation (x + Δx) * (y - Δy) = x * y, we arrive at the formula for the output amount:

After finding a common denominator and simplifying, we get the more intuitive form:

This formula tells us the output amount (Δy) based on the initial reserves (x, y) and the input amount (Δx).

3. Incorporating Fees

The formula above is for an ideal AMM. Real-world AMMs like Uniswap V2 charge a fee on every swap (e.g., 0.3%) to reward users who provide the liquidity (the x and y tokens).

This fee is taken from the input amount. So, if you swap Δx tokens, a small portion is set aside as a fee, and the rest is used for the swap calculation. This means the constant k actually increases slightly after each trade, growing the pool.

Let's look at how the formula is adjusted for fees.

Automated Market Makers (AMMs): Math, Risks & Solidity

The guide 'Automated Market Makers (AMMs): Math, Risks & Solidity' on speedrunethereum.com provides a concise explanation of the swap math including fees.

Read Section 5, 'Swap Math: Deriving the Output Formula'. Pay close attention to the formula under the 'With Fees' heading. This is the version we will implement.

As the article shows, with a 0.3% fee, the effective input amount becomes amountIn * 0.997. The formula used in the Uniswap V2 contracts is:

Where:

  • amountInWithFee = amountIn * 997 / 1000
  • reserveIn is the reserve of the token you are selling.
  • reserveOut is the reserve of the token you are buying.

This is the exact logic we need to implement in our smart contract.

4. A Concrete Example

Let's walk through a numerical example to make this tangible.

The Ultimate Guide To AMMs

The video 'The Ultimate Guide To AMMs' by Owen Thurm provides an excellent, easy-to-follow walkthrough of a swap.

Watch the section from 02:22 to 06:00. The video demonstrates a swap of 5,000 DAI for ETH in a pool with 5 ETH and 25,000 DAI. Follow the calculation to see how the output amount of ETH is determined. Note: This example ignores fees for simplicity, but it's great for building intuition.

To summarize the example from the video:

  • Pool State: 5 ETH (x) and 25,000 DAI (y). So, k = 5 * 25000 = 125,000.
  • Trade: A user swaps 5,000 DAI (Δy_in) for ETH (Δx_out).
  • New DAI reserve: 25,000 + 5,000 = 30,000.
  • New ETH reserve (x_new): To maintain k, x_new * 30,000 = 125,000. So, x_new = 125,000 / 30,000 ≈ 4.167 ETH.
  • ETH received by user (Δx_out): 5 - 4.167 = 0.833 ETH.

This example clearly shows the mechanics of how reserves adjust to facilitate a trade while preserving the invariant k.

5. Solidity Implementation

Now, let's translate this logic into a Solidity swap function. Your experience as a developer will make the mapping from algorithm to code straightforward.

We'll use the minimal AMM contract from the Speedrun Ethereum guide, which includes the core logic for swapping, adding, and removing liquidity. We will focus only on the swap function.

Automated Market Makers (AMMs): Math, Risks & Solidity

Let's return to the 'Automated Market Makers (AMMs): Math, Risks & Solidity' guide and examine the code.

Scroll down to Section 7, 'Solidity Code Walkthrough'. Study the MinimalAMM contract, focusing on the swap function. We will break it down line by line.

Here is the swap function from the article, with comments explaining each step:

function swap(
    uint amountIn, 
    address tokenIn, 
    uint amountOutMin
) external returns (uint amountOut) {
    // 1. Basic sanity checks
    require(amountIn > 0, "Zero input");
    require(tokenIn == address(token0) || tokenIn == address(token1), "Invalid token");

    // 2. Identify input/output reserves based on `tokenIn` address
    (
        IERC20 input, 
        IERC20 output, 
        uint reserveIn, 
        uint reserveOut
    ) = tokenIn == address(token0) 
        ? (token0, token1, reserve0, reserve1) 
        : (token1, token0, reserve1, reserve0);

    // 3. Transfer the input tokens from the user to this contract
    input.transferFrom(msg.sender, address(this), amountIn);

    // 4. Calculate the input amount after the 0.3% fee
    uint amountInWithFee = amountIn * 997 / 1000;

    // 5. Apply the constant product formula to calculate the output amount
    amountOut = (reserveOut * amountInWithFee) / (reserveIn + amountInWithFee);
    
    // 6. Slippage check: ensure the user receives at least the minimum amount they specified
    require(amountOut >= amountOutMin, "Slippage");

    // 7. Transfer the output tokens to the user
    output.transfer(msg.sender, amountOut);

    // 8. Update the stored reserve values for the next trade
    // Note: A more robust implementation would not re-read from balance but update in memory.
    // This is simplified for clarity.
    reserve0 = token0.balanceOf(address(this));
    reserve1 = token1.balanceOf(address(this));
}

This function is a direct implementation of the concepts we've discussed. It takes tokens in, applies the fee-adjusted formula, and sends the calculated tokens out, all while ensuring the x*y=k principle is upheld. For a deeper dive into the canonical Uniswap V2 implementation, which uses some gas-saving optimizations like "optimistic transfers", the paper "How UniswapV2 Swaps Work" (resource a7c73) is an excellent, though more advanced, read.

Conclusion

Congratulations! You have now implemented the core logic of a decentralized exchange. By understanding the x * y = k formula, you've unlocked the mechanism that powers a vast portion of the DeFi ecosystem.

Key Takeaways:

  • AMMs vs. Order Books: AMMs use liquidity pools and a deterministic formula to price assets, offering always-on, permissionless trading.
  • The Constant Product Formula: x * y = k is the simple invariant that governs swaps. The product of the token reserves must remain constant through a trade (before fees).
  • Swap Calculation: The output amount is a direct function of the pool's reserves and the input amount. We derived the formula: amountOut = (reserveOut * amountInWithFee) / (reserveIn + amountInWithFee).
  • Fees are Essential: A small fee (e.g., 0.3%) is taken from the input amount to reward liquidity providers, causing the pool's total liquidity (k) to grow over time.
  • Solidity Implementation: The mathematical formula translates directly into a smart contract function that handles token transfers and state updates.

Next Steps:

We've built a token and a place to trade it. Another fundamental DeFi primitive is earning yield on your assets. In our next lesson, we will build a staking contract for an ERC-20 token with a time-based reward distribution mechanism. This will allow token holders to lock up their tokens and earn rewards, a cornerstone of many crypto projects.

Can't find a good explanation? Sign up and we'll make it for you

Sign up