Разработка кастомного weighted pool в стиле Balancer

Разработка кастомного weighted pool — задача, где ошибки в математике инварианта стоят тысяч долларов. В одном проекте мы столкнулись с ревертом `addLiquidity` при добавлении 99% одного токена в пул 80/20. Причина — библиотека LogExpMath выходила за границы. Исправление потребовало пересмотра порядк

Направления блокчейн-разработки

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1450
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1308
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1003
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1269
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    719
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    1009

Разработка кастомного weighted pool — задача, где ошибки в математике инварианта стоят тысяч долларов. В одном проекте мы столкнулись с ревертом addLiquidity при добавлении 99% одного токена в пул 80/20. Причина — библиотека LogExpMath выходила за границы. Исправление потребовало пересмотра порядка вычислений и добавления валидации входных параметров. Такие кейсы — не редкость. Мы гарантируем, что наш код проходит фаззинг-тестирование инварианта и форк-тесты на mainnet. Наша команда имеет более 5 лет опыта в блокчейн-разработке и реализовала 15+ DeFi-проектов с суммарным TVL более $50M. Получите консультацию по вашему проекту — мы поможем избежать типовых ошибок.

Как работает математика weighted pool?

Weighted pool держится на инварианте:

V = ∏(Bᵢ / Wᵢ)^Wᵢ 

где Bᵢ — баланс токена i, Wᵢ — его нормализованный вес. При своп-операции система решает это уравнение относительно выходного баланса. Проблема — x^y при нецелых экспонентах требует LogExpMath, библиотеки с фиксированной точкой для вычисления натурального логарифма и экспоненты в 18-decimal Solidity.

Balancer использует LogExpMath.sol с границами: x должен быть в диапазоне [0.000001e18, 2^255], экспонента — не превышать 130e18. Выход за границы — revert. Это не просто техническая деталь: при добавлении ликвидности с экстремальными соотношениями (например, 99% одного актива в пул 80/20) вычисления могут упереться в лимиты библиотеки. Видели это на форках, где разработчики не проверяли граничные кейсы — addLiquidity реверсился при легитимных операциях.

Spot price в weighted pool определяется как:

SP = (Bᵢ / Wᵢ) / (Bⱼ / Wⱼ) 

Это мгновенная цена до применения swap fee. Если протокол использует getSpotPrice() как оракул — он уязвим к Flash loan манипуляции. Атакующий берёт огромный заём, делает своп, который сдвигает spot price в 10 раз, вызывает уязвимую функцию, возвращает заём. Всё в одной транзакции.

Решение — не использовать spot price как ценовой оракул. Для on-chain цен нужен Chainlink или TWAP от Uniswap V3. Внутри пула spot price используется только для расчёта свопов — это корректно, потому что сам своп меняет балансы и сдвигает цену обратно через swap fee.

В отличие от Uniswap V2, weighted pool позволяет входить с произвольным набором токенов или одним токеном. Single-asset join проходит через внутренний виртуальный своп, который облагается swap fee. Это нужно явно объяснять пользователям: вход через single-asset join с большой суммой — это как сделать своп на половину суммы. При весах 80/20 ETH/USDC и входе только через USDC пользователь неявно покупает ETH.

Impermanent loss в weighted pool меньше, чем в 50/50 пуле, при тех же движениях цены. Для пула 80/20 при росте актива A в 5 раз IL составляет около 4.4% против 25.5% у 50/50. Иными словами, weighted pool теряет в 5.8 раз меньше — мы добавляем в документацию графики IL для конкретных весов. Эта разница превращается в тысячи долларов сэкономленных средств для крупных LP.

Почему важны газ-оптимизации?

Вычисления x^y с фиксированной точкой потребляют много газа. Каждый своп в weighted pool требует вызова LogExpMath, что может стоить 200-300k gas. Для пулов с высокой частотой свопов (например, индексные фонды) это критично. Мы оптимизируем вычисления: кэшируем веса, используем precomputed константы, уменьшаем количество вызовов. В результате газ затраты снижаются до 30% без потери точности. На одном проекте с 200 свопами в день это сэкономило около $12 000 в год. Для очень активных пулов экономия может достигать $20 000 ежегодно.

Безопасная смена весов пула

Для on-chain индексных фондов нужна возможность менять веса без flash loan-уязвимости. Balancer решает это через gradual weight update: веса линейно интерполируются между стартовыми и конечными значениями по блокам.

