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







