Suward
ЗАЩИТА ОТ REORG

Защита от reorg: финальность, которой можно верить

Блок может быть пере-собран и откатан, утянув с собой «зачисленный» перевод. Suward не зачисляет по одному блоку. Каждый платёж проходит Pending → Safe → Finalized и держится до заданного порога финальности — за ним стоят авто- и ручная перепроверка.

PendingSafeFinalized
Pending
Safe
Finalized

Что такое reorg

Представьте: два майнера нашли блок почти на одной высоте. На миг у цепочки два «кончика». Сеть оставляет более длинную ветку, отбрасывает другую — и любая транзакция, что жила только на отброшенной ветке, просто исчезает, будто её и не было. Это и есть reorg. Наивный листенер зачисляет мерчанту сразу, как увидел перевод, и не отыгрывает назад, когда блок пропал, — а мерчант остаётся без денег. Это реальный риск публичных сетей. И именно его Suward снимает с вас.

Lifecycle

Pending → Safe → Finalized

Один перевод, три состояния. По-настоящему завершённым Suward считает платёж только на последнем.

  1. Pending

    Pending. Перевод попал в блок, но блок молодой, и подтверждения ещё набираются. Reorg тут вполне возможен, поэтому ничего не зачисляется. Товар придержите.

  2. Safe

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

  3. Finalized

    Finalized. Заданный порог финальности сети достигнут, и перевод стал частью устоявшейся истории. Отгружайте заказ.

За этим стоят две настройки, а не одна. Per-сеть required_confirmations считает, сколько блоков должно лечь сверху. Safe- и finalized-офсеты монитора решают, где проходят Safe и Finalized. Вместе они и проводят черту, по которой можно отгружать.

Авто-перепроверка

Монитор следит за головой каждой цепи. Когда блоки у кончика перестраиваются, он сам пересчитывает затронутые статусы — вплоть до Finalized, без оператора. В баланс платёж попадает только пройдя уровень финальности. Это зачисление ложится атомарно как Decimal128 и никогда не уходит ниже нуля. Работа идёт, смотрите вы или нет.

Ручной ReverifyBlock

На редкий краевой случай оператор может принудительно перепроверить блок. ReverifyBlock(blockchain_id, number, head_number) пересчитывает Pending, Safe и Finalized для одного блока; передайте head_number=0, чтобы оставить его как Pending. Это backstop, а не замена авто-логике. Под капотом outbox переносит статус-события из монитора в cryptopay, чтобы сбой сервиса их не уронил.

ReverifyBlock(blockchain_id, number, head_number)
Confirmations

Подтверждения по сетям

Значение required_confirmations задаётся для каждой сети. Вот сколько ждёт каждая.

Networkrequired_confirmations
Ethereum
12
Arbitrum
12
Optimism
12
Base
12
BSC
15
Polygon
128
PlaPlasmaSoon
12

Polygon ждёт 128 подтверждений намеренно: у него история частых reorg, поэтому доверие он набирает медленнее остальных. Plasma пока помечен Soon, пока чинится проблема с chainID. Детали по каждой сети — на её странице.

Отслеживание статуса через API

За платежом вы следите опросом GET /v1/payments/{paymentId}. В ответе — PaymentStatusEnum (pending, accepted, success, failed) и более тонкий PaymentSubStatusEnum (confirming, acceptedCompleted, acceptedOverpaid, acceptedUnderpaid). Этот poll — источник истины в любой момент, потому что вебхуков для мерчанта пока нет. Когда появятся, сначала будут помечены Soon.

GET
/v1/payments/{paymentId}
pending
accepted
success
failed
Честные ограничения

Две вещи, о которых честно сказать заранее. ERC-20-детект читает только calldata transfer(), а значит, не подхватит transferFrom или мульти-сенд, поэтому правило простое: пусть плательщики шлют обычный transfer на уникальный адрес — и всё сходится. Вебхуков пока тоже нет. Статус берётся из poll выше. Это инженерные факты, а не маркетинговые.

Reorg — частые вопросы

Когда статус становится Finalized — то есть достигнут заданный порог финальности сети. До этого он на Pending или Safe, и деньги ещё не дошли до баланса.

Safe значит «откат маловероятен», а не «невозможен». Именно поэтому это не Finalized. Если reorg всё же случился, монитор сам пересчитывает статус до финальности, а баланс — от on-chain-реальности. Можете дождаться Finalized — дождитесь.

Считается не время, а число подтверждений. Ethereum ждёт 12, Polygon — 128, поэтому Polygon ощутимо дольше, и это намеренно. На странице каждой сети указано её число.

Перестаньте писать свой листенер блоков