Owlio
RU
← Блог
ИнструкцияДля новичка

Десятичные знаки ERC-20: как превратить сырой баланс в количество токенов

Большое целое число из контракта может означать небольшое количество токенов. Перед сравнением балансов проверьте единицы.

Чтобы получить понятное количество токенов из сырого баланса ERC-20, разделите целое число на 10 в степени проверенного decimals токена. Делайте это только для значения в сырых базовых единицах. Кошелёк или обозреватель уже мог выполнить преобразование.

Например, сырой баланс 1234567 при 6 десятичных знаках означает 1.234567 токена. То же целое число при 18 десятичных знаках означает 0.000000000001234567 токена. Ни один результат не сообщает стоимость в долларах. Это условные арифметические примеры, а не балансы, полученные из кошелька.

Что меняет decimals при чтении баланса

Метод balanceOf контракта ERC-20 возвращает целое число. Спецификация ERC-20 описывает decimals как масштаб для представления количества токенов пользователю. Представьте целое число как число мельчайших учётных единиц токена, а decimals как указание интерфейсу, где поставить десятичную точку.

Расчёт такой:

Понятное количество токенов = сырое целое число, делённое на (10 в степени decimals).

В этой статье все сырые целые числа записаны в десятичной системе, без разделителей тысяч. Шестнадцатеричное значение, начинающееся с 0x, сначала нужно преобразовать в целое число. Буквы и цифры такой записи не являются десятичным количеством токенов, которое можно без изменений подставить в это деление.

Вот одно условное целое число при трёх разных масштабах:

Сырое целое число Decimals Количество токенов
1234567 6 1.234567
1234567 18 0.000000000001234567
1234567 0 1234567

При 0 десятичных знаков делитель равен 1. При 6 один целый токен соответствует 1000000 сырых единиц. При 18 он соответствует 1000000000000000000 сырых единиц. Сам размер целого числа не показывает, какой масштаб нужен.

Установите масштаб перед расчётом

Начните с сети и полного адреса контракта токена. Символ является подписью, а не уникальным идентификатором. Если вы не уверены, какой адрес принадлежит токену, а какой держателю, сначала прочитайте руководство об адресе кошелька и контракте токена.

Установите контракт по официальной информации проекта о развёртывании в этой сети. Затем прочитайте его decimals через надёжный обозреватель или инструмент чтения контракта, без внесения изменений. Сохраните результат вместе с контрактом и сетью. Метаданные другого развёртывания не устанавливают масштаб для вашего актива.

Не подставляйте 18 вместо отсутствующего decimals. В ERC-20 этот метод необязателен. Справочник ERC20 от OpenZeppelin описывает значение 18 по умолчанию в своей реализации, которое можно переопределить. Значение по умолчанию одной реализации не является правилом для всех токенов. Тот же справочник поясняет: decimals служит для отображения и не меняет целочисленную арифметику балансов и переводов в контракте.

Если чтение не удалось, отличайте недоступный источник от контракта, который не предоставляет пригодные метаданные. Попробуйте надёжный источник для того же развёртывания или проверьте документацию реализации. Если масштаб так и не установлен, сохраните сырое целое число и пометьте понятное количество как неустановленное. Правдоподобное число ещё не означает проверенное преобразование.

Проверьте, не отформатировано ли число

Перед формулой прочитайте подпись поля и документацию источника. Сырой результат контракта, нормализованное количество из API и округлённое значение кошелька могут по-разному описывать один актив. Десятичная точка указывает на форматирование, но её отсутствие не доказывает, что значение сырое: готовое количество может равняться ровно 2 токенам.

Для условного токена с 6 десятичными знаками сырое 2500000 превращается в 2.5 токена. Если кошелёк уже показывает 2.5 токена, деление показанного числа на 1000000 даст 0.0000025, то есть ошибочное повторное преобразование.

Получив точное количество токенов, отдельно применяйте округление для экрана. Сырое 1 при 6 десятичных знаках означает 0.000001 токена. Интерфейс с 4 знаками после точки может показать 0.0000. Эта округлённая подпись не доказывает пустой баланс. При разборе расхождения сохраняйте точный результат, не придумывая дополнительные значащие цифры сверх точности источника.

