Web 3 ENG
June 5

DEX from the Inside: Who Moves the Price and How It Actually Works

In my previous post, I shared a high-level breakdown of how I built my own arbitrage bot on Solana — leveraging liquidity from decentralized exchanges (DEXs) and executing atomic multihop swaps.

After publishing it, I got a bunch of comments and DMs with the same core question:

Where does the price on a DEX actually come from?

Why does it move? Who sets it? And what’s up with slippage?

So in this article, I want to go deeper and explain how pricing works inside decentralized liquidity pools. No fluff — just clear examples and simple explanations.

If you’re curious to dig into the math and mechanics under the hood, let me know in the comments — happy to explore that in follow-ups.

Let’s start by quickly revisiting how price formation works on centralized exchanges (CEXs), and then contrast it with DEXs.

How pricing works on CEXs

On CEXs like Binance, Bybit, or OKX, the price is determined through orders. One person wants to buy, another wants to sell — and the exchange simply matches their orders.

Example:

  • Someone wants to buy 1 BTC for $85,000
  • Someone is willing to sell for $85,100
  • The exchange just shows what each side is offering — and trades happen based on those prices

How it looks visually

Imagine a vertical Y-axis, where the top represents high prices and the bottom — low prices. That’s how we visualize the order book.

Sellers always want to sell at higher prices, so in the sell side of the book:

  • the lowest (most attractive for buyers) price is at the bottom
  • the highest offers are at the top

Buyers, on the other hand, want to buy cheaper, so in the buy side:

  • the highest price (more attractive for sellers) is at the top
  • lower bids are listed below

Below is an example of how it looks in practice.

How to read this?

For example:

  • I want to buy 4 BTC (look at the Amount BTC column),
  • At a price of $85,700 per BTC (Price USDT cell),
  • For a total of $342,800 (Total USDT — 4 × 85,700).

Each row in both sides of the order book represents orders like this — just like the one we broke down.

Order Book Visualization

To make it clearer, let’s imagine flipping the BUY order book upside down (like a mirror reflection)

and placing it under the bottom of the SELL order book.

This gives us the classic picture with a spread in the middle — showing how the buy and sell prices converge.

All of this makes up the order book — a table where the sell orders are on top, and the buy orders are at the bottom. They don’t align perfectly, and the gap between them is called the spread.

Example:

You go to Binance and want to buy 1 SOL.

  • The order book shows that the nearest seller is offering it at $145.
  • You click “buy at market” — the exchange takes that order from the seller, and you get SOL at $145.
  • That transaction — $145 — becomes the current market price.

Prices on a CEX change constantly — not because someone is “setting” the price, but because people place orders: someone buys, someone sells, and that creates the new price.

It’s like an auction — the price is whatever people are willing to pay.

The exchange doesn’t set the price itself — it simply matches orders between participants.

How Pricing Works on a DEX: Order Book vs AMM 💥

Unlike centralized exchanges where prices are set by matching buy and sell orders, decentralized exchanges (DEXs) work differently — through liquidity pools.

A liquidity pool is a smart contract holding two tokens, like SOL and USDC.

Anyone can come and swap one for the other — at a rate determined by the current ratio of tokens inside the pool.

What pricing mechanics are out there?

If we simplify things to the most fundamental level, almost every DEX uses one of two core pricing models under the hood:

Order Book (Limit Orders)

Example: OpenBook (formerly Serum)

  • Prices are formed through limit orders
  • There are buyers and sellers, each setting their own price
  • A smart contract matches orders just like on a centralized exchange
  • Feels almost like a CEX — but everything runs on-chain

AMM (Automated Market Maker)

And this is where things get more interesting.

Instead of using orders, the price is based purely on the token balances in the pool — and a formula that calculates the exchange rate.

This includes several variations:

CPMM (Constant Product Market Maker)

  • Used in: Raydium AMM v4, Raydium CPMM, Uniswap V2
  • Formula: X * Y = K — simple and reliable

