Разработка контрактов стейкинга
Стейкинг-контракт — один из базовых DeFi примитивов. Пользователь депонирует токены, получает вознаграждение со временем, может изъять. Звучит просто — и именно поэтому большинство реализаций содержат баги. Правильный reward calculation механизм нетривиален, и ошибки здесь стоят денег.
Reward Distribution: алгоритм accumulated reward per token
Наивная реализация перебирает всех стейкеров и обновляет их балансы — это O(n) по газу и убивает контракт при большом числе пользователей.
Стандартный алгоритм: accumulated reward per token. Глобальная переменная rewardPerTokenStored накапливает вознаграждение на 1 токен с момента деплоя. При каждом deposit/withdraw она обновляется. Индивидуальный reward вычисляется как (rewardPerToken - userCheckpoint) × userBalance.
uint256 public rewardPerTokenStored;
uint256 public lastUpdateTime;
mapping(address => uint256) public userRewardPerTokenPaid;
mapping(address => uint256) public rewards;
function rewardPerToken() public view returns (uint256) {
if (totalSupply == 0) return rewardPerTokenStored;
return rewardPerTokenStored +
(block.timestamp - lastUpdateTime) * rewardRate * 1e18 / totalSupply;
}
function earned(address account) public view returns (uint256) {
return balanceOf[account] *
(rewardPerToken() - userRewardPerTokenPaid[account]) / 1e18
+ rewards[account];
}
Это O(1) — газ не зависит от числа пользователей. Именно так работает Synthetix StakingRewards, ставший референсной реализацией.
Основные механики стейкинга
Lock period: токены заблокированы на N дней после депозита. Снижает sell pressure. Требует хранить depositTime и проверять при withdraw.
Unstaking cooldown: после инициации вывода — ожидание 7-28 дней. Популярно в PoS протоколах (имитирует unbonding period).
Early withdrawal penalty: при выводе до окончания lock period — штраф (например, 10% от суммы). Штраф идёт в reward pool или сжигается.
Multiplier по времени: чем дольше стейкинг — тем выше reward rate. Реализуется через tiered multipliers или linear vesting multiplier.
Безопасность
Reentrancy: при выплате rewards через transfer → внешний вызов → функция контракта снова. CEI pattern (Checks-Effects-Interactions): сначала обновить состояние, потом делать transfer.
Precision loss: деление в Solidity округляет вниз. При малых суммах или большом totalSupply точность может быть потеряна. Используют scaling factor 1e18 (или 1e27 для extra precision).
Reward token != staking token: если reward и staking токен одинаковый — totalSupply включает reward токены в пуле, что ломает расчёт rewardPerToken. Нужно аккуратно считать только «застейканные» токены.
Admin keys: кто может менять rewardRate? Если это EOA — единая точка отказа. Timelock + multisig — стандарт для production контрактов.
Контракты стейкинга перед деплоем обязательно проходят audit — они хранят средства пользователей и являются частой мишенью для эксплойтов.







