Перейти к содержанию
Learning Platform
Средний
35 минут
AMM xy=k Constant Product Swap Price Impact Slippage

Требуемые знания:

  • 01-defi-ecosystem

AMM: Автоматический маркет-мейкер

Зачем это блокчейну?

Как обменять токены без посредника и ордер-бука? Автоматический маркет-мейкер (AMM) заменяет трейдеров математической формулой. Вместо “кто-то хочет продать по этой цене” AMM говорит: “вот формула, она определяет цену”.

Одна формула — xy = k — лежит в основе большинства DEX с общим TVL более $20 миллиардов. Uniswap, SushiSwap, PancakeSwap — все они работают на вариациях этой формулы. Понимание xy = k — это ключ к пониманию всего DeFi.

В этом уроке мы разберем формулу на трех уровнях: интуитивно (аналогия с качелями), алгоритмически (пошаговый расчет) и математически (формальное доказательство).

Интуитивное объяснение: кривая xy = k

Что такое AMM Pool?

AMM Pool — это смарт-контракт, который хранит два токена и позволяет обменивать один на другой. Ключевое правило: произведение количеств двух токенов должно оставаться постоянным.

  • Token A — резерв x (например, ETH)
  • Token B — резерв y (например, USDC)
  • Инвариант: x * y = k (постоянное произведение)
  • Цена A в терминах B: price_A = y / x

Аналогия с качелями

Представьте качели: когда одна сторона опускается (больше Token A добавлено в пул), другая поднимается (Token B становится дефицитнее и дороже). AMM всегда сохраняет баланс произведения.

Если в пуле 1000 ETH и 2,000,000 USDC, то k = 2,000,000,000. При добавлении ETH пул “отдает” USDC, но k не меняется.

Кривая xy = k: постоянное произведение
Token A (x)Token B (y)(1000, 1000)(1100, 909)
Swap amount (dx):100 Token A
1250500
Резервы до
x = 1000, y = 1000
Резервы после
x = 1100, y = 909
k = x * y
1,000,000 (const)
Output (dy)
90.91 Token B
Цена до (y/x)
1.0000
Цена после
0.8264

Свойства кривой

Кривая xy = k — это гипербола. Ее ключевые свойства:

  1. Асимптотическая: Кривая никогда не касается осей. Резервы никогда не могут стать нулевыми
  2. Выпуклая: Большие свопы получают прогрессивно худшую цену (price impact)
  3. Симметричная: Обмен в обе стороны работает одинаково
  4. Бесконечная ликвидность: Пул всегда может выдать цену (пусть и плохую для больших ордеров)

Пошаговый расчет свопа

Разберем конкретный пример: обмен 10 ETH на USDC в пуле с 1000 ETH и 2,000,000 USDC.

Swap: пошаговый расчет
Начальное состояние пула
Пул ETH/USDC содержит ликвидность. Текущая цена определяется соотношением резервов: 2,000,000 / 1,000 = 2,000 USDC за 1 ETH.
Reserve ETH (x)
1,000
Reserve USDC (y)
2,000,000
k = x * y
2,000,000,000
Цена ETH
2,000 USDC

Полный расчет

Пул: x = 1000 ETH, y = 2,000,000 USDC, k = 2,000,000,000.

Шаг 1: Trader отправляет dx = 10 ETH в пул.

Шаг 2: Вычитается комиссия 0.3%:

dx_effective = 10 * (1 - 0.003) = 10 * 0.997 = 9.97 ETH
fee = 10 * 0.003 = 0.03 ETH (остается в пуле)

Шаг 3: Рассчитываем новые резервы:

new_x = 1000 + 9.97 = 1009.97
new_y = k / new_x = 2,000,000,000 / 1009.97 = 1,980,258.49
dy = y - new_y = 2,000,000 - 1,980,258.49 = 19,741.51 USDC

Шаг 4: Trader получает 19,741.51 USDC.

Эффективная цена: 19,741.51 / 10 = 1,974.15 USDC/ETH (вместо спотовой 2,000).

Формула без комиссии

Выведем формулу аналитически.

Постановка

Имеем пул с резервами x и y. Инвариант: x * y = k. Trader вносит dx токенов A и получает dy токенов B.

Вывод

После свопа (без комиссии):

(x + dx) * (y - dy) = k

Раскрываем:

xy + dx*y - x*dy - dx*dy = k

Поскольку xy = k:

dx*y - x*dy - dx*dy = 0
dx*y = dy*(x + dx)

Решаем для dy:

dy=ydxx+dxdy = \frac{y \cdot dx}{x + dx}

Это формула выходного количества без комиссии. Заметьте: dy всегда меньше, чем dx * (y/x) — потому что знаменатель (x + dx) > x.