CLMM (Concentrated Liquidity Market Maker)

  • Used in: Uniswap V3, Raydium CLMM
  • Liquidity is allocated within specific price ranges (ticks), reducing slippage

DLMM (Dynamic Liquidity Market Maker)

  • Used in: Meteora
  • Liquidity automatically follows the price, offering more flexibility than CLMM

AMM (Automated Market Maker) 💥

Instead of matching buyers and sellers like in an order book, AMMs rely on token balances in a liquidity pool and a formula to determine price. There are no limit orders — just math and assets locked in a smart contract.

At the core of this model lies a simple yet powerful formula:

X * Y = K

Where:

  • X is the amount of one token in the pool (e.g., SOL)
  • Y is the amount of the other token (e.g., USDC)
  • K is a constant — the product of the initial amounts of SOL and USDC — and it stays the same during each swap

This formula ensures that as one token is bought, its price increases relative to the other, maintaining balance in the pool.

How a Swap Works

Let’s say you want to swap SOL → USDC.

  • You add some SOL into the pool — which means X increases.
  • To keep K constant, Y (the amount of USDC) has to decrease.
  • You receive those USDC — but at a worse rate, because you disrupted the pool’s balance.
  • The more you swap, the more you shift the balance — and the worse the exchange rate gets.

That’s why larger swaps suffer from higher slippage — it’s not a fee, it’s just how AMMs naturally work.

Example 1 — Small Swap

Let’s say the pool contains:

  • 1000 SOL
  • 100,000 USDC

That means:

K = 1000 × 100,000 = 100,000,000

You want to swap 1 SOL for USDC.

After the swap, the new SOL balance becomes X = 1001.

To keep K constant, we calculate the new USDC balance:

Y = K / X = 100,000,000 / 1001 ≈ 99,900.1

So:

  • USDC before: 100,000
  • USDC after: 99,900.1
  • You receive: ≈ 99.9 USDC

Effective rate: 1 SOL = 99.9 USDC

(instead of exactly 100 — you get a tiny bit less due to slippage)

Example 2 — Large Swap (and Noticeable Slippage)

Let’s take the same pool:

  • 1000 SOL
  • 100,000 USDC
  • So, K = 1000 × 100,000 = 100,000,000

Now you want to swap 100 SOL for USDC.

The new SOL balance becomes X = 1100

Calculate the new USDC balance:

Y = K / X = 100,000,000 / 1100 ≈ 90,909.1

So in the pool:

  • USDC before: 100,000
  • USDC after: 90,909.1
  • Pool now have: 100,000 – 90,909.1 = 9,090.9 USDC

Effective rate:

100 SOL = 9,090.9 USDC → 1 SOL ≈ 90.91 USDC

That’s a much worse rate than before — you’ve shifted the balance heavily, so the price dropped hard. That’s slippage in action.

Practical Example on Meteora Devnet 💥

To demonstrate how everything works in practice, I created a test pool on devnet and will walk through how the calculation is done — and how closely it matches reality.

I minted two test tokens for myself, which I’ll use as paired assets in the pool.

Creating the pool

For this experiment, I set up a pool with 100 tokens of each type — Token X and Token Y.

In the screenshot you can see:

  • Base Token (2no) — we’ll call this Token X
  • Quote Token (BaS) — this will be Token Y
  • Initial Price — I set it to 1, meaning 1 Token X = 1 Token Y. This almost never happens in real markets, but it’s perfect for a clean example.
  • Base Fee — the default swap fee on devnet is 10%

Now let’s see what happens when we try to swap.

Making the first swap: exchanging 10 X for Y 💥

Recalling the classic AMM formula:

X × Y = K — must remain constant.

Without fees, here’s the basic math:

Initial state of the pool:

  • X = 100, Y = 100
  • So: K = 100 × 100 = 10,000

You add 10 tokens of X:

  • Xnew = 100 + 10 = 110

Now calculate new Y:

  • Ynew = K / Xnew = 10,000 / 110 ≈ 90.91

