
«РБК-Крипто» не дает инвестиционных советов, материал опубликован исключительно в ознакомительных целях. Криптовалюта — это волатильный актив, который может привести к финансовым убыткам.
В сети биткоин делимость задана самим протоколом: 1 биткоин равен 100 млн сатоши. У токенов эфириум масштаб выбирает контракт. Поэтому запись 1 000 000 в двух разных токенах может означать совершенно разные суммы. Разбираемся, что это значит и как работает.
Откуда берется запятая
Стандарт ERC-20 определяет функцию decimals(количество знаков после запятой или точность токена). Если она возвращает 6 знаков, кошелек показывает 1 500 000 базовых единиц как 1,5 токена. При 18 знаках те же 1,5 токена записываются уже как 1 500 000 000 000 000 000.
Единого значения нет. Более того, decimals относится к необязательным функциям ERC-20. Библиотека OpenZeppelin использует 18 знаков по умолчанию, но разработчик может задать другое значение.
У USDC шесть знаков после запятой, у WBTC — восемь, у DAI — 18. Один токен для этих контрактов соответствует соответственно 10 в шестой, восьмой и 18-ой степени соответственно.
Для пользователя эта разница обычно незаметна. Кошелек сам превращает, например, 12 500 000 единиц USDC в 12,5 USDC. Но если интерфейс неверно определит decimals, он может показать неправильный баланс или подготовить транзакцию на сумму, которую пользователь не собирался отправлять.
Ошибка на двенадцать порядков
Считать 18 знаков универсальным значением опасно. Для 1 USDC такой код подставит 10 в 18-ой степени базовых единиц вместо 10 в шестой степени. Разница составляет 10 в 12-ой степени или 1 000 000 000 000.
Именно такую проблему OpenZeppelin описала в 2025 году после аудита Across Protocol. Один из контрактов рассчитывал сумму токена для оплаты газа, исходя из 18 знаков. Для USDC с шестью знаками результат мог оказаться завышен в триллион раз.
Другой источник ошибок — соединение систем с разной точностью. В аудите платформы Wenia в апреле 2026 года OpenZeppelin отдельно указала на несовпадение шестизначного формата токена и восьмизначной точности, которую используют многие долларовые ценовые потоки Chainlink. Без приведения значений к одному масштабу проверка резервов работала бы неправильно.
Похожая проблема возникает на биржах и в обменных протоколах. Если один актив имеет 6 знаков, а второй 18, перед расчетом цены нужно учесть разницу в 10 в 12-ой степени. Иначе неверным будет не только отображение котировки, но и размер сделки, залога или ликвидации.
Где появляется округление
Даже правильный decimals не гарантирует точный результат, если приложение переводит базовые единицы в обычные числа с плавающей запятой.
В JavaScript каждое целое число гарантированно представляется точно только до 9 007 199 254 740 991. Для токена с 18 знаками эта граница соответствует примерно 0,009 токена. Выше нее некоторые значения по-прежнему представимы точно, но уже не каждое соседнее целое число.
Поэтому система проводит ряд преобразовакний, а в расчетах остается целое число. Округление есть и внутри смарт-контрактов. При делении целых чисел Solidity отбрасывает дробную часть. Если переменные равны 5 и 2, результатом будет 2.
Для обычного перевода потеря одной минимальной единицы почти незаметна. В кредитных протоколах и токенизированных хранилищах такие операции повторяются постоянно: при начислении процентов, выпуске долей и выводе средств.
Что в итоге видит пользователь
Количество знаков после запятой не связано с ценой токена. Один миллион базовых единиц — это 1 USDC, 0,01 WBTC или 0,000000000001 DAI.
Иногда из-за округления интерфейс показывает 0,00 токена, хотя ненулевой остаток все еще находится на адресе. Например, четыре базовые единицы USDC равны 0,000004 USDC. При отображении только двух знаков кошелек покажет ноль, хотя контракт продолжит учитывать этот баланс.
Поэтому при странном балансе или подозрительной сумме транзакции полезно проверить не только тикер, но и адрес контракта и его decimals. Для сервисов правило еще жестче: расчеты нужно вести в целых базовых единицах, а перевод в привычную десятичную запись оставлять интерфейсу.