The spread is the gap between the highest price a buyer is willing to pay (the best bid) and the lowest price a seller is willing to accept (the best ask). If the best bid for ETH is $1,998 and the best ask is $2,001, the spread is $3. This gap is the most fundamental cost of trading. Every time you execute a market order, you cross the spread, buying at the ask or selling at the bid.
The spread exists because market makers need compensation for providing liquidity. They sit on both sides of the market, willing to buy and sell at any moment, and the spread is how they get paid for that service.
Market makers provide a service. They stand ready to buy and sell at any time, absorbing the timing mismatch between buyers and sellers. The spread compensates them for three risks.
Highly liquid assets like Apple stock or EUR/USD have extremely tight spreads, often just one cent or one pip. The spread on AAPL might be $0.01 on a $180 stock, which is about 0.006%. There are so many market makers competing that the spread gets compressed to almost nothing.
Illiquid assets tell a different story. A small-cap stock might have a spread of $0.50 on a $10 stock (5%). An exotic currency pair or a thinly traded commodity future can have spreads measured in percentage points. The less competition among market makers and the less volume, the wider the spread.
AMMs do not have explicit bid and ask prices. There is no order book with visible spread. Instead, the spread emerges implicitly from two sources.
First, the bonding curve itself creates a spread. When you buy a token from an AMM, you push the price up along the curve. If you immediately tried to sell the same amount back, you would get less than you paid because selling pushes the price back down. The round-trip cost is the implicit spread.
Second, swap fees widen the spread further. Uniswap V3 offers multiple fee tiers that LPs choose when creating pools.
The fee is applied on top of the curve impact, so the effective spread on a Uniswap V3 ETH/USDC pool with a 0.30% fee tier is at minimum 0.60% for a round trip (0.30% to buy, 0.30% to sell), plus whatever additional curve impact the trade size causes.
There are several ways to quantify the spread.
For AMM pools, we can compute the implied spread by simulating a buy and a sell of the same size against the reserves.
// Read Uniswap V2 pool reserves and compute the implied spread
import (
"context"
"fmt"
"math"
"math/big"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
)
func getImpliedSpread(client *ethclient.Client, pairAddr common.Address, tradeSize float64) {
// getReserves() selector
selector := crypto.Keccak256([]byte("getReserves()"))[:4]
result, _ := client.CallContract(context.Background(), ethereum.CallMsg{
To: &pairAddr,
Data: selector,
}, nil)
// Decode ABI-packed (uint112, uint112, uint32)
reserve0 := new(big.Int).SetBytes(result[0:32])
reserve1 := new(big.Int).SetBytes(result[32:64])
x := float64(reserve0.Int64()) / math.Pow(10, 18) // ETH (18 decimals)
y := float64(reserve1.Int64()) / math.Pow(10, 6) // USDC (6 decimals)
k := x * y
spotPrice := y / x
// Buy tradeSize ETH -- remove ETH from pool, add USDC
newX := x - tradeSize
buyPrice := (k/newX - y) / tradeSize
// Sell tradeSize ETH -- add ETH to pool, remove USDC
newX2 := x + tradeSize
sellPrice := (y - k/newX2) / tradeSize
absoluteSpread := buyPrice - sellPrice
relativeSpreadBps := (absoluteSpread / spotPrice) * 10000
fmt.Printf("Spot price: %.2f\n", spotPrice)
fmt.Printf("Buy price: %.2f\n", buyPrice)
fmt.Printf("Sell price: %.2f\n", sellPrice)
fmt.Printf("Absolute spread: %.2f\n", absoluteSpread)
fmt.Printf("Relative spread: %.1f bps\n", relativeSpreadBps)
}
The spread is not static. It widens and tightens in response to market conditions.
Understanding the spread is the first step. But the spread only tells you the cost of an infinitely small trade. For real trades of meaningful size, you also need to understand slippage, which measures how much worse your execution gets as your trade size increases.
For the broader framework of how these mechanics fit together, see Market Microstructure. For how swaps are executed as on-chain transactions through smart contracts, see the contracts deep dive.