В скрипте или таблице сохраняйте сырое целое число как текст или точное целое до форматирования. Большие целые могут терять точность в обычном JavaScript Number, как объясняет справочник MDN о безопасных целых. Деление не вернёт уже потерянную точность. Документация ethers v6 предлагает formatUnits, возвращающий десятичную строку. Явно передавайте проверенное decimals и сохраняйте эту строку, не превращая её ради удобства в неточное число.

Сверьте два показания без перемещения токенов

Проверяйте один актив на одном адресе. Для чтения публичных данных контракта не нужны перевод, разрешение, фраза восстановления или подпись кошелька.

  1. Зафиксируйте идентификаторы. Запишите сеть, публичный адрес держателя и проверенный контракт токена. Не подставляйте адрес контракта вместо держателя при чтении его баланса.
  2. Зафиксируйте наблюдение. Сохраните время и номер блока, если он доступен. Предпочтительны показания одного блока. Иначе перевод между наблюдениями может помешать точному совпадению.
  3. Подпишите входные данные. Сохраните исходное значение, отметку о сырых или готовых единицах и подтверждение decimals контракта. Если источник не объясняет единицы, остановите преобразование.
  4. Измените масштаб один раз. Преобразуйте сырое целое число с этим decimals, сохраняя точные цифры до округления для экрана. Количество, уже данное в токенах, оставьте как есть.
  5. Сравнивайте одинаковые единицы. Сопоставьте это количество токенов с количеством на другом экране при совместимой точности. Для округлённого нуля запросите подробности, прежде чем считать сырой баланс нулевым.
  6. Разберите оставшееся расхождение. Если идентификаторы, момент наблюдения и единицы совпадают, а количества различаются, запишите оба показания и источники. При сбое источника пометьте чтение недоступным, а не подставляйте ноль. Руководство по расхождениям портфеля разбирает отсутствующие ответы источников, цены и охват позиций.

Полезный результат представляет собой запись, которую другой человек может воспроизвести: какой контракт, чей баланс, какое наблюдение, какое сырое значение, какой decimals и какое преобразованное количество. Транзакция не нужна для доказательства преобразования.

Отделяйте количество токенов от стоимости

Форматирование даёт количество этого токена. Для оценки в долларах дополнительно нужна цена именно этого актива в указанной валюте на указанное время. Decimals не устанавливает эту цену, торговую ликвидность или безопасность контракта. Незнакомый токен может вернуть вполне обычный decimals.

Токен-квитанция или обёрнутый токен добавляет ещё один вопрос: сколько базового актива представляет каждый токен? Преобразование сырого баланса даёт количество токенов-квитанций или обёрнутых токенов. Эквивалент в базовом активе требует метода преобразования и единиц соответствующего протокола. Decimals токена не заменяет этот обменный курс, а коэффициент протокола, например коэффициент здоровья, требует собственного документированного масштаба.

Если число всё ещё кажется неверным, сохраняйте существенную неопределённость. Неизвестный decimals оставляет понятное количество неустановленным. Известное количество при неизвестной цене оставляет стоимость неустановленной. Явно обозначенные пробелы дают полезную следующую проверку без изменения актива, который вы пытаетесь понять.

Частые вопросы

У всех токенов ERC-20 18 десятичных знаков?

Нет. Реализация ERC20 от OpenZeppelin по умолчанию использует 18, но стандарт ERC-20 этого не требует. Метод decimals необязателен. Перед преобразованием сырого баланса установите decimals для конкретного контракта и сети.

Нужно ли делить количество из кошелька с учётом decimals?

Масштабирование нужно только значению, которое документировано как сырые базовые единицы. Кошелёк уже может показывать понятное количество токенов. Повторное деление готового количества даст ошибку. Сначала установите единицы поля, которое читаете.

Означает ли ноль на экране, что баланс токена пуст?

Нет. Интерфейс может округлить небольшое положительное количество до нуля. Проверьте более точное количество или сырой баланс с проверенным decimals. Успешно прочитанный нулевой сырой баланс и недоступное чтение являются разными результатами.