Разработка системы fee distribution для протокола
Uniswap V3 генерирует миллионы долларов комиссий ежедневно. До включения fee switch весь этот поток шёл LP-провайдерам — держатели UNI получали ноль. Когда governance проголосовал за перенаправление части fees на treasury, потребовалась система сбора, аккумуляции и распределения. Это типичная задача — протокол начинает монетизироваться, и нужен механизм, который честно делит доходы между стейкерами/держателями токена.
Два паттерна распределения: push vs pull
Push distribution — рассылка всем
Контракт накапливает fees и периодически вызывает distribute(), которая пробегает по списку стейкеров и переводит каждому долю. Просто в понимании, сложно в реализации: unbounded loop — классический gas griefing вектор. При 10 000 стейкерах транзакция превысит block gas limit.
Допустимо только для систем с явным cap на количество участников и batch обработкой (pagination). В большинстве случаев — неправильный выбор.
Pull distribution — пользователь сам забирает
Контракт ведёт rewardPerTokenStored — накопленный reward на единицу стейка с момента запуска. При каждом deposit/withdraw/claim обновляет userRewardPerTokenPaid для конкретного пользователя. Награда = (rewardPerTokenStored - userRewardPerTokenPaid) * balance.
Это математика из Synthetix StakingRewards контракта — одного из самых скопированных паттернов в DeFi. Ключевое свойство: Gas-complexity O(1) для claim, не зависит от количества стейкеров.
function earned(address account) public view returns (uint256) {
return (
(balanceOf[account] * (rewardPerToken() - userRewardPerTokenPaid[account])) / 1e18
) + rewards[account];
}
Этот паттерн мы используем как базу для большинства fee distribution систем.
Сбор fees и конвертация
Protocols генерируют fees в разных токенах — swap fees в торгуемых токенах, lending fees в debt-токенах. Прежде чем распределить стейкерам, нужно конвертировать в один target token (обычно protocol token или USDC).
FeeCollector контракт — агрегирует fees со всех source контрактов. Периодически вызывается keeper (Chainlink Automation, Gelato) или любым пользователем.
Конвертация через DEX — swap accumulated fees в target token через Uniswap V3. Важно: конвертация большого объёма за раз создаёт price impact и MEV-возможности. Решение: конвертировать малыми частями через TWAP-ориентированные свопы или использовать Cow Protocol для MEV-защищённых свопов.
Распределение в нескольких токенах — иногда правильнее не конвертировать, а распределять в оригинальных fee-токенах. Curve распределяет 3CRV LP-токены (корзина стейблкоинов) вместо конвертации. Это дороже в реализации (multi-reward staking), но сохраняет ценность без slippage.
Многоканальное распределение
Редко весь fee идёт только стейкерам. Типичная схема:
| Получатель | Доля | Механизм |
|---|---|---|
| Стейкеры токена | 40-60% | Pull-distribution, rewardPerToken |
| Treasury | 20-30% | Прямой перевод на multisig |
| Insurance fund | 10-20% | Накопление для покрытия bad debt |
| Burn | 5-10% | token.burn() |
Пропорции задаются через governance-управляемые параметры с timelock. FeeDistributor контракт читает актуальные пропорции при каждом вызове distribute().
veToken модель (vote-escrowed)
Curve ввела модель, где для получения fees нужно залочить CRV на срок до 4 лет. Чем дольше lock — тем больше veCRV, тем больше доля fees. Это выравнивает интересы: долгосрочные держатели получают больше. Реализация сложнее базового staking — нужен decay расчёт voting power, периодические checkpoints, интеграция с gauge voting.
Если нужна veToken механика — это отдельный scope работ поверх базового fee distribution.
Процесс работы и ориентиры по срокам
Проектирование (2-3 дня). Определяем source контракты, target token, пропорции распределения, keeper механизм для периодической конвертации.
Разработка (5-8 дней). FeeCollector + FeeDistributor + Staking контракт. Тесты с Foundry: корректность расчёта earned() при изменении total supply, корректная обработка deposit/withdraw в том же блоке что distribute().
Интеграционные тесты. Fork-тест с реальным Uniswap V3 pool для проверки конвертации fees. Fuzz-тесты на математику распределения — edge cases при очень маленьких или очень больших балансах.
Базовая система (pull-distribution, один reward token, periodic collect) — 1 неделя. С конвертацией через DEX и multi-reward — 1.5-2 недели. veToken механика — дополнительные 2-3 недели.







