Разработка системы buyback-and-burn
Buyback-and-burn — механизм дефляционного давления на токен: протокол использует часть выручки для покупки своего токена на рынке и его уничтожения. BNB, MKR, GMX — все используют вариации этого механизма. Реализация требует чёткой on-chain логики, правильного выбора DEX-роутера и защиты от sandwich-атак.
Как работает механизм
Базовая схема: protocol fee -> buyback contract -> swap на DEX -> burn. Ключевые решения:
Источник средств: комиссии протокола (trading fees, lending fees, mint fees). Обычно контракт аккумулирует USDC/ETH, а buyback триггерится по расписанию или по достижению порога.
DEX для свопа: Uniswap V3 через Universal Router или Swap Router 02 — наиболее ликвидный вариант для Ethereum/L2. На BSC — PancakeSwap. Для крупных buyback важен маршрут через несколько пулов.
Burn механизм: token.transfer(address(0xdead)) или token.burn(amount) если есть функция. Отправка на 0xdead — не настоящий burn с точки зрения totalSupply(), но принятый стандарт. Настоящий burn через _burn() уменьшает totalSupply.
Контракт buyback
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable2Step.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
interface IBurnable is IERC20 {
function burn(uint256 amount) external;
}
contract BuybackAndBurn is Ownable2Step, ReentrancyGuard {
using SafeERC20 for IERC20;
ISwapRouter public immutable swapRouter;
IERC20 public immutable paymentToken; // USDC/ETH/WETH
IBurnable public immutable projectToken;
address public immutable BURN_ADDRESS = address(0xdead);
uint24 public poolFee = 3000; // 0.3% пул, настраивается
uint256 public maxSlippageBps = 200; // 2% максимальный slippage
uint256 public minBuybackAmount; // минимальный порог для триггера
event BuybackExecuted(
uint256 paymentAmount,
uint256 tokensBought,
uint256 tokensBurned
);
constructor(
address _router,
address _paymentToken,
address _projectToken,
uint256 _minBuybackAmount
) Ownable(msg.sender) {
swapRouter = ISwapRouter(_router);
paymentToken = IERC20(_paymentToken);
projectToken = IBurnable(_projectToken);
minBuybackAmount = _minBuybackAmount;
}
function executeBuyback(uint256 amountIn, uint256 amountOutMinimum)
external
nonReentrant
onlyOwner
{
require(amountIn >= minBuybackAmount, "Below minimum buyback amount");
require(
paymentToken.balanceOf(address(this)) >= amountIn,
"Insufficient balance"
);
paymentToken.approve(address(swapRouter), amountIn);
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
tokenIn: address(paymentToken),
tokenOut: address(projectToken),
fee: poolFee,
recipient: address(this),
deadline: block.timestamp + 300, // 5 минут
amountIn: amountIn,
amountOutMinimum: amountOutMinimum, // защита от sandwich
sqrtPriceLimitX96: 0
});
uint256 amountOut = swapRouter.exactInputSingle(params);
// Burn купленные токены
projectToken.burn(amountOut);
emit BuybackExecuted(amountIn, amountOut, amountOut);
}
// Расчёт minAmountOut off-chain через Uniswap SDK перед вызовом
function getMinAmountOut(uint256 amountIn)
external
view
returns (uint256)
{
// Это view-helper для front-end, реальный расчёт через quoter
// quoter.quoteExactInputSingle() вне контракта
revert("Use Quoter contract off-chain");
}
}
Защита от манипуляций
Sandwich атака — главная угроза buyback транзакций. MEV-боты видят pending buyback в mempool, вставляют свой swap перед ним (задирая цену) и сразу после (фиксируя прибыль). Защита:
- amountOutMinimum: никогда не ставить 0. Рассчитывать через Uniswap V3 Quoter с запасом 1-2%.
- Flashbots / MEV blocker: отправлять buyback транзакции через приватный mempool (Flashbots Protect, MEV Blocker от CoW Protocol).
- Разбивка на части: вместо одного большого buyback — несколько меньших с интервалом. Снижает impact и делает предсказуемость атаки меньше.
- TWAP pricing: сравнивать цену свопа с TWAP ценой Uniswap V3 оракула. Если отклонение > N% — revert.
// Проверка через Uniswap V3 TWAP оракул
function checkPriceDeviation(uint256 amountIn, uint256 amountOut) internal view {
// Получаем TWAP за последние 30 минут
uint32[] memory secondsAgo = new uint32[](2);
secondsAgo[0] = 1800; // 30 min ago
secondsAgo[1] = 0; // now
(int56[] memory tickCumulatives,) = IUniswapV3Pool(pool)
.observe(secondsAgo);
int56 tickDelta = tickCumulatives[1] - tickCumulatives[0];
int24 twapTick = int24(tickDelta / 1800);
// Рассчитываем ожидаемый amountOut по TWAP
uint256 expectedAmountOut = getAmountFromTick(twapTick, amountIn);
// Допускаем отклонение не более 3% от TWAP
require(
amountOut >= (expectedAmountOut * 97) / 100,
"Price deviation too high"
);
}
Автоматизация и триггеры
Два подхода к запуску buyback:
Keeper-based (рекомендуется): Chainlink Automation или Gelato Network. Смарт-контракт определяет условие (checkUpkeep), keeper вызывает performUpkeep. Децентрализованно, не требует доверенного сервера.
// Совместимость с Chainlink Automation
function checkUpkeep(bytes calldata)
external
view
returns (bool upkeepNeeded, bytes memory)
{
upkeepNeeded = paymentToken.balanceOf(address(this)) >= minBuybackAmount;
}
function performUpkeep(bytes calldata) external {
require(
paymentToken.balanceOf(address(this)) >= minBuybackAmount,
"Condition not met"
);
uint256 balance = paymentToken.balanceOf(address(this));
uint256 minOut = _calculateMinOut(balance);
executeBuyback(balance, minOut);
}
Schedule-based: ежедневный/еженедельный buyback по времени. Проще для коммуникации с сообществом, но менее capital efficient.
Прозрачность и репортинг
Сообщество должно видеть каждый buyback. Рекомендуемые данные для публичного дашборда:
| Метрика | Описание |
|---|---|
| Total burned | Суммарный burn за всё время |
| Buyback frequency | Количество buyback за период |
| Avg price | Средняя цена покупки |
| Protocol revenue | Выручка, направленная на buyback |
| Burn rate | % supply уничтожен |
Все данные берутся из on-chain событий BuybackExecuted — дополнительной инфраструктуры не нужно, только индексация ивентов.







