Liquidity Pools

What is a Liquidity Pool?

A liquidity pool is a core component of JAMM DEX, consisting of a smart contract that holds reserves of two tokens. Each liquidity pool is an instance of the JAMMPair contract, responsible for managing the trading and liquidity of a specific token pair.

Pool Creation

Creation via Factory

All liquidity pools are created through the JAMMFactory contract:

// from JAMMFactory.sol
function createPair(
    address tokenA,
    address tokenB,
    uint24 fee
) external override returns (address pair) {
    require(tokenA != tokenB, "JAMMFactory: IDENTICAL_ADDRESSES");
    (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
    require(token0 != address(0), "JAMMFactory: ZERO_ADDRESS");
    require(
        fee == FEE_0_5_PERCENT ||
        fee == FEE_1_PERCENT ||
        fee == FEE_2_PERCENT ||
        fee == FEE_3_PERCENT,
        "JAMMFactory: INVALID_FEE"
    );
    require(getPair[token0][token1][fee] == address(0), "JAMMFactory: PAIR_EXISTS");
    
    // deploy the pair using CREATE2
    bytes memory bytecode = type(JAMMPair).creationCode;
    bytes32 salt = keccak256(abi.encodePacked(token0, token1, fee));
    assembly {
        pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
    }
    
    // initialize the pair
    JAMMPair(pair).initialize(token0, token1, fee);
    getPair[token0][token1][fee] = pair;
    getPair[token1][token0][fee] = pair;
    allPairs.push(pair);
    emit PairCreated(token0, token1, fee, pair, allPairs.length);
}

Deterministic Address Generation

JAMM DEX uses CREATE2 to generate deterministic pool addresses. This means that for the same token pair and fee, the pool address will always be the same. This calculation is performed in JAMMLibrary.sol:

Pool State

Reserve Management

Each pool maintains reserves of two tokens:

Reserve Updates

Reserves are updated after every trade or liquidity change:

Liquidity Tokens (LP Tokens)

The Role of LP Tokens

When a user provides liquidity to a pool, they receive LP tokens as a receipt:

  • LP tokens represent the user's share in the pool.

  • They can be redeemed at any time for the corresponding token pair.

  • LP tokens are themselves ERC-20 tokens and can be transferred.

Minting LP Tokens

Burning LP Tokens

Trade Execution

The swap Function

The core function of the pool is to execute token swaps:

Security Mechanisms

Re-entrancy Guard

All critical functions are protected with the lock modifier to prevent re-entrancy attacks:

Minimum Liquidity Lock

To prevent the pool from being completely drained, a minimum amount of LP tokens is permanently locked on the first liquidity provision:

Overflow Protection

Reserves use the uint112 type, and updates are checked for overflow, leveraging the built-in security features of Solidity 0.8.x:

Utility Functions

skim Function

Used to remove any excess tokens that were accidentally sent to the pool and not accounted for in the reserves:

sync Function

Used to forcibly synchronize the reserves with the contract's actual token balances. This can be used to recover the pool state in certain edge cases:

Summary

Liquidity pools are the core components of JAMM DEX, and they:

  • Are created and managed centrally by the Factory contract.

  • Use deterministic address generation for easy calculation and lookup.

  • Implement full AMM functionality, including liquidity management and token swaps.

  • Have built-in security mechanisms and fee distribution logic.

  • Provide price oracle functionality.

Understanding how liquidity pools work is essential for effectively using JAMM DEX.