Представьте: ваш смарт-контракт перестаёт работать при 1000 холдеров, каждая транзакция исчерпывает лимит газа — это реальность наивных реализаций reflection. Не так давно клиент пришёл с контрактом, где excluded массив достиг 500 адресов: любая операция вылетала за gas limit. Мы за 5+ лет в блокчейн-разработке реализовали десятки токенов с алгоритмом O(1), который работает при любом числе держателей. Разрабатываем такие токены под ключ, включая аудит и оптимизацию газа. Разберём механику, типичные ошибки и меры защиты. Получите консультацию инженера по вашему проекту.
Как reflection-токен экономит газ?
Механизм основан на двух видах балансов: rBalance (reflection balance) и tBalance (token balance). Держатели хранят rBalance, который автоматически растёт при каждой транзакции. Вместо перераспределения токенов контракт меняет курс конвертации rBalance → tBalance за счёт уменьшения rTotal на сумму комиссии. Это увеличивает rate = rTotal / tTotal для всех остальных. Подробнее — в Solidity (Solidity).
Полный листинг контракта ReflectionToken
```solidity contract ReflectionToken is IERC20, Ownable { uint256 private constant MAX = ~uint256(0);uint256 private _tTotal;
uint256 private _rTotal;
uint256 private _tFeeTotal;
uint256 public taxFee = 5;
uint256 public liquidityFee = 3;
uint256 public burnFee = 2;
mapping(address => uint256) private _rOwned;
mapping(address => uint256) private _tOwned;
mapping(address => bool) private _isExcluded;
constructor(uint256 totalSupply) {
_tTotal = totalSupply * 10**18;
_rTotal = (MAX - (MAX % _tTotal));
_rOwned[msg.sender] = _rTotal;
}
function _getRate() private view returns (uint256) {
(uint256 rSupply, uint256 tSupply) = _getCurrentSupply();
return rSupply / tSupply;
}
function _getCurrentSupply() private view returns (uint256, uint256) {
uint256 rSupply = _rTotal;
uint256 tSupply = _tTotal;
for (uint256 i = 0; i < _excluded.length; i++) {
if (_rOwned[_excluded[i]] > rSupply || _tOwned[_excluded[i]] > tSupply)
return (_rTotal, _tTotal);
rSupply -= _rOwned[_excluded[i]];
tSupply -= _tOwned[_excluded[i]];
}
if (rSupply < _rTotal / _tTotal) return (_rTotal, _tTotal);
return (rSupply, tSupply);
}
function balanceOf(address account) public view returns (uint256) {
if (_isExcluded[account]) return _tOwned[account];
return tokenFromReflection(_rOwned[account]);
}
function tokenFromReflection(uint256 rAmount) public view returns (uint256) {
require(rAmount <= _rTotal, "Amount too large");
return rAmount / _getRate();
}
function _transferStandard(address sender, address recipient, uint256 tAmount) private {
(uint256 rAmount, uint256 rTransferAmount, uint256 rFee,
uint256 tTransferAmount, uint256 tFee, uint256 tLiquidity, uint256 tBurn)
= _getValues(tAmount);
_rOwned[sender] -= rAmount;
_rOwned[recipient] += rTransferAmount;
_reflectFee(rFee, tFee);
_takeLiquidity(tLiquidity);
_burn(sender, tBurn);
emit Transfer(sender, recipient, tTransferAmount);
}
function _reflectFee(uint256 rFee, uint256 tFee) private {
_rTotal -= rFee;
_tFeeTotal += tFee;
}
}
</details>
Наивный перебор всех держателей потребляет в 50 раз больше газа, чем O(1) reflection. При 10 000 холдеров одна транзакция может стоить 5 млн газа, в то время как O(1) — всего 100 тыс. O(1) реализация эффективнее наивного перебора по газу, что подтверждает таблица ниже.
### Почему excluded адреса пулов критичны?
Адреса пулов ликвидности (Uniswap pair, PancakeSwap pair) должны быть excluded от reflection. Если пул участвует в reflection, его баланс токена постоянно растёт, нарушая соотношение token/ETH в пуле и создавая арбитражные возможности. Это классическая ошибка в ранних reflection-токенах. Включаем этот пункт в каждый чек-лист аудита.
```solidity
function excludeFromReward(address account) public onlyOwner {
require(!_isExcluded[account], "Already excluded");
if (_rOwned[account] > 0) {
_tOwned[account] = tokenFromReflection(_rOwned[account]);
}
_isExcluded[account] = true;
_excluded.push(account);
}
Сравнение O(1) и наивной реализации: во сколько раз лучше?
| Параметр | Наивная реализация (перебор) | O(1) через reflection |
|---|---|---|
| Сложность транзакции | O(N) | O(1) |
| Газ при 10 000 холдеров | ~5 000 000 gas | ~100 000 gas |
| Масштабируемость | Падает при >500 холдеров | Не ограничена |
| Риск выхода из gas limit | Высокий | Отсутствует |
O(1) реализация потребляет в 50 раз меньше газа и не зависит от числа держателей. Экономия на комиссиях за транзакции достигает 90%. Закажите разработку reflection-токена — подготовим детальный план за 7–14 дней.
Как протестировать reflection-токен перед деплоем?
Используем статический анализ с Slither для выявления уязвимостей в коде, символическое выполнение Mythril для поиска путей с ошибками, и fuzzing с Echidna для проверки корректности распределения при случайных параметрах. Также запускаем интеграционные тесты на mainnet-fork, чтобы проверить газовые лимиты и корректность excluded адресов.
Уязвимости в reflection-токенах и их предотвращение
- Итерация по excluded: функция
_getCurrentSupply()итерируется по массиву excluded. Если массив большой — выход из gas limit. Ограничиваем длину массива и разрешаем добавление только owner. - Precision loss: при огромном числе транзакций
_rTotalможет стать слишком малым,_getRate()вернёт 0. ИнвариантrTotal > tTotal * minRateпроверяется в тестах. - Anti-whale меры: добавляем
maxTransactionAmount(1% от supply) иmaxWalletToken(2%).
uint256 public maxTxAmount = _tTotal / 100;
uint256 public maxWalletToken = _tTotal / 50;
function _transfer(address from, address to, uint256 amount) internal {
require(amount <= maxTxAmount, "Exceeds max tx");
if (!_isExcluded[to]) {
require(balanceOf(to) + amount <= maxWalletToken, "Exceeds max wallet");
}
// ...
}
Типовые комиссии и их назначение
| Тип комиссии | Налог (типичный) | Назначение |
|---|---|---|
| Reflection | 2–5% | Вознаграждение держателей |
| Liquidity | 2–3% | Автоматическое пополнение пула |
| Burn | 0–2% | Дефляция предложения |
Суммарная комиссия не должна превышать 8%, иначе токен становится экономически дисфункциональным.
Как реализовать reflection-токен за 5 этапов?
- Аналитика и проектирование: спецификация механик (tax, liquidity, burn, anti-whale).
- Разработка контракта на Solidity 0.8.x с использованием Foundry или Hardhat.
- Тестирование: unit-тесты, fuzzing с Echidna, интеграционные тесты в mainnet-fork для проверки корректности распределения и газовых лимитов.
- Аудит: статический анализ Slither + символическое выполнение Mythril по чек-листу из 30+ пунктов.
- Документация и поддержка при деплое: помощь с выбором пула ликвидности и настройкой excluded.
Что входит в разработку reflection-токена под ключ
- Спецификация механик (tax, liquidity, burn, anti-whale) с обоснованием параметров.
- Исходный код контракта на Solidity 0.8.x с комментариями.
- Набор unit-тестов и тестов на форке mainnet.
- Отчёт аудита с разбором уязвимостей (Slither, Mythril, Echidna).
- Инструкция по деплою и настройке excluded адресов пулов.
- Поддержка в течение 1 месяца после деплоя.
Auto-liquidity механизм: зачем он нужен?
Накопленная liquidityFee периодически конвертируется в LP-токены через DEX. Флаг inSwapAndLiquify предотвращает рекурсивный вызов. Механизм поддерживает ликвидность без участия команды, автоматически добавляя пары на децентрализованные биржи.
Мы гарантируем, что контракт пройдёт проверку на известные уязвимости (reentrancy, flash loan атаки, precision loss). Получите консультацию инженера по вашему проекту. Свяжитесь с нами для оценки.







