Разработка системы buyback-and-burn

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка системы buyback-and-burn
Средняя
~2-3 рабочих дня
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1221
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1163
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    855
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1056
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    828

Разработка системы 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 — дополнительной инфраструктуры не нужно, только индексация ивентов.