Авторизация агентов
Поддержка подписи несколькими ключами для маркетмейкеров.
Обзор
Авторизация агента позволяет выделенному ключу подписи (агенту) размещать и отменять ордера от имени торгового кошелька. Это полезно для:
- Безопасности: храните ключи торгового кошелька в холодном хранилище, а для подписи используйте горячие ключи
- Операционной работы: несколько участников команды могут подписывать разными ключами
- Автоматизации: автоматизированные системы могут подписывать выделенными ключами
Две модели авторизации
В Hypercall есть две отдельные системы делегирования в зависимости от продукта:
| Продукт | Тип делегирования | Хранение | Как настроить |
|---|---|---|---|
| Опционы (REST API) | Авторизация агента | Офчейн (база данных) | POST /approve-agent |
| Перпы (ончейн-директивы) | API-кошелёк | Ончейн (контракт Exchange) | Директива hc_update_api_wallet |
Это независимые системы. Одобрение агента для торговли опционами не даёт ему прав на перпы, и наоборот.
Опционы: авторизация агента (офчейн)
Агенты подписывают EIP-712-сообщения PlaceOrder и CancelOrder от имени торгового кошелька. API-сервер проверяет авторизацию по своей базе данных перед передачей в движок.
Перпы: API-кошелёк (ончейн)
API-кошельки подписывают директивы для перпов, используя EIP-712-домен HypercallAgentSign. Контракт Exchange проверяет авторизацию ончейн через isApiWalletActive(). Полный справочник по подписи директив см. в разделе Подпись EIP-712.
Чтобы добавить или удалить API-кошелёк, отправьте директиву hc_update_api_wallet, подписанную управляющим кошельком аккаунта.
Это повторяет модель API-кошельков Hyperliquid. Hyperliquid описывает их как API-кошельки, также называемые агентскими кошельками, в разделе Nonces and API wallets, а approveAgent документирован в разделе Exchange endpoint.
Защита от повторного использования nonce
Отслеживание nonce следует модели nonce Hyperliquid. Все подписанные действия (ордера, одобрение/отзыв агента, QP-хендшейки) используют общее пространство nonce на каждого подписанта. Движок хранит 100 наибольших nonce для каждого адреса подписанта. Новый nonce принимается, если:
nonce > min(stored_set)— должен быть больше наименьшего хранимого nonce!stored_set.contains(nonce)— не должен быть дубликатомnonceнаходится в пределах (T - 2 дня, T + 1 день) от временной метки сервера
Nonce вне порядка допустимы (например, nonce 105, затем 102 — оба сработают, если оба выше минимума набора). Набор ограничен 100 записями, поэтому по мере добавления новых старейшие записи вытесняются. Это исключает блокировку аккаунта из-за одного слишком большого nonce.
Подписант nonce — это адрес, подписавший EIP-712-сообщение: API-кошелёк для ордеров, восстановленный подписант для авторизации агента, QP-кошелёк для хендшейков. Клиентам следует использовать Date.now() (миллисекунды эпохи) в качестве начального значения nonce и монотонно его увеличивать.
Авторизация агентов для опционов
Прямая подпись
Если signer == wallet, ордер всегда авторизован (самоподпись).
Подпись агентом
Если signer != wallet, подписант должен быть авторизованным агентом:
- Агент должен присутствовать в состоянии авторизации, принадлежащем движку
- Авторизация не должна быть просроченной
- Снепшоты движка и журнал движка — надёжные источники при перезапуске
Одобрение агента
Эндпоинт: POST /approve-agent
Запрос: ApproveAgentRequest
{
"agent": "0x...",
"nonce": 1,
"signature": "0x..."
}
Подпись:
- Владелец кошелька подписывает сообщение
ApproveAgent - Кошелёк определяется из восстановленной подписи
- Агент — это поле
agentв запросе
Структура EIP-712:
struct ApproveAgent {
address agent;
uint64 nonce;
}
Ответ: ApproveAgentResponse
{
"success": true,
"error": null
}
Примечания:
- Авторизация агента постоянна (хранится в БД)
- Авторизация не истекает, если не задано
expires_at(пока не реализовано)
Отзыв агента
Эндпоинт: DELETE /revoke-agent
Запрос: RevokeAgentRequest
{
"agent": "0x...",
"nonce": 2,
"signature": "0x..."
}
Подпись:
- Владелец кошелька подписывает сообщение
RevokeAgent - Кошелёк определяется из восстановленной подписи
Структура EIP-712:
struct RevokeAgent {
address agent;
uint64 nonce;
}
Ответ: RevokeAgentResponse
Примечания:
- Применяет журналируемую команду
RevokeAgentк состоянию авторизации, принадлежащему движку - Проверки авторизации торгового API читают состояние бэкенда и применяют отзывы для торговых запросов. Публикация в троллбоксе может кэшировать положительную авторизацию агента дольше, поэтому недавно отозванный агент может по-прежнему публиковать сообщения, пока кэш не истечёт или инвалидация по мере возможности не дойдёт до соответствующей edge-локации. Этот кэш не даёт прав на мутации торгового API.
- После отзыва агент больше не может подписывать за кошелёк
Получение списка авторизованных агентов
Эндпоинт: GET /authorized-agents?wallet=...
Параметры запроса:
wallet(обязательный)
Ответ:
{
"agents": [
"0x...",
"0x..."
]
}
Примечания:
- Возвращает только активных агентов с непросроченной авторизацией
- Сортировка по
created_at DESC
Использование агентов
Подпись ордеров агентом
После одобрения агента:
- Подпишите ордер кошельком агента: используйте кошелёк агента для подписи сообщений
PlaceOrder/CancelOrder - Заполните поле wallet: укажите в поле
walletадрес торгового кошелька (не адрес агента) - Проверка в middleware: middleware проверяет, что агент авторизован для этого кошелька
Пример:
// Agent wallet signs the order
const agentSigner = new ethers.Wallet(agentPrivateKey);
const message = {
wallet: "0x...", // Trading wallet (not agent)
symbol: "BTC-20250131-100000-C",
side: "Buy",
size: "0.1",
price: "100.0",
tif: "gtc",
clientId: "mm-1",
nonce: 1
};
// Sign with agent wallet
const signature = await agentSigner._signTypedData(domain, types, message);
// Send request
const response = await fetch('/order', {
method: 'POST',
body: JSON.stringify({
...message,
signature
})
});
Пакетные ордера с агентом
Пакетные эндпоинты проверяют авторизацию агента для каждого элемента:
- Каждый ордер в
POST /bulk_orderможет быть подписан разным агентом - Авторизация агента проверяется для каждого элемента
- Если у какого-либо элемента проверка авторизации агента не проходит, этот элемент возвращает ошибку в
BulkOrderResult
Проверки авторизации
Middleware (одиночные ордера)
Эндпоинты:
POST /orderDELETE /orderDELETE /order_cloid
Проверка: signature_and_agent_middleware проверяет:
- Восстановление подписи успешно
- Подписант авторизован (signer == wallet ИЛИ агент авторизован)
Обработчик (пакетные ордера)
Эндпоинты:
POST /bulk_orderDELETE /bulk_orderDELETE /bulk_order_cloid
Проверка: поэлементная проверка в обработчике:
- Восстановление подписи для каждого элемента
- Проверка авторизации агента для каждого элемента
Хранение авторизации
Авторизация агентов — это состояние, принадлежащее движку. Команды ApproveAgent и RevokeAgent журналируются, восстанавливаются через воспроизведение журнала движка и доступны через снепшот чтения для проверок API.
Логика авторизации
Авторизация подписанта — это явная логика ИЛИ:
- Прямая подпись:
signer == wallet. - Подпись агентом: снепшот движка содержит запись авторизации для
wallet_address == <wallet>иagent_address == <signer>, аexpires_atотсутствует или находится в будущем.
Истечение срока
expires_at контролируется проверками авторизации по снепшоту движка. Агенты с
expires_at < NOW() считаются неавторизованными.
Вопросы безопасности
- Безопасность ключей агента: защищайте приватные ключи агентов (используйте аппаратные кошельки или безопасное управление ключами)
- Регулярные аудиты: регулярно проверяйте список авторизованных агентов через
GET /authorized-agents - Отзывайте неиспользуемых агентов: отзывайте агентов, которые больше не нужны
- Истечение срока: используйте
expires_atдля временной авторизации агентов, когда путь одобрения позволяет задать нестандартный срок истечения
Рекомендации
- Используйте агентов для автоматизации: храните ключи торгового кошелька в холодном хранилище, для автоматизированных систем используйте агентов
- Ограничивайте область действия агентов: одобряйте только тех агентов, которым нужен доступ
- Отслеживайте использование агентов: следите за тем, какие агенты размещают ордера
- Отзывайте своевременно: отзывайте агентов сразу, как только они перестают быть нужны
Типичные проблемы
"Unauthorized: signer not authorized for wallet"
Причина: агент не одобрен, либо авторизация истекла или отозвана.
Решение: одобрите агента через POST /approve-agent или подписывайте кошельком напрямую.
Авторизация агента не работает
Причины:
- Агент отсутствует в состоянии авторизации, принадлежащем движку
- Авторизация была отозвана
- Авторизация истекла
Решение: проверьте статус агента через GET /authorized-agents?wallet=....