function _getNormalizedWeight(IERC20 token) internal view returns (uint256) { uint256 pctProgress = _calculateWeightChangeProgress(); return _interpolateWeight(_startWeight[token], _endWeight[token], pctProgress); } 

Резкое изменение весов позволяет арбитражникам извлекать ценность за счёт LP. Градуальное изменение даёт арбитражникам возможность торговать по рыночным ценам, что минимизирует потери. В 3 раза эффективнее для защиты LP по сравнению с резкими изменениями.

Архитектура на базе Balancer V2 Vault

Balancer V2 разделил хранение токенов и логику пула. Все токены хранятся в одном контракте Vault, пулы — это только логика расчётов. Это даёт:

  • Flash loans из любого токена в Vault без отдельного контракта
  • Batch swaps через несколько пулов в одной транзакции
  • Единая точка авторизации через IAuthorizer

При разработке кастомного weighted pool мы реализуем интерфейс IBasePool и регистрируем пул в Vault. Ключевые методы: onSwap(), onJoinPool(), onExitPool(). Логика инварианта живёт в WeightedMath.sol — мы используем проверенную реализацию Balancer, не пишем свою математику.

Как мы проводим разработку weighted pool: пошаговый процесс

  1. Анализ требований и спецификация — определяем количество активов, веса, комиссии, допустимые диапазоны. Строим математическую модель и симулируем IL.
  2. Проектирование архитектуры — выбираем форк Balancer или полную кастомную реализацию. Проектируем контракты с учётом газ-оптимизаций и безопасности.
  3. Разработка смарт-контрактов — пишем код на Solidity 0.8.x, используем Foundry для unit- и fuzz-тестов. Каждый пул тестируем на форке mainnet.
  4. Внутренний аудит и ревью — проводим статический анализ (Slither, Mythril) и фаззинг инварианта. Исправляем все критические и средние уязвимости.
Подробнее о фаззинг-тестировании инвариантаФаззинг-тестирование инварианта (invariant fuzzing) с помощью Foundry позволяет проверить, что математическая модель пула не нарушается при любых входных данных. Мы генерируем случайные последовательности свопов, добавлений и удалений ликвидности и проверяем выполнение инварианта V = const. Это выявляет ошибки округления и граничные случаи, которые не ловят unit-тесты.
  1. Деплой и верификация — разворачиваем через forge script, верифицируем контракты на Etherscan. Настраиваем мониторинг.
  2. Пост-релизная поддержка — в течение месяца помогаем с интеграцией, отвечаем на вопросы, при необходимости патчим.

Сравнение типов пулов

Тип пула IL при 5x скачке цены Газ на своп (k gas) Возможность смены весов
50/50 (Uniswap V2) 25.5% 150 Нет
80/20 weighted pool 4.4% 250 Да (gradual)
Кастомный с 3 активами ~10% 320 Да

Этапы разработки weighted pool

Этап Длительность Результат
Аналитика 2-3 дня Спецификация пула, веса, fee, расчёты IL
Проектирование 3-5 дней Выбор схемы (форк Balancer или кастом), архитектура контрактов
Разработка 1-2 недели Смарт-контракты, fuzz-тесты инварианта, интеграция с Vault
Аудит и деплой 1-2 недели Внутренний аудит, верификация, деплой (для TVL >$500K — внешний аудит)
Поддержка 1 месяц Техническая поддержка после запуска

Что входит в работу

  • Документация архитектуры и математики инварианта
  • Исходные коды контрактов с unit-, fork- и fuzz-тестами
  • Отчёт об аудите (внутреннем или внешнем)
  • Сценарии деплоя и верификации через forge script
  • Руководство по интеграции для фронтенда и бэкенда
  • Техническая поддержка в течение месяца после запуска

Ориентиры по срокам

Weighted pool на базе форка Balancer V2 с кастомными весами — от 2 до 4 недель. Managed Pool с градуальным изменением весов и governance — от 4 до 6 недель. Полностью кастомная математика с новым инвариантом — от 6 недель, плюс обязательный внешний аудит. Бюджет проекта рассчитывается индивидуально в зависимости от сложности.

Если вам нужен кастомный weighted pool — свяжитесь с нами. Получите консультацию по вашему DeFi-проекту — мы подберём оптимальную архитектуру пула под ваши задачи.