Market Makers but Automated
A complete guide on how AMMs work, built around x . y = k contract.
Market Makers but Automated
A complete guide on how AMMs work, built around x . y = k contract.

What is Market Maker??
Before we talk about automated market makers, we need to understand what a market maker is in the traditional financial world.
Imagine a fruit market You walk into a fruit market wanting to sell 10 kg of apples. But right now there is no one who wants to buy apples. You are stuck and now you have to wait until a buyer shows up.
Now imagine there is a special shopkeeper who says: “I will always buy your apples, and I will always sell apples to anyone who wants them.” This shopkeeper holds a big pile of apples and a big pile of cash at all times. They quote two prices:
- A bid price — what they’ll pay you when you sell to them (say ₹18/kg).
- An ask price — what they’ll charge when you buy from them (say ₹20/kg).
The small gap (₹2) is the SPREAD, and it’s how the shopkeeper makes a profit for taking on the risk and inconvenience of always being ready to trade.
That shopkeeper is a market maker. Their entire job is to provide liquidity (the ability to buy or sell instantly, without waiting for a matching counterparty). In stock markets, big firms do exactly this for shares: they’re always willing to buy and sell, so you never have to wait.
Key Takeaways
A market maker solves the “coincidence of wants” problem. Without one, every trade requires a buyer and seller who want the exact opposite thing, at the exact same price, at the exact same time. That almost never happens naturally, so market maker steps in and become the counterparty for everyone.
The problem with Traditional Order Books in DeFi
Traditional exchanges and centralized crypto exchanges like Binance uses Order Book. But,
WHAT ACTUALLY AN ORDER BOOK IS?? An order book is just a giant list of offers, When a buyer’s price meets a seller’s price, the exchange matches them and the trade happens. This works beautifully on fast, centralized servers.
The Problem:- As we know, On Ethereum every single action costs gas and takes block time. Early defi tried on-chain order books and they were clunky, slow and expensive. The Blockchain needed a fundamentally different design, one that didn’t need a counterparty to be online, didn’t need constant order updates, and could price assets with pure math.
Thus resulting design came up with Automated Market Makers.
What actually is an AMM?
A smart-contract-based protocol used by decentralized exchange(DEXs) to price and trade digital assets automatically. Instead of relying on a traditional order book where buyers and sellers must be matched at a specific price, AMMs use an algorithmic formula and crowdsourced pools of token to facilitate instant, 24/7 trading on the blockchain.
What it does? An AMM replaces the human market maker and the Order Book with two things:
- A pool of token that anyone can contribute to, i.e. crowdsourced liquidity.
- A mathematical formula that automatically sets the price based on how many tokens are in the pool.
Instead of trading against another person, you trade against the pool itself. You put tokens in, the formula calculates how many tokens you get out, and the contract sends them to you instantly, with no counterparty needed.
The Three Building Blocks
Every constant-product AMM breaks down into 3 main components:
- Liquidity Pool
- Liquidity providers
- Algorithmic Pricing
How AMMs works (The Constant Product Formula)
x . y = k
x = total quantity of token A in the pool y = total quality of the token B in pool k = a fixed constant that must say the same before and after every trade
The rule is brutally simple:
Whatever you do, the product x · y must not decrease. When someone trades, they add some of one token and remove some of the other, but the product k stays constant (ignoring fees for a moment). That single rule is what sets the price.
Lets understand it more easily:-
imagine a brand-new pool with 10ETH and 20,000 USDC.
k = x · y = 10 × 20,000 = **200,000**
what’s the price of 1 ETH then?
It’s the ratio of the reserves:
price of 1 ETH = USDC reserve / ETH reserve = 20,000 / 10 = 2,000 USDC
so the spot price of 1 ETH is 2,000 USDC. From here we got that the price emerges purely from the ratio of what’s in the pool.
Why a curve instead of a fixed price?
Because the price must change as the reserves change. If ETH gets scarcer in the pool (people are buying it), each remaining ETH must get more expensive, otherwise the pool would be drained to zero. The x · y = k curve enforces exactly this:
The more of a token you try to buy, the more expensive each additional unit becomes. This is what makes the pool impossible to fully drain and is the source of price impact.
Liquidity Pools
What They Are?
A liquidity pool is a smart contract containing a paired reserve of two different tokens (for e.g. ETH & USDC). Instead of trading directly with another person, users trade against the pool.
How they Work?
1.The pool holds the reserves In our contract, the pool is created with two token addresses, and it tracks how much of each it holds:
IERC20 private immutable token0; // WETH
IERC20 private immutable token1; // USDC
uint256 private reserve0; // how much WETH the pool holds
uint256 private reserve1; // how much USDC the pool holds
2. Reserves are “re-synced” from real balances A subtle but important design choice: after every operation, the contract doesn’t just trust its internal counters, it re-reads the actual token balances and updates the reserves:
function updateReserves() internal {
reserve0 = token0.balanceOf(address(this));
reserve1 = token1.balanceOf(address(this));
emit ReserveUpdated(reserve0, reserve1);
}
This keeps the pool’s accounting honest and matches the real tokens it holds.
How a swap moves the reserves
When swap takes place, the contract:
- Pulls input token in (reserves of that token go up).
- Calculates output using the curve.
- Sends the output token out (reserves of that token go down).
- Re-syncs reserves and emits a
Swappedevent.
That’s the entire life of a trade. No order book, no counterparty, just a formula and two balances changing.
Liquidity Providers & LP Tokens
The tokens in these pools are deposited by liquidity providers. They lock their assets in order to facilitate trades. In return, they earn a proportional share of trading fees generated by the pool.
Who fills the pool?
The pool doesn’t create tokens from thin air. Liquidity Providers deposit them. In return, they get an LP token. Now think of it as a receipt that says “I own X% of this pool.” When they want to leave, they hand back the receipt and withdraw their share of the reserves (plus any fees that accumulated while they were in).
Adding liquidity
1. The First Deposit The very first LP sets the initial price by choosing the ratio of tokens they deposit. The contract mints them LP shares equal to the geometric mean of the two amounts:
if (poolToken.totalSupply() == 0) {
shares = sqrt(_reserveAdded0 * _reserveAdded1);
}
Why sqrt(a · b)?
Using the square root of the product makes the number of LP shares independent of the units and proportional to the actual liquidity depth. If you deposited 10 WETH and 20,000 USDC, you'd get sqrt(10 20,000) = sqrt(200,000) = 447 shares. The exact number doesn't matter, what matters is that it scales correctly so later depositors get a fair, proportional* amount.
The contract implements the square root with the classic Babylonian method (iterative averaging):
function sqrt(uint256 x) internal pure returns (uint256 z) {
if (x == 0) return 0;
else if (x == 1) return 1;
else {
z = x;
uint256 y = (x / 2) + 1;
while (y < z) {
z = y;
y = ((x / y) + y) / 2; // average guess with x/guess, converges to sqrt(x)
}
}
}
2. Later deposits must match the ratio Once the pool exists, you can’t deposit a lopsided amount that would change the price and let you effectively trade for free. So the contract enforces that your deposit matches the current reserve ratio, within a 1% tolerance:
uint256 left = reserve0 * _reserveAdded1;
uint256 right = reserve1 * _reserveAdded0;
uint256 diff = left > right ? left - right : right - left;
require(diff * 1000 <= left * 100, "Invalid Ratio of Token--1% tolerence");
shares = min(
(_reserveAdded0 * poolToken.totalSupply()) / reserve0,
(_reserveAdded1 * poolToken.totalSupply()) / reserve1
);
The min() function means you're credited based on whichever side you contributed less of, relative to the pool, preventing you from gaming the system by over-supplying one token.
Removing liquidity
To leave, you burn your shares and get back a proportional slice of both reserves:
reserveAmountRemoved0 = (_shares * balance0) / poolToken.totalSupply();
reserveAmountRemoved1 = (_shares * balance1) / poolToken.totalSupply();
If you own 10% of all LP shares, you get back 10% of the WETH and 10% of the USDC currently in the pool. Because fees have been quietly accumulating in those reserves, you typically withdraw more than you put in that’s your yield.
Price Impact & Slippage
This is where the x · y = k curve shows its teeth.
Lets start with and Example of buying 1 ETH
Take our pool again: 10 ETH and 20,000 USDC, with k = 200,000. The spot price said 1 ETH = 2,000 USDC. So buying 1 ETH should cost 2,000 USDC, right? Wrong. Let's see why.
You want to remove 1 ETH, so the new ETH balance must be 9. But k must stay at 200,000, so the pool calculates the required USDC balance:
new USDC balance = k / new ETH balance = 200,000 / 9 = 22,222.22 USDC
The pool currently has 20,000 USDC, so you must deposit the difference:
22,222.22 − 20,000 = 2,222 USDC
So you paid 2,222 USDC for 1 ETH, not 2,000. That extra 222 USDC is price impact (often loosely called slippage). And the rule it reveals: The larger your trade is relative to the pool’s total size, the worse the price you get. Big trades in small pools move the price a lot; small trades in deep pools barely move it. This is the AMM’s natural defense against being drained i.e. buying all the ETH would cost an infinite amount of USDC, because the curve approaches the axis but never touches it.
How the contract actually computes a swap
The example above is the clean, fee-free, “I know exactly how much I want out” mental model. Contracts work slightly differently, it takes a fixed input and includes the 0.3% fee:
uint256 amountInWithFee = (_amountIn * 997) / 1000;// take 0.3% fee
amountOut = (amountInWithFee * reserveOut) / (reserveIn + amountInWithFee);
This is algebraically the same constant-product curve, just rearranged to solve for the output given an input, and with the fee shaved off the input first.
Slippage protection
“Slippage” in practice also means: the price moved against you between when you clicked and when your transaction landed on-chain (because someone traded just before you). Protecting against this means specifying a minimum acceptable output and reverting if reality is worse.
Trading Fees (How LP’s Actually Earn)
Every swap takes a small fee (0.3%) and leaves it in the pool. This slowly increases the value of k, meaning LPs eventually burn their LP tokens to withdraw more funds than they deposited.
Where the fee comes from
Looking again at the swap math:
uint256 amountInWithFee = (_amountIn * 997) / 1000;
Here’s the clever part: the contract pulls in full _amountIn, but only credits 99.7% of it toward the curve calculation. The remaining 0.3% stays in the pool and is never given back to you. It just sits there, increasing the reserves.
How fees become LP yield
Because LP shares are redeemed for a proportional slice of the reserves, and the reserves keep growing from accumulated fees, the value backing each LP share grows over time. No fees are paid out separately they’re baked directly into the pool. When you finally withdraw, your shares are simply worth more tokens than when you deposited.
This is also why traders sometimes say fees “increase k": every swap nudges the constant k upward slightly, and that growth belongs to the LPs.
Example: if a pool does a lot of volume, an LP who deposited the equivalent of $10,000 might redeem $10,300 worth of tokens later, the extra $300 is their cut of all the 0.3% fees collected while they were providing liquidity.
Arbitrage(The Invisible Hand That Keeps Prices Honest)
If the AMM’s price is set purely by internal math, how does it ever match the real-world price of a token and the answer is it relies entirely on arbitrageurs usually known as automated bots.
How arbitrage corrects the price
Suppose a massive sell-off happens on Binance and ETH drops to $1,800. But our isolated AMM pool, having seen no trades yet, is still pricing ETH at $2,000. That’s a $200 mispricing listed.
Now the bots instantly does 2 things:
- Buy cheap ETH on Binance at $1,800.
- Sell it into our AMM pool at $2,000.
Each time they sell ETH into the pool, the pool’s ETH reserve goes up and its USDC reserve goes down, which (per x · y = k) lowers the pool's ETH price. Bots keep doing this until the pool's price drops to ~$1,800 and the profit disappears.
The result: the AMM’s internal math gets dragged into line with the broader market automatically, with no oracle and no admin. Arbitrage is the “invisible hand” that keeps a purely mathematical price honest. The traders chasing profit are, as a side effect, performing a public good keeping the pool accurate.
This is elegant, but it has a dark side for LPs, which is Impermanent Loss.
Impermanent Loss
Impermanent loss (IL) is arguably the most counterintuitive concept in decentralized finance. When interacting with or designing an AMM, it is crucial to understand that providing liquidity is not a risk-free yield play. It is actively taking a position on the volatility of two assets or simply we can say that IL is the difference in total value between simply holding 2 assets in your wallet, versus providing those same assets as liquidity in an AMM pool.
It’s called impermanent because the loss only becomes permanent when you withdraw. If prices return to where they started, the loss disappears.
Why does it happen?
The AMM algorithm forces you to automatically be on the losing side. As ETH becomes more valuable, the pool algorithmically sells off your ETH to arbitrageurs to maintain the constant k. So at the end you are always selling the outperforming asset to buy more of the underperforming one. When ETH’s market price rises, arbitrageurs buy ETH out of your pool until the pool price catches up. That means the pool automatically sells your ETH while it’s going up. You end up holding less of the winner and more of the loser than if you had just sat on the coins in your wallet. The pool mechanically rebalances you into the wrong direction every time prices move.
The IL formula
For a 2-token pool (x · y = k), if the price changes by a ratio r:
2 * √r
IL = ─────────── − 1
1 + r
where:
new price
r = ───────────
old price
Reading the formula
- If
r = 1(price didn't move):IL = (2*1)/(2) − 1 = 0. No loss. Makes sense, nothing changed. - If
r = 4:IL = (2*2)/(5) − 1 = 0.8 − 1 = −0.20, i.e. −20%. You ended up with 20% less value than if you'd just held. - The result is always ≤ 0 i.e. IL is never positive. Any price movement in either direction costs the LP, relative to holding.
The crucial trade-off
So why provide liquidity at all? Because LPs earn. The real question for an LP is always:
Will the trading fees I collect outweigh the impermanent loss I suffer?
Yes, In a high-volume low-volatility pair (like two stablecoins), fees usually win. In a volatile pair that trends hard in one direction, IL can easily swamp the fees. Providing liquidity is a bet that fees > IL.
The Vault (Auto-Zapping with ERC-4626)
Everything so far describes the raw pool. But using it is annoying: to add liquidity we need both WETH and USDC, in the right ratio but What if a user only has USDC and just wants to “deposit and earn”?
That’s what the Vault solves. It's an ERC-4626 vault a standardized "tokenized vault" interface that lets a user deposit a single asset (USDC) and have everything else handled automatically.
What “Zapping” means
Zapping is taking a single token and automatically converting it into a balanced LP position. The vault does this for you on deposit:
1. Figure out what fraction of the USDC to convert to WETH so both sides are balanced
uint256 usdcToSwap = (usdcAmount * currReserve0) / (currReserve0 + currReserve1)
2. Swap that fraction USDC -> WETH (with slippage protection)
uint256 token0Out = amm.swap(address(token1), usdcToSwap);
require(token0Out >= minToken0Out, "Slippage too high");
3. Add both sides as liquidity, receive LP tokens
uint256 token1Remaining = usdcAmount - usdcToSwap;
shares = amm.addLiquidity(token0Out, token1Remaining);
So from the user’s point of view: USDC goes in → vault shares (vUSDC) come out. Under the hood the vault swapped, added liquidity, and is now holding LP tokens on their behalf.
Why ERC-4626?
ERC-4626 is a battle-tested standard for “deposit an asset, get shares that represent your growing claim on a pool.” By conforming to it, this vault automatically speaks the same language as the rest of DeFi (aggregators, frontends, other protocols). The vault overrides the key hooks:
deposit/mint— pull USDC, zap into LP, mintvUSDCshares.withdraw/redeem— burn shares, pull liquidity out, swap the WETH leg back to USDC, return USDC to the user.totalAssets()— the single most important function: it values the vault's entire LP position in USDC terms using the pool's live exchange rate, so share pricing is always accurate.
Slippage protection at the vault layer
The core swap() has no built-in slippage guard. The vault adds one with a configurable slippageBps = 100 (1%), computing an expected output and reverting if the real swap underdelivers. This is the right layering: keep the core pool minimal, put user protection in the layer users actually touch.
In short: the AMM is the engine; the vault is the user-friendly dashboard bolted on top.
Conclusion
Let’s bring it all together. Why AMM matters?
A traditional market needs a market maker to always be willing to trade. On a blockchain, order books are too slow and expensive, so DeFi replaced the human market maker with math and a shared pool of tokens. That’s an AMM. The whole system rests on a single, beautiful equation:
x * y = k
From that one rule, everything emerges:
- Pricing comes from the ratio of reserves.
- Price impact comes from the curve’s shape.
- Fees (0.3%) accumulate in the pool and become LP yield.
- Arbitrage keeps the pool’s price honest against the real world.
- Impermanent loss is the price LPs pay for that automatic rebalancing.
- And clever layers like an ERC-4626 auto-zapping vault make the whole thing usable by ordinary users with a single token.
AMMs matter because they made markets permissionless. Anyone, anywhere, can create a market for any token and trade it instantly, with no gatekeeper. That is one of the genuinely new things blockchains made possible. And now we know exactly how it works, all the way down to the formula.
메타데이터
- post_id
- ec475d5bd4a8
- slug
- market-makers-but-automated-ec475d5bd4a8
- url
- https://medium.com/@viihshaal/market-makers-but-automated-ec475d5bd4a8
- canonical_url
- https://medium.com/@viihshaal/market-makers-but-automated-ec475d5bd4a8
- author_url
- https://medium.com/@viihshaal
- status
- ok
- fetched_at
- 2026-08-20 18:19:56