Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Паттерны DeFi
defi_patterns

Паттерны DeFi

AMM и формула x*y=k, пулы ликвидности, стейкинг-контракты, оракулы цен, flash loans

Паттерны DeFi

DeFi перестроил финансовую систему на открытом коде. Понимание AMM и пулов ликвидности — основа для любого Web3-разработчика

#Что такое DEX и AMM

Традиционная биржа использует книгу ордеров (order book): покупатели и продавцы выставляют заявки, матчинг-движок их сводит. Это эффективно, но требует централизованного оператора.

DEX (Decentralized Exchange) — биржа на смарт-контрактах. AMM (Automated Market Maker) — алгоритмический маркет-мейкер без книги ордеров. Цена определяется математической формулой на основе соотношения активов в пуле ликвидности.

#Формула Constant Product (x * y = k)

Основа Uniswap v1/v2 и множества других AMM. Принцип: произведение резервов двух токенов остаётся константным.

Если пул содержит x единиц токена A и y единиц токена B, то после любого свопа x' * y' = k = x * y.

Покупая dA токенов A, вы добавляете dB токенов B. Формула определяет сколько именно dA вы получите:

x * y = k
(x - dA) * (y + dB) = k

dA = x - k / (y + dB)

Эта математика автоматически регулирует цену: чем больше покупаешь A, тем дороже становится A (скользящая цена — price impact).

#Пул ликвидности

Ликвидность обеспечивают LP (Liquidity Providers). Они вносят оба токена в равных долях по текущей рыночной цене и получают LP-токены, подтверждающие долю в пуле.

// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; // Упрощённый AMM — только иллюстрация механизма contract SimpleAMM { IERC20 public tokenA; IERC20 public tokenB; uint256 public reserveA; uint256 public reserveB; // LP shares mapping(address => uint256) public shares; uint256 public totalShares; constructor(address _tokenA, address _tokenB) { tokenA = IERC20(_tokenA); tokenB = IERC20(_tokenB); } // Добавление ликвидности function addLiquidity(uint256 amountA, uint256 amountB) external returns (uint256 mintedShares) { tokenA.transferFrom(msg.sender, address(this), amountA); tokenB.transferFrom(msg.sender, address(this), amountB); if (totalShares == 0) { // Первое добавление: shares = sqrt(amountA * amountB) mintedShares = sqrt(amountA * amountB); } else { // Последующие: пропорционально существующим резервам mintedShares = min( amountA * totalShares / reserveA, amountB * totalShares / reserveB ); } shares[msg.sender] += mintedShares; totalShares += mintedShares; reserveA += amountA; reserveB += amountB; } // Своп tokenA -> tokenB function swapAtoB(uint256 amountAIn) external returns (uint256 amountBOut) { require(amountAIn > 0, "Zero input"); // Формула: (reserveA + amountAIn) * amountBOut = reserveA * reserveB // С комиссией 0.3%: амортизируем 99.7% от input uint256 amountAWithFee = amountAIn * 997; amountBOut = (amountAWithFee * reserveB) / (reserveA * 1000 + amountAWithFee); require(amountBOut > 0, "Insufficient output"); tokenA.transferFrom(msg.sender, address(this), amountAIn); tokenB.transfer(msg.sender, amountBOut); reserveA += amountAIn; reserveB -= amountBOut; } function sqrt(uint256 x) internal pure returns (uint256) { if (x == 0) return 0; uint256 z = (x + 1) / 2; uint256 y = x; while (z < y) { y = z; z = (x / z + z) / 2; } return y; } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } }

#Impermanent Loss

LP провайдеры несут риск непостоянных потерь. Когда цена токена резко меняется по сравнению с моментом внесения ликвидности, стоимость активов LP оказывается ниже, чем если бы они просто держали токены (HODL).

Пример: вы вносите 1 ETH + 1000 USDC (цена ETH = $1000). Цена ETH вырастает до $4000. AMM балансирует пул: теперь там 0.5 ETH + 2000 USDC. Ваши активы стоят $4000, но если бы держали — 1 ETH + 1000 USDC = $5000. Потеря $1000 — это impermanent loss. "Непостоянная" — потому что если цена вернётся к $1000, потеря исчезнет.

#Стейкинг-контракт

Базовый стейкинг: пользователи блокируют токены и получают вознаграждение пропорционально времени и сумме.

// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; contract Staking is ReentrancyGuard { IERC20 public immutable stakingToken; IERC20 public immutable rewardToken; uint256 public rewardRate; // токены награды в секунду uint256 public lastUpdateTime; uint256 public rewardPerTokenStored; mapping(address => uint256) public userRewardPerTokenPaid; mapping(address => uint256) public rewards; mapping(address => uint256) public balances; uint256 public totalSupply; constructor(address _staking, address _reward, uint256 _rewardRate) { stakingToken = IERC20(_staking); rewardToken = IERC20(_reward); rewardRate = _rewardRate; } // Accumulated reward per staked token function rewardPerToken() public view returns (uint256) { if (totalSupply == 0) return rewardPerTokenStored; return rewardPerTokenStored + (rewardRate * (block.timestamp - lastUpdateTime) * 1e18) / totalSupply; } // Сколько наград накопил пользователь function earned(address account) public view returns (uint256) { return (balances[account] * (rewardPerToken() - userRewardPerTokenPaid[account])) / 1e18 + rewards[account]; } modifier updateReward(address account) { rewardPerTokenStored = rewardPerToken(); lastUpdateTime = block.timestamp; if (account != address(0)) { rewards[account] = earned(account); userRewardPerTokenPaid[account] = rewardPerTokenStored; } _; } function stake(uint256 amount) external nonReentrant updateReward(msg.sender) { totalSupply += amount; balances[msg.sender] += amount; stakingToken.transferFrom(msg.sender, address(this), amount); } function withdraw(uint256 amount) external nonReentrant updateReward(msg.sender) { totalSupply -= amount; balances[msg.sender] -= amount; stakingToken.transfer(msg.sender, amount); } function getReward() external nonReentrant updateReward(msg.sender) { uint256 reward = rewards[msg.sender]; if (reward > 0) { rewards[msg.sender] = 0; rewardToken.transfer(msg.sender, reward); } } }

#Оракулы цен

Смарт-контракт не может сам получить цену токена — нужен оракул.

Spot price из AMM (простая цена из пула) — уязвима к flash loan манипуляциям. Рекомендуется использовать Uniswap v3 TWAP (Time-Weighted Average Price) или Chainlink Price Feed.

Chainlink — декентрализованная сеть оракулов, которые агрегируют цены с бирж и публикуют их on-chain. Самый надёжный вариант для production. Для чтения цены достаточно одного view-вызова к AggregatorV3Interface.

Далее: Оптимизация газа