Формула с комиссией (0.3%)

В реальных AMM (Uniswap V2) комиссия вычитается до расчета:

dy=ydx(1f)x+dx(1f)dy = \frac{y \cdot dx \cdot (1 - f)}{x + dx \cdot (1 - f)}

Где f = 0.003 (0.3%).

Целочисленная арифметика

Solidity не поддерживает дробные числа. Uniswap V2 использует целочисленную формулу:

dy = y * dx * 997 / (x * 1000 + dx * 997)

Это эквивалентно:

(1 - f) = 997/1000
dy = y * (dx * 997) / (x * 1000 + dx * 997)

Пример с числами

Пул: x = 1000 ETH, y = 2,000,000 USDC. Swap: dx = 10 ETH.

dy = 2,000,000 * 10 * 997 / (1000 * 1000 + 10 * 997)
   = 2,000,000 * 9,970 / (1,000,000 + 9,970)
   = 19,940,000,000 / 1,009,970
   = 19,742.50 USDC

Разница с нашим расчетом выше (19,741.51) — погрешность округления. В Solidity используется целочисленное деление (округление вниз).

Price Impact: влияние размера сделки

Price impact — это разница между спотовой ценой и эффективной ценой сделки. Чем больше сделка относительно пула, тем хуже цена.

Price Impact: влияние размера сделки
5%Swap size (ETH)Impact %01002003004005000%5%10%15%20%25%30%35%
Swap amount:10 ETH
1 ETH250 ETH500 ETH
Output
19743.16 USDC
Эффективная цена
1974.32 USDC/ETH
Спотовая цена
2000.00 USDC/ETH
Price impact
0.99% (OK)
price_impact = dx / (x + dx) = 10 / (1000 + 10) = 0.9901%
Защита от проскальзыванияУстановите amountOutMin для ограничения максимального impact. amountOutMin = 0 -- классическая уязвимость (sandwich attack).

Формула price impact

price_impact = dx / (x + dx)

Примеры

Swap sizePool sizePrice Impact
0.1 ETH1000 ETH0.01%
1 ETH1000 ETH0.1%
10 ETH1000 ETH0.99%
100 ETH1000 ETH9.09%
500 ETH1000 ETH33.33%

Правило: Если ваш swap > 1% от пула, price impact будет заметным. Если > 5% — значительным.

Slippage Protection

Параметр amountOutMin защищает от проскальзывания:

function swap(uint amountIn, uint amountOutMin) external {
    uint amountOut = getAmountOut(amountIn);
    require(amountOut >= amountOutMin, "Slippage exceeded");
    // ... выполнить своп
}

КРИТИЧНО: Установка amountOutMin = 0 — классическая уязвимость. Это позволяет sandwich attack: атакующий вставляет свою транзакцию до и после вашей, извлекая прибыль из вашего проскальзывания. Подробнее в Phase 7 (Security).

Комиссии и рост k

Комиссия 0.3% вычитается до расчета, но все токены остаются в пуле. Это означает, что после каждого свопа k растет:

Комиссии: как растет k
Initial
#1
#2
#3
#4
#5
k: 2,000,000,0002,007,899,534 (+0.3950%)
Монотонный рост kk никогда не уменьшается. Комиссии остаются в пуле и увеличивают k. Доля LP в растущем пуле -- это заработок провайдеров ликвидности.

Механизм

  1. Trader отправляет 10 ETH. Комиссия 0.03 ETH
  2. Расчет ведется для dx = 9.97 ETH (после комиссии)
  3. Но в пул добавляются все 10 ETH (включая комиссию)
  4. Из пула изымаются dy USDC (рассчитанных для 9.97 ETH)
  5. Результат: в пуле больше токенов, чем нужно для k
k_new = (x + 10) * (y - dy) > k_old

k_new > k_old, потому что 0.03 ETH комиссии остались в пуле.

Что это значит для LP?

Провайдеры ликвидности (LP) владеют долей пула через LP-токены. Когда k растет:

  • Пул содержит больше активов
  • Доля LP стоит больше
  • LP зарабатывают на каждом свопе

Это основной incentive для предоставления ликвидности. Однако LP также несут риск impermanent loss (урок DEFI-05).

Алгоритмический уровень: псевдокод AMM

# Упрощенный AMM своп (Uniswap V2 логика)

