Autorisation d'agents
Prise en charge de la signature multi-clés pour les teneurs de marché.
Vue d'ensemble
L'autorisation d'agents permet à une clé de signature dédiée (agent) de placer et d'annuler des ordres pour le compte d'un portefeuille de trading. C'est utile pour :
- Sécurité : conservez les clés du portefeuille de trading en stockage à froid et utilisez des clés chaudes pour signer
- Opérations : plusieurs membres d'une équipe peuvent signer avec des clés différentes
- Automatisation : les systèmes automatisés peuvent signer avec des clés dédiées
Deux modèles d'autorisation
Hypercall dispose de deux systèmes de délégation distincts selon le produit :
| Produit | Type de délégation | Stockage | Mise en place |
|---|---|---|---|
| Options (API REST) | Autorisation d'agent | État du moteur Hypercall | POST /approve-agent |
| Perpétuels | Portefeuille API | On-chain (votre contrat Account) | Directive hc_update_api_wallet |
Ces systèmes sont indépendants. Approuver un agent pour le trading d'options ne l'autorise pas pour les perpétuels, et inversement.
Options : autorisation d'agent (off-chain)
Les agents signent les messages EIP-712 PlaceOrder et CancelOrder pour le compte d'un portefeuille de trading. L'API vérifie l'agent par rapport à l'état d'autorisation du moteur avant que l'ordre n'atteigne le moteur.
Perpétuels : portefeuille API (on-chain)
Les portefeuilles API signent les ordres et annulations sur perpétuels dans le domaine EIP-712 HypercallApiSign. Hypercall vérifie le signataire auprès de votre contrat Account (isApiWalletActive()) avant d'admettre l'ordre. Sur la route TEE (par défaut dans l'application, et sur option pour les clients API), une enclave sécurisée détenant une clé de trading Hyperliquid distincte pour votre Account signe et envoie l'ordre natif ; sur la route smart contract, un paramètre avancé de l'application, l'ordre passe par votre contrat Account. Consultez Signature EIP-712 pour la référence de signature et Perpétuels pour le flux.
Pour ajouter ou retirer un portefeuille API, soumettez une directive hc_update_api_wallet signée par le portefeuille gestionnaire (manager) du compte.
Ce fonctionnement reprend le modèle de portefeuille API d'Hyperliquid. Hyperliquid documente ces portefeuilles sous le nom d'API wallets, également appelés agent wallets, dans Nonces and API wallets, et documente approveAgent dans l'Exchange endpoint.
Protection contre le rejeu des nonces
Le suivi des nonces suit le modèle de nonce d'Hyperliquid. Toutes les actions signées (ordres, approbation/révocation d'agent, handshakes QP) partagent un espace de nonces par signataire. Le moteur conserve les 100 nonces les plus élevés par adresse de signataire. Un nouveau nonce est accepté si :
!stored_set.contains(nonce): ce n'est pas un doublonnonce > min(stored_set)une fois que l'ensemble contient 100 entrées : il est supérieur au plus petit nonce stockénoncese situe dans l'intervalle (T - 2 jours, T + 1 jour) autour de l'horodatage du serveur
Les nonces hors séquence sont autorisés (par exemple, le nonce 105 puis le nonce 102 fonctionnent tous deux s'ils sont au-dessus du minimum de l'ensemble). L'ensemble est limité à 100 entrées, de sorte que les entrées les plus anciennes sont évincées à mesure que de nouvelles sont ajoutées. Cela évite qu'un compte soit bloqué par un seul nonce très élevé.
Le signataire du nonce est l'adresse qui a signé le message EIP-712 : le portefeuille API pour les ordres, le signataire récupéré pour l'autorisation d'agent, le portefeuille QP pour les handshakes. Les clients doivent utiliser Date.now() (epoch en millisecondes) comme valeur initiale du nonce et l'incrémenter de façon monotone.
Autorisation d'agent pour les options
Signature directe
Si signer == wallet, l'ordre est toujours autorisé (auto-signature).
Signature par un agent
Si signer != wallet, le signataire doit être un agent autorisé :
- L'agent doit être présent dans l'état d'autorisation détenu par le moteur
- L'autorisation ne doit pas être expirée
- Les snapshots du moteur et le journal du moteur sont les sources durables utilisées au redémarrage
Approuver un agent
Endpoint : POST /approve-agent
Requête : ApproveAgentRequest
{
"agent": "0x...",
"nonce": 1,
"signature": "0x..."
}
Signature :
- Le propriétaire du portefeuille signe le message
ApproveAgent - Le portefeuille est dérivé de la signature récupérée
- L'agent correspond au champ
agentde la requête
Struct EIP-712 :
struct ApproveAgent {
address agent;
uint64 nonce;
}
Réponse : ApproveAgentResponse
{
"success": true,
"error": null
}
Remarques :
- L'autorisation d'agent est un état du moteur journalisé et survit aux redémarrages
- Les approbations effectuées via cet endpoint n'expirent pas
Révoquer un agent
Endpoint : DELETE /revoke-agent
Requête : RevokeAgentRequest
{
"agent": "0x...",
"nonce": 2,
"signature": "0x..."
}
Signature :
- Le propriétaire du portefeuille signe le message
RevokeAgent - Le portefeuille est dérivé de la signature récupérée
Struct EIP-712 :
struct RevokeAgent {
address agent;
uint64 nonce;
}
Réponse : RevokeAgentResponse
Remarques :
- Applique une commande
RevokeAgentjournalisée à l'état d'autorisation détenu par le moteur - Les vérifications d'autorisation de l'API de trading lisent l'état du backend et appliquent les révocations aux requêtes de trading. La publication dans la Trollbox peut mettre en cache une autorisation d'agent positive plus longtemps, de sorte qu'un agent récemment révoqué peut encore publier jusqu'à l'expiration de ce cache ou jusqu'à ce que l'invalidation, effectuée au mieux, atteigne l'emplacement edge concerné. Ce cache n'autorise aucune mutation via l'API de trading.
- L'agent ne peut plus signer pour le portefeuille après la révocation
Révoquer tous les agents
Endpoint : DELETE /revoke-all-agents
Requête : { "nonce": 3, "signature": "0x..." }, signée par le propriétaire du portefeuille sur RevokeAllAgents(uint64 nonce). Supprime tous les agents du portefeuille récupéré.
Obtenir les agents autorisés
Endpoint : GET /authorized-agents?wallet=...
Paramètres de requête :
wallet(obligatoire)
Réponse :
{
"agents": [
"0x...",
"0x..."
]
}
Remarques :
- Renvoie uniquement les agents actifs et non expirés
Utilisation des agents
Signer des ordres avec un agent
Une fois un agent approuvé :
- Signer l'ordre avec le portefeuille agent : utilisez le portefeuille agent pour signer les messages
PlaceOrder/CancelOrder - Renseigner le champ wallet : définissez le champ
walletsur l'adresse du portefeuille de trading (et non sur l'adresse de l'agent) - Vérification par le middleware : le middleware vérifie que l'agent est autorisé pour ce portefeuille
Exemple :
// 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. The REST body uses snake_case `client_id`.
const { clientId, ...rest } = message;
const response = await fetch('/order', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
...rest,
client_id: clientId,
signature
})
});
Ordres groupés avec un agent
Les endpoints groupés vérifient l'autorisation d'agent élément par élément :
- Chaque ordre de
POST /bulk_orderpeut être signé par un agent différent - L'autorisation d'agent est vérifiée pour chaque élément
- Si un élément échoue à la vérification d'agent, cet élément renvoie une erreur dans
BulkOrderResult
Vérifications d'autorisation
Middleware (ordres unitaires)
Endpoints :
POST /orderDELETE /orderDELETE /order_cloid
Vérification : signature_and_agent_middleware vérifie que :
- La récupération de la signature réussit
- Le signataire est autorisé (signer == wallet OU agent autorisé)
Handler (ordres groupés)
Endpoints :
POST /bulk_orderDELETE /bulk_orderDELETE /bulk_order_cloid
Vérification : vérification élément par élément dans le handler :
- Récupération de la signature pour chaque élément
- Vérification de l'autorisation d'agent pour chaque élément
Stockage des autorisations
L'autorisation d'agent est un état détenu par le moteur. Les commandes ApproveAgent et RevokeAgent sont journalisées, restaurées par le rejeu du moteur et exposées via le snapshot de lecture pour les vérifications de l'API.
Logique d'autorisation
L'autorisation du signataire repose sur une logique OU explicite :
- Signature directe :
signer == wallet. - Signature par un agent : le snapshot du moteur contient un enregistrement d'autorisation pour
wallet_address == <wallet>etagent_address == <signer>, etexpires_atest absent ou situé dans le futur.
Expiration
Le moteur prend en charge un champ expires_at sur une autorisation et considère un agent
expiré comme non autorisé. POST /approve-agent n'en définit pas, de sorte que les agents
approuvés via l'API restent actifs jusqu'à leur révocation.
Considérations de sécurité
- Sécurité des clés d'agent : protégez les clés privées des agents (utilisez des portefeuilles matériels ou une gestion de clés sécurisée)
- Audits réguliers : passez régulièrement en revue les agents autorisés via
GET /authorized-agents - Révocation des agents inutilisés : révoquez les agents qui ne sont plus nécessaires
Bonnes pratiques
- Utilisez des agents pour l'automatisation : conservez les clés du portefeuille de trading en stockage à froid et utilisez des agents pour les systèmes automatisés
- Limitez le périmètre des agents : n'approuvez que les agents qui ont besoin d'un accès
- Surveillez l'utilisation des agents : suivez quels agents placent des ordres
- Révoquez rapidement : révoquez les agents dès qu'ils ne sont plus nécessaires
Problèmes courants
"Signer 0x... is not authorized to act for wallet 0x..."
Cause : agent non approuvé, ou autorisation expirée ou révoquée.
Solution : approuvez l'agent via POST /approve-agent ou signez directement avec le portefeuille.
L'autorisation d'agent ne fonctionne pas
Causes :
- L'agent n'est pas présent dans l'état d'autorisation détenu par le moteur
- L'autorisation a été révoquée
- L'autorisation a expiré
Solution : vérifiez le statut de l'agent via GET /authorized-agents?wallet=....