Перейти к содержанию

Ценовой оракул: decimals и целочисленные расчёты

Ответ feed определён как цена BTC в USD с указанным масштабом. Теперь подготовим отдельное расширение библиотеки: учебное предложение с ценой 18 USD, которое фиксирует требуемую сумму в сатоши. Исходный счёт серии на 30 000 сатоши остаётся прежним; новые правила относятся только к этому явно введённому варианту предложения.

Результат урока — целочисленная формула, правило округления и сохранённые основания расчёта. Значения условные, чтение feed и выполнение программы отсутствуют. Это арифметическое объяснение, а не предложение торговли или утверждение о сегодняшней цене.

Сначала назвать единицы

Цена библиотеки равна 1 800 центов. BTC/USD-feed имеет восемь десятичных знаков и условный answer 6 000 000 000 000. BTC содержит 100 000 000 сатоши. Все три масштаба нужны одновременно: cents, единицы ответа и единицы актива.

Формула для сатоши получается из размерностей. Цена в центах переводится в USD; answer делится на масштаб feed и даёт USD за BTC; полученная доля BTC переводится в сатоши. Вместо последовательных десятичных делений можно составить одну целочисленную дробь. Это помогает сохранить точность до принятия решения об округлении.

numerator = usdCents × 10^feedDecimals × 10^8
 denominator = 100 × btcUsdAnswer
sats = numerator / denominator по выбранному правилу

В нашем первом примере дробь имеет точный результат 30 000 сатоши. Такой удачный вход не доказывает, что округление вообще не требуется. Следующий допустимый ответ может дать дробную минимальную единицу, которую невозможно отправить как часть сатоши.

Направление пары

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

Для общего интерфейса называем переменные конкретно: btcUsdAnswer, usdCents, sats. Не используем одно поле price для суммы заказа, котировки и итоговой оплаты. Такие значения похожи внешне, но имеют разные единицы и владельцев. Ошибка размерности способна изменить результат на много порядков, не вызывая технического исключения.

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

Правило округления

Пусть условная котировка теперь равна 70 000 USD за BTC. Те же 18 USD соответствуют дроби 25 714 и ещё части сатоши. Округление вниз даст 25 714, вверх — 25 715. Библиотека должна выбрать правило, а не оставлять его случайным эффектом языка.

Для предложения «не меньше указанной стоимости» можно определить округление вверх до минимальной единицы. Это прикладной выбор; другой продукт вправе выбрать иную политику и описать последствия. Важно, что после фиксации итоговой суммы платёжный счёт сравнивает целые сатоши, а не пересчитывает дробь при каждом наблюдении.

// Чистая учебная функция; сетевого чтения и исполнения здесь нет.
function ceilDivPositive(numerator, denominator) {
  if (numerator < 0n || denominator <= 0n) throw new Error('Bad units');
  return numerator / denominator + (numerator % denominator === 0n ? 0n : 1n);
}

Функция предполагает целые bigint-входы и определённый знак. Она не проверяет свежесть или происхождение feed. Эти проверки выполняются до расчёта. Корректная арифметика чужой либо устаревшей котировки не делает предложение допустимым.

Пределы и кодирование

В JavaScript bigint помогает работать с большими целыми без потери точности Number. В Solidity арифметика имеет ограниченный диапазон соответствующего типа. При умножении масштабов нужно анализировать промежуточные значения, даже если окончательный результат небольшой. Автоматический checked-overflow обнаружит ошибку, но не выберет правильный способ вычисления вместо разработчика.

Будущий контракт может использовать подходящую проверенную технику полного умножения и деления либо заранее доказанные ограничения входов. В этом уроке такой контракт не объявлен реализованным. Наш результат — размерностная формула и область допустимых данных, которые нужны следующему исполнителю.

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

Зафиксированное предложение

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

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

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

Для отображения результата не обязательно преобразовывать bigint в Number перед передачей клиенту. Сервер может вернуть согласованную десятичную строку минимальных единиц и отдельное правило форматирования. Браузер показывает сумму с подходящим количеством знаков, а платёжная проверка использует исходные целые сатоши. Если интерфейс обрезал видимую дробную справку в USD, это не меняет счёт. В журнале суммы имеют явные единицы, чтобы оператор отличил округление представления от округления требуемой минимальной оплаты. Поздняя частичная оплата рассматривается платёжным маршрутом и не пересчитывается автоматически по новой котировке.

Изменить масштаб без изменения значения

Если новый допустимый источник выражает те же 60 000 USD за BTC с другим количеством десятичных знаков, масштаб и answer меняются согласованно. Правильная размерностная формула должна описывать тот же результат при соответствующем представлении. Но это не означает, что любой источник с другой конфигурацией имеет одинаковое доверие или свежесть.

Такой сценарий полезен для будущего упражнения: точное совпадение дроби, случай округления, неверная пара и недопустимый масштаб. Ожидаемые результаты фиксируются заранее, исполнения пока нет. Основы единиц раскрывает Data Feeds API Reference. Далее определим допустимость временного ответа, потому что числовая точность не заменяет свежего основания.

Оглавление серии