Журнал изменений
Журнал изменений
Что нового, что изменилось, что удалили — в хронологическом порядке.
- Инфраструктура
Отказоустойчивость на нескольких серверах
Обработчики блоков, консолидации, вебхуков и исходящих событий координируются через рекомендательные блокировки PostgreSQL. Для каждой нагрузки в один момент работает один ведущий процесс.
Если ведущий процесс останавливается, другой получает блокировку на следующем цикле опроса. Идемпотентная обработка сохраняет один результат даже при повторном чтении диапазона блоков во время переключения.
PostgreSQL хранит изменяемое состояние платформы. Кеш в памяти используется только для справочных данных, например точности токенов и констант сетей.
- Pricing
Комиссионные политики на проект
Комиссионные политики настраиваются на проект, а не только на мерчанта. Комиссия платформы на каждом инвойсе вычисляется при создании и фиксируется на инвойсе — что видит клиент в checkout, то и рассчитывается в цепи.
Две ручки на проект: комиссия платформы (процент с мерчанта) и customer markup (процент от комиссии платформы, добавляемый поверх отображаемой суммы и платимый плательщиком). Оба ноль — мерчант покрывает всё; markup 100 % — клиент платит полную комиссию.
Комиссия хранится на самом инвойсе, не пересчитывается потом из суммы депозита. Пересчёт — класс бухгалтерских багов, которого у нас нет.
- Withdrawals
Повторная отправка выводов по RBF
Выводы, зависшие в цепи — недоплатили газ, конфликт nonce, выкинули из мемпула — теперь ловит выделенный watchdog и автоматически проводит повторно.
На EVM-сетях watchdog использует replace-by-fee: если транзакция не включилась в блок за настроенный таймаут, она отправляется повторно с более высокой ценой газа, используя тот же nonce. Исходная вытесняется из мемпула без смены идентичности операции.
Ошибки broadcast классифицируются платформой на actionable-категории: revert (хендлер решает), конфликт nonce (повторная отправка со свежим), underpriced (RBF-бамп), insufficient funds (алёрт операциям). Каждая классификация видна в статусе вывода — не надо гадать, что пошло не так.
- Auth
Команды и роли
Приглашайте коллег в merchant-аккаунт без раздачи мастер-кредов. Каждый член команды получает роль, разворачивающуюся в гранулярный набор пермишенов, применяемых на уровне authorization-пайплайна — не только спрятанных в UI.
Вывод и управление вайтлистом по умолчанию доступны только владельцу. Admin может управлять инвойсами, вебхуками, проектами и составом команды, но не двинет деньги без явного гранта.
Управление в Settings.
- Тестирование
Тестовый режим с симуляцией платежей
Тестовый режим повторяет рабочий сценарий: те же методы API, подписи и вебхуки. Данные и ключи разделены между средами.
Платёж можно симулировать без перевода в основную сеть. Передайте этап (
paid,overpaid,underpaid,cancelled) в метод симуляции: Paymos рассчитает сумму и отправит те же события, что при реальной оплате. Формат вебхуков, подписи и расписание повторов не меняются.После проверки замените тестовый ключ рабочим. Интеграционный код и контракт API остаются прежними.
- Branding
Брендированный checkout — ваш логотип, ваши цвета
Размещённая страница оплаты теперь носит бренд мерчанта. Логотип, акцентный цвет, фон, текст футера — задаются один раз на проект и применяются ко всем инвойсам этого проекта.
Конструктор виджетов опирается на те же настройки бренда: палитра и логотип проекта подтягиваются во встраиваемый виджет, поэтому сайт с JS-сниппетом выглядит консистентно с размещённой страницей оплаты, на которую он ведёт.
Настройка бренда — в Settings. Конструктор виджетов — Widgets.
- Webhooks
Подписанные вебхуки с at-least-once доставкой
Доставка вебхуков теперь работает через outbox-паттерн. Доменные события пишутся в outbox в той же транзакции БД, что меняет бизнес-стейт — событие либо устойчиво записано, либо изменение стейта не случилось. Отдельный воркер забирает события и доставляет.
Каждый payload подписывается HMAC-SHA256. Подпись считается по сырым байтам тела и заголовку timestamp, поэтому защита от replay встроена — приёмник режет подписи старше настроенного окна. Секрет ротируется на endpoint через дашборд.
Доставка at-least-once. Расписание ретраев: 1 минута, 2, 4, 8, 16, 32 минуты, далее 1, 2, 4, 8, 16 часов — итого 11 попыток, растянутых более чем на 31 час. Приёмник должен быть идемпотентен по event ID — он есть в payload и в заголовке
Idempotency-Key. - POS
POS-терминал для оффлайн-точек
POS-терминал теперь часть платформы. Создание инвойса одним кликом со сгенерированным QR-кодом — кассир показывает клиенту телефон, клиент сканирует, платёж приходит на баланс мерчанта.
Страница терминала сделана под планшеты и телефоны, а не под десктоп. Большая клавиатура ввода суммы, заметная кнопка «Charge», статус переключается на «подтверждено» в реальном времени, как только депозит финализируется. На одном проекте может работать несколько терминалов, каждый идентифицируется отдельно для сверки.
Открывается на /pos.
- API
Публичный API для мерчантов
Публичный REST API принимает и возвращает JSON. Контракт опубликован в формате OpenAPI.
Ключ относится к конкретному проекту, а не ко всему аккаунту. Ограничение частоты считается отдельно для каждой учётной записи API в PostgreSQL и одинаково работает на нескольких серверах.
Merchant API подписывает запросы через HMAC. Сервер проверяет среду, права ключа и принадлежность ресурса до выполнения операции. Ключ рабочего режима не читает данные тестового проекта, и наоборот.
Управление ключами — в разделе Разработчикам → Ключи API. Контракт и примеры запросов доступны в документации.
- Widget
Конструктор виджетов с предварительным просмотром
В дашборде появился конструктор виджетов. Соберите платёжный виджет визуально — выберите цвета, лого, поддерживаемые сети, дефолтную сумму, redirect-поведение — и наблюдайте, как живое превью обновляется по мере правок.
URL-состояние кодируется в страницу — собранный виджет можно отправить одной ссылкой. Варианты экспорта: drop-in JavaScript-сниппет для любого сайта или iframe с явными размерами для жёсткого контроля над лейаутом. Виджет общается со стабильным публичным endpoint, поэтому деплой не сломается, когда мы выкатим внутренние изменения.
Откройте конструктор в Developers → Widgets.
- Architecture
CQRS-пайплайн с компилированной авторизацией
Каждая команда и запрос проходят через типизированный пайплайн: Logging → Validation → Authorization → Retry → Transaction → Handler. Каждый шаг generic по типу запроса — добавить поведение — одна DI-регистрация, не рефакторинг.
Авторизация компилируется на старте, а не разрешается через рефлексию на каждый запрос. Каждая команда несёт один атрибут, отображаемый на скоуп пермишена, проверку ownership и environment-guard. Скомпилированные таблицы делают per-request авторизацию словарным lookup-ом, а не обходом атрибутов.
Валидация идёт первой, потому что отклонить плохой ввод до удара по БД — самая дешёвая возможная неудача. Transaction — последний behavior перед хендлером — хендлеры сами не открывают транзакции, им передают.
- Payment Page
Размещённая страница оплаты
Размещённая страница оплаты доступна по единой ссылке. Клиент выбирает сеть, получает адрес и QR-код, а статус меняется на странице после обнаружения перевода.
После выбора сети Paymos выделяет адресу счёта реквизиты из платформенного пула и открывает серверный поток статуса. Обновления приходят автоматически; клиенту не нужно перезагружать страницу или нажимать кнопку проверки.
Один счёт может предложить несколько сетей, например Tron, BSC и Polygon. Оплату закрывает первый подтверждённый перевод, а неиспользованные адреса возвращаются в пул.
Доступно на /invoice/{invoice-id}.
- Dashboard
Дашборд мерчанта
Дашборд мерчанта доступен в рабочей среде. Blazor Server формирует страницу на сервере, а SignalR передаёт изменения без периодического опроса и перезагрузки.
Что в первом срезе:
- Обзор — дневной оборот, доля оплаченных счетов, события в очереди и последние поступления (Обзор →)
- Инвойсы — история с фильтрами по статусу, разбивка по сетям, таймлайн депозитов (Инвойсы →)
- Балансы — текущие суммы по токенам во всех включённых сетях и история выводов (Балансы →)
- Проекты — настройки на проект, включённые сети и токены, брендинг (Проекты →)
- Ключи API — учётные данные, адреса вебхуков и журнал событий (Ключи API →)
Переключатель в шапке переводит дашборд между рабочим и тестовым режимами без потери текущего раздела.
- Надёжность
Поздний платёж проверяется на границе счёта
Счёт закрывается только после того, как обработанная цепь прошла его срок действия. Это правило задано в доменной модели и применяется одинаково независимо от обработчика события.
Перевод может попасть в блок до окончания срока, но быть обнаружен позже. Поэтому Paymos учитывает время блока, последний обработанный блок и состояние подтверждения, а не время получения события сервером.
Регрессионные тесты проверяют этот инвариант при каждом изменении. Нарушение останавливает сборку до выпуска в рабочую среду.
- Расчёты
Автоматическая консолидация средств
Средства с адресов отдельных счетов автоматически переводятся в горячие кошельки Paymos. Консолидация выполняется в фоне и не задерживает зачисление: баланс мерчанта обновляется после подтверждения входящего перевода.
В EVM-сетях консолидация проходит в два этапа: адрес получает газ, затем переводит токен. Оба этапа входят в ставку приёма. В Tron Paymos также покрывает комиссию консолидации. Неудачные операции повторяются с увеличивающимся интервалом, а зависшие попадают в операционную проверку.
Мерчант работает с единым балансом и не обслуживает адреса каждого счёта отдельно.
- Rates
Курсы в реальном времени
Сервис курсов рассчитывает сумму счёта в стейблкоинах по актуальной рыночной котировке. Paymos не конвертирует полученный актив в фиат или другой токен: курс нужен только для цены счёта.
Основной источник котировок — CoinGecko. Несколько HTTP-подключений распределяют запросы, а временный кеш снижает задержку при создании счёта. Если мерчант указывает цену в EUR, Paymos рассчитывает сумму USDT по курсу на момент создания и сохраняет её до истечения счёта.
При кратком сбое используется последняя допустимая котировка. Если её срок истёк, создание счёта с пересчётом останавливается: система не подставляет непроверенную цену.
- Tokens
USDC на каждой EVM-сети
USDC теперь принимается на всех шести EVM-сетях, которые мы поддерживаем: Ethereum, BSC, Polygon, Arbitrum, Optimism, Base. Реестр токенов хранит канонический адрес контракта на сеть — нативный USDC не перепутается с бриджевым.
Мерчант включает USDC на проект через страницу настроек. У каждого проекта свой список принимаемых токенов; правила комиссий применяются на токен, а не на проект.
- Networks
TON в проде — восемь сетей онлайн
TON вошёл в список сетей. С TRON, шестью EVM-сетями и TON платформа теперь рассчитывает в восьми сетях через один API.
Архитектура TON отличается от EVM: кошельки реализованы как смарт-контракты, а джеттоны используют мастер-контракт и отдельный контракт кошелька пользователя. Для TON добавлены собственные RPC-клиенты, вычисление адресов джеттон-кошельков и отдельный обработчик переводов.
Подписной путь использует threshold-MPC по ed25519 вместо secp256k1, применяемой на ECDSA-сетях. Свойство порога то же: ни один узел не видит полного ключа.
- Networks
Arbitrum, Optimism и Base в проде
В список поддерживаемых сетей добавлены Arbitrum One, Optimism и Base. Все три используют общий процесс обработки EVM-транзакций, включая предварительную проверку и обработку реорганизаций блоков.
Газ на роллапах кардинально дешевле L1 Ethereum — расчёт USDC на Base или Arbitrum становится реальным вариантом для низкочекового e-commerce. Порог подтверждений настраивается на сеть — Base и Optimism подтверждаются по финалити секвенсера, как только достигнута заданная глубина подтверждений.
Подключите их на проект в разделе Проекты.
- Сети
Ethereum, BSC и Polygon подключены
Paymos подключил основные сети Ethereum, BNB Smart Chain и Polygon PoS. Общий обработчик блоков использует отдельную политику подтверждений для каждой сети.
Переводы обнаруживаются через
eth_getLogsв скользящем диапазоне блоков. Фильтр ограничивает выборку поддерживаемыми контрактами токенов. При реорганизации цепи обработчик отмечает исключённые блоки и продолжает с новой точки ветвления.Для каждой сети настроено несколько RPC-узлов. При ограничении частоты или сбое запросы переходят на доступный узел с увеличивающимся интервалом повтора. Новая EVM-сеть подключается через конфигурацию общей инфраструктуры.
- Токены
USDT-TRC20: от счёта до баланса
USDT в сети Tron проходит весь сценарий: счёт, обнаружение перевода, подтверждение и зачисление на баланс. Комиссия за консолидацию адреса входит в ставку Paymos и не вычитается отдельной строкой из поступления мерчанта.
Точность токена загружается из канонического реестра. Суммы рассчитываются в минимальных единицах USDT, поэтому отображение в интерфейсе не влияет на бухгалтерскую запись и не создаёт ошибок округления.
- Сети
Приём USDT в сети Tron
Paymos принимает USDT-TRC20 в сети Tron. Система создаёт счёт, обнаруживает перевод, применяет политику подтверждений и зачисляет средства на баланс мерчанта.
Число подтверждений зависит от суммы: небольшие платежи не ждут столько же, сколько крупные. Обработчик сети использует несколько RPC-узлов и переключается между ними при недоступности одного из источников.
Tron выбран за ликвидность USDT и широкое использование среди покупателей. Комиссию за отправку платит кошелёк клиента; для кошелька без энергии она обычно выше, чем в других поддерживаемых сетях.
- Custody
Threshold-подпись для каждого вывода
Каждая исходящая транзакция теперь подписывается пороговым протоколом — ни один сервер, ни один инженер, ни один утёкший секрет не двинет средства в одиночку.
Setup использует распределённую генерацию ключей: приватный ключ никогда не собирается в памяти ни на одном узле. Подпись делается через t-of-n MPC-протокол — secp256k1 для ECDSA-сетей (Ethereum, BSC, Polygon, Arbitrum, Optimism, Base, TRON) и ed25519 для TON. Порог настраивается на окружение.
Компрометация одной шары не двигает деньги. Компрометация меньше чем порог — тоже. Математике безразлично, кто атакует.
- Ledger
Двойная запись в ledger
Ledger с двойной записью теперь фиксирует каждое движение на платформе. Депозиты, комиссии, расчёты, возвраты, реверсы — каждое сбалансировано с противоположной стороной книги до коммита транзакции.
Дебет равен кредиту. Проверка выполняется внутри той же транзакции БД, что пишет записи — несбалансированная проводка не попадёт в БД. Расхождение между балансом мерчанта и реальностью в блокчейне — класс багов, которого у нас просто нет.
Ledger append-only. Корректировки кладутся новыми транзакциями со ссылкой на исходную — история целостна и реплеится.
- Architecture
Доменно-ориентированный фундамент
Доменный слой готов. Богатые модели с приватными сеттерами, фабричные методы, валидирующие каждый вход, и value-объекты для всего, что касается денег.
Money — это value-объект, привязанный к токену, а не сырое decimal. Кросс-токенная арифметика отсекается на уровне намерения и громко падает в рантайме — сложить USDT и TRX просто нельзя.
Бизнес-операции возвращают
Outcome<T, Error>, а не бросают исключения. Исключения зарезервированы под реальные баги. Ожидаемые сбои идут как значения через весь пайплайн. - Engineering
Старт разработки
Сегодня началась разработка Paymos. Стек: .NET 10 и Blazor Server для хост-слоя, PostgreSQL с EF Core 9 для персистенса, MediatR для пайплайна команд и запросов.
Кодовая база разделена на четыре слоя — домен, приложение, инфраструктура, хост — со строгой инверсией зависимостей. Домен не зависит ни от чего. Инфраструктура адаптируется к портам, объявленным в приложении. Хост соединяет всё вместе.
Test-first — правило, а не исключение. CI прогоняет полный набор тестов на каждый push.