Розробка системи 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 для swap: 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);
// Сжигаємо куплені токени
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: порівнювати ціну swap з 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 хвилин назад
secondsAgo[1] = 0; // зараз
(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 | % пропозиції знищено |
Усі дані беруться з on-chain подій BuybackExecuted — додаткової інфраструктури не потрібно, тільки індексація подій.







