Разработка системы стейкинга токенов с доходностью
Стейкинг с доходностью — один из базовых строительных блоков DeFi. Реализаций много: от простого «lock tokens, get more tokens» до сложных систем с veToken моделью, gauge voting и bribe markets (Curve, Convex, Balancer). Выбор архитектуры зависит от цели: удержание холдеров, governance, liquidity incentivization.
Разберём две наиболее используемые модели — MasterChef-style и ve-модель — и поговорим о том, где каждая из них проигрывает.
MasterChef-стиль: базовая архитектура
Оригинальный SushiSwap MasterChef до сих пор форкается сотнями проектов. Суть: один контракт управляет несколькими пулами, каждый пул получает долю от общей эмиссии токена пропорционально allocPoint.
Математика accRewardPerShare
Ключевая инварианта: pending(user) = user.amount * accRewardPerShare / PRECISION - user.rewardDebt.
accRewardPerShare монотонно возрастает с каждым новым блоком (или секундой). При deposit/withdraw пользователь обновляет rewardDebt, «обнуляя» текущий пендинг (который сначала ему выплачивается).
function _updatePool(uint256 pid) internal {
PoolInfo storage pool = poolInfo[pid];
if (block.timestamp <= pool.lastRewardTime) return;
uint256 elapsed = block.timestamp - pool.lastRewardTime;
uint256 reward = elapsed * rewardPerSecond * pool.allocPoint / totalAllocPoint;
// mint reward tokens (или transfer из reward wallet)
rewardToken.mint(address(this), reward);
pool.accRewardPerShare += reward * 1e18 / pool.totalStaked;
pool.lastRewardTime = block.timestamp;
}
Проблема MasterChef: если наград нет (rewardPerSecond = 0 или бюджет исчерпан) — пользователи уходят. Модель полностью зависит от постоянной эмиссии, что dilute-ит токен бесконечно. APY падает по мере роста TVL, что создаёт нестабильный flywheel.
Reward в нескольких токенах
Мульти-reward стейкинг — каждый пул начисляет несколько типов наград одновременно. Референс: Synthetix StakingRewards (audited, widely forked).
// Несколько rewarders для одного пула
mapping(address => RewardInfo) public rewardInfo; // rewardToken -> RewardInfo
struct RewardInfo {
uint256 rewardRate; // reward per second
uint256 lastUpdateTime;
uint256 rewardPerTokenStored;
mapping(address => uint256) userRewardPerTokenPaid;
mapping(address => uint256) rewards;
}
Важно: при добавлении нового reward-токена после запуска — retroactive начисления для уже существующих стейкеров происходить не должны. Новый rewardPerTokenStored стартует с текущего момента.
veToken модель: долгосрочный стейкинг
Curve Finance ввела veCRV — vote-escrowed CRV. Идея: ты lock CRV на срок от 1 недели до 4 лет, получаешь veCRV пропорционально сумме и сроку. veCRV: не трансферабелен, постепенно decay к нулю по мере истечения срока блокировки.
Это меняет incentive: чтобы сохранить влияние, нужно регулярно продлевать lock. Большие держатели, заинтересованные в долгосрочном управлении, держат максимальный lock.
Реализация ve-механики
struct LockedBalance {
int128 amount;
uint256 end; // timestamp конца блокировки (округлён до недели)
}
function create_lock(uint256 value, uint256 unlock_time) external nonReentrant {
LockedBalance memory locked = _locked[msg.sender];
require(locked.amount == 0, "Withdraw old tokens first");
uint256 rounded_unlock = (unlock_time / WEEK) * WEEK; // округление до недели
require(rounded_unlock >= block.timestamp + WEEK, "Lock too short");
require(rounded_unlock <= block.timestamp + MAXTIME, "Lock too long");
_deposit_for(msg.sender, value, rounded_unlock, locked, CREATE_LOCK_TYPE);
}
Voting power линейно убывает: при создании lock на 4 года — voting power максимальна, каждую неделю уменьшается. Это требует checkpoint-механизма для хранения истории (Curve хранит точки на каждую неделю в point_history).
Сложность реализации ve-модели: честная и газово-эффективная реализация — это ~500-800 строк Vyper/Solidity с продуманным checkpoint алгоритмом. Использование готовой референсной реализации Curve (MIT лицензия) с адаптацией — предпочтительнее написания с нуля.
Gauge voting и бриб-маркет
Поверх ve-стейкинга строится gauge system: держатели veToken голосуют за распределение эмиссии между разными пулами. Пул, получивший больше голосов — получает больше наград.
Это создаёт bribe market: проекты, желающие направить ликвидность в свой пул, платят veToken-держателям за голоса. Votium (для Curve), Hidden Hand (для Balancer/Aura) — готовые bribe-платформы. Интеграция своего gauge с этими платформами — стандартная практика для новых протоколов.
Сравнение моделей
| Характеристика | MasterChef | veToken |
|---|---|---|
| Сложность реализации | Низкая | Высокая |
| Долгосрочное удержание | Слабое | Сильное |
| Governance influence | Нет | Встроен |
| Gas cost клейма | Низкий | Средний |
| Риск инфляции | Высокий | Контролируемый |
| Time-to-market | 1-2 недели | 4-8 недель |
Безопасность: типовые уязвимости
Reentrancy при claim. Если reward-токен имеет ERC-777 хук или токен с callback — злоумышленник может рекурсивно вызвать claim, получая многократные награды до обновления rewardDebt. Защита: nonReentrant модификатор + CEI паттерн (effects перед interactions).
Flash loan манипуляция. Атакующий берёт flash loan, делает огромный deposit, wait одного блока (если reward per block), клеймит, выводит. При reward per second — даже одного блока достаточно. Защита: минимальный lock период или reward только за целые эпохи (epoch-based snapshots).
Oracle manipulation для reward в USD. Если контракт вычисляет reward в долларах через on-chain oracle (Chainlink) — манипуляция ценой токена может изменить reward rate. Лучше хранить reward rate в token units, не USD.
Экономика стейкинга
APY = (годовая эмиссия наград / TVL) × 100%. При TVL = $1M и эмиссии $100K/год → APY = 10%.
Ошибка: запускать с высоким APY (300-1000%) для привлечения TVL, а потом снижать. Это создаёт mercenary capital: TVL уходит вместе со снижением APY. Лучше: умеренный стабильный APY (20-50%) с долгосрочным vesting наград, что снижает sell pressure.
Для реальной устойчивости reward должны иметь non-dilutive источник: комиссии протокола (как в Uniswap v3 fee switch), revenue sharing, а не чистая эмиссия.
Процесс и сроки
MasterChef с мульти-наградами и frontend — 3-4 недели разработки + 2 недели аудита. veToken система с gauge voting — 6-10 недель разработки, обязательный аудит от 3-4 недель. Фундаментальная рекомендация: для veToken — fork референсного Curve VotingEscrow с модификациями, а не написание с нуля.