def swap(token_in: address, amount_in: uint256, amount_out_min: uint256):
    # 1. Определить направление
    (reserve_in, reserve_out) = get_reserves(token_in)

    # 2. Рассчитать output с комиссией 0.3%
    amount_in_with_fee = amount_in * 997
    numerator = reserve_out * amount_in_with_fee
    denominator = reserve_in * 1000 + amount_in_with_fee
    amount_out = numerator / denominator

    # 3. Проверить slippage
    require(amount_out >= amount_out_min, "Slippage exceeded")

    # 4. Перевести токены
    transfer(token_in, msg.sender -> pool, amount_in)
    transfer(token_out, pool -> msg.sender, amount_out)

    # 5. Обновить резервы
    update_reserves()

    # 6. Проверить k-инвариант (с комиссией k должен вырасти)
    assert new_reserve_in * new_reserve_out >= old_k

Ключевые детали

  • Порядок операций: Сначала перевод в пул, потом проверка инварианта
  • Целочисленная арифметика: Нет дробных чисел, все через умножение/деление
  • k-инвариант: Проверяется >=, а не ==, потому что комиссия увеличивает k

Математический уровень: формальный вывод

Константное произведение

Пусть x,y>0x, y > 0 — резервы пула, k=xyk = xy — инвариант.

Своп без комиссии

Trader вносит Δx>0\Delta x > 0 и получает Δy>0\Delta y > 0:

(x+Δx)(yΔy)=k=xy(x + \Delta x)(y - \Delta y) = k = xy

Раскрываем:

xy+ΔxyxΔyΔxΔy=xyxy + \Delta x \cdot y - x \cdot \Delta y - \Delta x \cdot \Delta y = xy

Упрощаем (xy сокращается):

Δxy=Δy(x+Δx)\Delta x \cdot y = \Delta y(x + \Delta x) Δy=yΔxx+Δx\Delta y = \frac{y \cdot \Delta x}{x + \Delta x}

Своп с комиссией

Пусть γ=1f\gamma = 1 - f (для 0.3%: γ=0.997\gamma = 0.997). Эффективный вход:

Δy=yγΔxx+γΔx\Delta y = \frac{y \cdot \gamma \cdot \Delta x}{x + \gamma \cdot \Delta x}

Маргинальная цена

Маргинальная цена — производная output по input:

Pmarginal=d(Δy)d(Δx)=yx(x+Δx)2P_{marginal} = \frac{d(\Delta y)}{d(\Delta x)} = \frac{y \cdot x}{(x + \Delta x)^2}

При Δx0\Delta x \to 0: PmarginalyxP_{marginal} \to \frac{y}{x} (спотовая цена).

При Δx\Delta x \to \infty: Pmarginal0P_{marginal} \to 0 (бесконечный price impact).

Price impact

Price Impact=1PeffectivePspot=1Δy/Δxy/x=Δxx+Δx\text{Price Impact} = 1 - \frac{P_{effective}}{P_{spot}} = 1 - \frac{\Delta y / \Delta x}{y / x} = \frac{\Delta x}{x + \Delta x}

Это убывающая функция x (размера пула) и возрастающая функция Δx\Delta x (размера свопа). Чем глубже пул, тем меньше impact.

Рост k от комиссий

После свопа с комиссией:

knew=(x+Δx)(yΔy)k_{new} = (x + \Delta x)(y - \Delta y)

Подставляем Δy\Delta y с комиссией:

knew=(x+Δx)(yyγΔxx+γΔx)k_{new} = (x + \Delta x) \left( y - \frac{y \cdot \gamma \cdot \Delta x}{x + \gamma \cdot \Delta x} \right) knew=(x+Δx)yx+γΔxγΔxx+γΔxk_{new} = (x + \Delta x) \cdot y \cdot \frac{x + \gamma \cdot \Delta x - \gamma \cdot \Delta x}{x + \gamma \cdot \Delta x} knew=(x+Δx)yxx+γΔxk_{new} = \frac{(x + \Delta x) \cdot y \cdot x}{x + \gamma \cdot \Delta x}

Поскольку γ<1\gamma < 1, имеем x+γΔx<x+Δxx + \gamma \cdot \Delta x < x + \Delta x, следовательно:

knew=(x+Δx)x+γΔxxy>xy=kk_{new} = \frac{(x + \Delta x)}{x + \gamma \cdot \Delta x} \cdot xy > xy = k

Q.E.D. k монотонно растет с каждым свопом, когда f>0f > 0.

Что дальше

В следующем уроке (DEFI-03) мы погрузимся в реальный код Uniswap V2:

  • Смарт-контракты Factory и Pair
  • Минтинг LP-токенов
  • Flash Swaps
  • Fork-тестирование на реальных данных Ethereum

В уроке DEFI-04 разберем революцию Uniswap V3 — концентрированная ликвидность, которая позволяет LP зарабатывать в 100-4000x больше комиссий на том же капитале. И заглянем в будущее: Uniswap V4 с hooks и singleton architecture.

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс