В прошлый раз, когда я пополнял биржу, я после того как скопировал адрес, еще дважды перепроверил memo — боялся, что монеты придут, но система не сможет понять, что это мои. Потом, когда я посмотрел интеграцию биржи для @Dusk в документации, я понял: требования Dusk к пополнению бэкенд предъявляет более строгие, чем просто «указать правильный memo». Сначала выбирается модель публичного аккаунта Moonlight, потом решается, у каждого пользователя отдельный аккаунт или общий аккаунт с memo.

Если используется общий аккаунт, то memo нужно только для того, чтобы сообщить системе, «кому следует отнести эти деньги», но оно не подходит как единственное доказательство для предотвращения повторного зачисления. Два пользователя могут ошибиться и указать одинаковый memo, а одна и та же запись может быть заново просканирована из‑за перезапуска бэкенда. Поэтому в официальной документации рекомендуется использовать transaction ID Dusk как idempotency key. Простыми словами: это «замок, который позволяет записать пополнение только один раз».

#dusk

Еще один легко упускаемый из виду крайний случай: биржа не должна сразу начислять пользователю средства просто потому, что увидела увеличение баланса Moonlight. Ей нужно просканировать архивную историю, которая уже окончательно финализирована, найти прямые переводы, и пополнения с отсутствующим memo, с неверным форматом, с неизвестным или повторяющимся memo сначала отправлять в изоляцию, а не автоматически зачислять «на авось».

Точнее: запись пополнения в бэкенд и продвижение блокового чекпойнта должны выполняться в рамках одного и того же транзакционного запроса к базе данных. Если сначала продвинуть чекпойнт, а затем зачислить, то при падении сервиса можно пропустить деньги пользователя; если сначала зачислить, но не сохранить прогресс, то при повторном сканировании можно обработать одно и то же пополнение дважды. Конвертация Phoenix, оплата по контракту и вывод с залога тоже должны иметь отдельные правила событий — нельзя смешивать их с обычным пополнением.

Эта логика очень похожа на склад доставки: memo — это ярлык получателя, transaction ID — неповторимый номер посылки, а finalized — тот момент, когда посылка действительно поступает на склад. Если смотреть только на одно из этих звеньев, легко получить потерю посылки или повторную доставку.

Поэтому, когда я смотрел адаптацию биржи для $DUSK , я оцениваю не только «умеет ли она пополнять/выводить», а то, может ли бэкенд после финализации корректно зачислять, дедуплицировать по transaction ID, синхронно отправлять чекпойнт и обновлять бухгалтерскую книгу. Настоящий финансовый уровень — это не «быстро крутится на фронтенде», а то, что после перезапуска бэкенда и повторного сканирования система не добавит лишнего и не убавит ни цента.

#dusk