Перейти к содержимому
PortunaPortunaPortunaДокументацияTestnet

Модель безопасности

Ключи депозитных адресов не покидают вашу кастоди. Ваш HSM, KMS или MPC подписывает для каждого адреса одно — авторизацию EIP-7702, и к Portuna попадает только подпись. Горячие кошельки (котлы) — ваши собственные адреса: их ключей сервис тоже не держит.

Авторизация заставляет депозитный адрес выполнять в одной сети код делегата вашего горячего кошелька. Этот код маленький и неизменный:

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

Ещё не применённую авторизацию может отправить в сеть кто угодно, не только Portuna: так устроен EIP-7702. Но и тогда она поставит только ваш делегат, который платит только в ваш горячий кошелёк. Подписывайте только на delegate, который API вернул для вашего горячего кошелька, и сначала проверяйте его командой verify-delegate.

Авторизация привязана:

  • к одной сети: API не принимает chain_id 0, иначе подпись действовала бы во всех сетях;
  • к одному nonce: если адрес отправит любую транзакцию раньше, чем авторизация будет применена, она перестанет действовать, и нужно подписать новую.

Чтобы отменить делегацию, адрес подписывает авторизацию на нулевой адрес: см. Снятие делегации.

Код контрактов открыт, а создаются они через CREATE2, поэтому каждый адрес — это хэш точного кода, который по нему лежит. Если адрес, посчитанный из кода, совпадает с адресом в сети и там есть код, значит, в сети именно этот код — с вашими горячим кошельком и газ-кошельком внутри. Команда verify-delegate из SDK делает всю проверку: см. Проверка делегата и Контракты.

У каждого партнёра свои газ-кошелёк, батчер и делегаты. Делегат слушается только батчера своего партнёра, а батчер — только его газ-кошелька, поэтому один партнёр не может запустить, перенаправить или заблокировать sweep другого. Сервис со своей стороны:

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

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

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

  • API-ключ показывается один раз и хранится только в виде хэша. Держите его на бэкенде; отозванный ключ перестаёт работать сразу. Тестовые ключи (ptn_test_) работают только в тестнетах, боевые (ptn_live_) — только в мейннете.
  • Вебхуки уходят только на публичные адреса по https, редиректы не выполняются. Каждая доставка подписана HMAC-SHA256 с меткой времени: проверяйте подпись, прежде чем доверять ей.