Amount you receive:

  • AmountOut = Y - Ynew = 100 - 90.91 ≈ 9.09

🔸 So, without any fee, you’d get ~9.09 Y tokens in return for 10 X.

Next up: we’ll factor in the swap fee.

Now let’s include the 10% fee:

Most AMMs apply the fee on the input token, so here’s how it works:

You swap 10 X, but 10% goes to fees:

  • 10 * 0.10 = 1 X taken as a fee
  • Only 10 * 0.90 = 9 X reaches the pool

New pool state:

  • Xnew = 100 + 9 = 109
  • Ynew = 10,000 / 109 ≈ 91.74

Final output:

  • AmountOut = 100 - 91.74 ≈ 8.26 Y

🔺 So you receive 8.26 Y instead of 9.09 Y.

That difference — 0.83 Y — is the effective cost of the 10% swap fee.

Important:

This is not universal behavior — different DEXs and liquidity pools handle this differently:

  • In ExactIn, the fee is subtracted from the input (like in our example)
  • In ExactOut, the fee is taken from the output
  • Some models even add the fee on top of the input amount

That’s why you should always check:

  • Which swap model is used (ExactIn, ExactOut, hybrid)
  • How fees are applied on that specific DEX

What happened to the pool after the swap?

From the screenshot:

  • Token X balance: 109.00
  • Token Y balance: 91.74
  • The new price dropped: from 1 to ≈ 0.841

💡 This price shift reflects how AMMs work — swaps change the ratio, and therefore the price.

📌 Makes sense:

  • You added more of token X,
  • The pool now holds more X and less Y,
  • → So X lost value, and Y became more expensive.

That’s how AMM pricing dynamically adjusts after each swap — the pool always seeks to restore balance through the price.

Let’s do the second swap — exchanging another 10 X for Y 💥

After the first swap, the token balances in the pool have changed. Now let’s run the same swap again — another 10 tokens of X — and see what happens.

Starting state after the first swap:

  • X = 109
  • Y = 91.74
  • K = 10,000 (the formula stays the same)

Let’s factor in the 10% fee right away:

Just like before:

  • You send 10 X
  • 10% fee = 1 X, so only 9 X reaches the pool

New X balance:

  • Xnew = 109 + 9 = 118

Recalculate Y:

  • Ynew = 10,000 / 118 ≈ 84.74

Output:

  • AmountOut = 91.74 - 84.74 = 7 Y

🔻 You only get 7 Y tokens this time — less than the previous swap.

Comparing to the First Swap

  • First swap: 10 X → 8.26 Y
  • Second swap: 10 X → 7 Y, you got less for the same amount of input.

In total:

20 X → 15.26 Y

Why is that?

Because the ratio of tokens in the pool changed — and the price of token X relative to Y dropped.

In other words, your X is now “worth less” than before.

Key Takeaways:

  • The larger the pool’s liquidity, the less your swap affects the price.
  • The larger your swap, the more the price shifts — and the higher the slippage.

Visual Representation:

You can now see:

  • Updated token balances in the pool
  • New X-to-Y ratio
  • The updated price shown in the UI

But Here’s What’s Important to Understand:

The current price shown in the UI is just the token ratio in the pool — not the actual rate you’ll get on your next swap.

The real swap price is calculated at the moment of the transaction, based on:

  • current liquidity,
  • the size of your swap,
  • and the fee model.

Key Takeaways 💥

The formula X * Y = K is simple — but it’s not about fixed exchange rates.

Every swap changes the price.

That’s exactly why arbitrage exists between pools:

If one pool’s price shifts significantly and another hasn’t caught up — that’s an opportunity.

  • The larger your swap, the worse the rate.
  • It’s better to do one swap of size X than two swaps of 0.5X each.
  • If the current pool price is 1.5, that doesn’t mean you’ll get exactly 15 SPL for 10 USDT — because the effective rate is calculated every time via the X * Y = K formula.
  • The greater the pool liquidity (K), the larger your swap can be without significant price impact.

My socials.

Follow if you’re curious 🗿