Signature EIP-712
Cette page est la référence, champ par champ, de chaque message EIP-712 vérifié par Hypercall : les trois domaines de signature des directives (portefeuille API, Manager, RSM), les messages perp uniquement hors chaîne qui partagent le domaine du portefeuille API, et le domaine autonome Physical Covered Call Quote. Les ordres d'options de l'API REST utilisent un domaine différent, Hypercall ; voir Authentification et signature.
Tout ce qui figure ici a été vérifié par rapport aux contrats déployés sur le réseau principal HyperEVM (chain ID 999) : Exchange 0.6.1 à l'adresse 0xE6b7FaA216cabb2b38B392f577C9c826378b2240 et Account 0.2.4. Les séparateurs de domaine et les typehashes ci-dessous sont intégrés dans ce bytecode déployé.
Vue d'ensemble
Une directive est une action unique sur un Account, signée hors chaîne et soumise on-chain par le séquenceur de Hypercall via Exchange.executeUserDirective ou Exchange.executeRsmDirective. L'Account récupère le signataire à partir du digest EIP-712 et vérifie l'autorisation :
- Portefeuille API : une adresse enregistrée sur l'Account avec
hc_update_api_wallet(Account.isApiWalletActive). Signe les ordres et les annulations. - Manager : le propriétaire de l'Account (
Account.manager). Signe les modifications de portefeuille API, les envois d'actifs et les changements de mode de compte. - Signataire RSM : contrôlé par le protocole (
Exchange.rsmSigner). Signe les crédits, les retraits, les directives de liquidation et les ordres de récupération reduce-only. Les utilisateurs ne les signent jamais.
Encodage des directives
On-chain, une directive est abi.encodePacked(account, nonce, version, id, data) :
| Octets | Champ | Signification |
|---|---|---|
| 20 | account | L'adresse de l'Account (address) |
| 8 | nonce | Le nonce du signataire (uint64) |
| 1 | version | Famille d'actions |
| 3 | id | Identifiant de l'action au sein de la famille |
| reste | data | abi.encode de la structure d'action interne |
| Version | Famille | Identifiants d'action |
|---|---|---|
0 | HyperCall (HC) | 2 mise à jour du portefeuille API. 1 (transfert d'option) est réservé et rejeté. |
1 | HyperLiquid (HL) | 1 ordre limite, 9 ajout de portefeuille API, 10 annulation par oid, 11 annulation par cloid, 13 envoi d'actif, 16 définition de l'abstraction |
255 | Système | 1 crédit de token, 2 crédit d'option, 3 début de liquidation, 4 fin de liquidation, 5 retrait de token |
Vous ne construisez pas cette chaîne d'octets vous-même. Signez les données typées, puis soumettez account, nonce, action et signature à l'API, qui encode la directive.
Forme des données typées
Chaque directive a la même forme externe : l'adresse de l'Account, le nonce du signataire et une structure d'action interne.
<Outer>(address account,uint64 nonce,<Inner> action)<Inner>(...)
La chaîne de type externe ajoute la définition du type interne, de sorte que le typehash couvre les deux. En termes EIP-712, primaryType est le nom externe, types contient les deux entrées, et message est { account, nonce, action }. L'ordre des champs fait partie de la chaîne de type et doit correspondre exactement.
Points d'entrée de financement non signés
Tous les appels de financement ne sont pas des actions EIP-712. Ces méthodes sont des transactions directes envoyées par le portefeuille payeur ou le routeur :
function depositUsdcFor(address account, uint256 amount) external;
function depositOption(address account, address token, uint256 amount) external;
depositUsdcFor est volontairement non signé, car msg.sender n'est que le payeur en USDC. Le compte Hypercall crédité est l'argument explicite account et le champ d'événement UsdcDeposit.account. Des routeurs et des zaps peuvent appeler cette méthode, donc les indexeurs et les services backend ne doivent pas utiliser msg.sender pour attribuer le crédit.
depositOption brûle les tokens d'option de msg.sender et émet Deposit(account, msg.sender, token, amount) pour l'indexeur RSM. Le chemin de crédit des options est piloté par les événements et n'utilise aucune signature de manager, d'agent ou du RSM de la part du déposant.
Domaine autonome : cotations de covered calls physiques
Les cotations de covered calls physiques sont vérifiées par la factory déployée sur la chaîne sélectionnée. Elles n'utilisent ni le vérificateur de l'Exchange ni son domaine à adresse nulle.
Domaine :
{
"name": "Hypercall Physical Covered Call",
"version": "1",
"chainId": "<selected chain id>",
"verifyingContract": "<exact PhysicalCoveredCallFactory address>"
}
Signataire : le market maker encodé dans PhysicalCoveredCallQuote.marketMaker.
Types imbriqués canoniques :
AssetTerms(address underlyingWrapper)
OptionTerms(address seller,uint256 underlyingAmount,uint64 strikeX8,uint64 expiry)
PhysicalCoveredCallRequest(bytes32 rfqId,AssetTerms asset,OptionTerms option)AssetTerms(address underlyingWrapper)OptionTerms(address seller,uint256 underlyingAmount,uint64 strikeX8,uint64 expiry)
PhysicalCoveredCallQuote(bytes32 requestHash,bytes32 quoteId,address marketMaker,uint256 premiumSettlement,uint64 quoteDeadline,uint64 nonce)
La factory recalcule requestHash à partir de la requête imbriquée complète avant de récupérer le signataire de la cotation. La signature lie donc le vendeur, le wrapper du sous-jacent, le montant de parts du wrapper, le strike, l'échéance, la prime, la date limite de la cotation, le nonce, le chain id et l'adresse de la factory. Le token de règlement et ses décimales relèvent de la configuration de la factory, qui fait autorité, et ne sont pas des valeurs signées séparément. Pyth est absent de cette génération sans oracle. Le digest de la cotation et le nonce du market maker sont tous deux consommés lorsque le vendeur finance un vault.
Seul le vendeur encodé dans la requête peut soumettre la cotation signée. Le financement émet le NFT de créance du vendeur (writer-claim) au profit du vendeur et le NFT d'option longue au profit du market maker coté, à condition que ce market maker soit un destinataire éligible lorsque la liste blanche optionnelle des acheteurs est activée. Une signature valide autorise le financement, pas l'exercice.
Seul le détenteur actuel du NFT d'option longue peut appeler l'exercice. Cette règle réservée au détenteur empêche un opérateur ERC-721 de consommer l'allowance en token de règlement du détenteur. Un opérateur approuvé peut toujours transférer le NFT selon les règles standard ERC-721, ce qui transfère le droit économique à un destinataire éligible lorsque le filtre acheteur est activé. Un exercice réussi prélève le montant du strike auprès de l'appelant détenteur, lui livre le sous-jacent et brûle le NFT d'option longue.
Séparateurs de domaine EIP-712
Les trois domaines de directives utilisent la même structure et ne diffèrent que par name. Le verifyingContract est l'adresse nulle, donc une même signature est valide pour n'importe quel Account de la chaîne, et c'est l'adresse de l'Account dans le message qui la lie à un Account unique.
{
"name": "<DomainName>",
"version": "1",
"chainId": <chainId>,
"verifyingContract": "0x0000000000000000000000000000000000000000"
}
Le type de domaine est EIP712Domain(string name,string version,uint256 chainId,address verifyingContract).
Chain IDs : réseau principal 999, testnet 998. L'Account sélectionne le séparateur selon la chaîne sur laquelle il s'exécute, donc une signature testnet n'est jamais vérifiée sur le réseau principal.
| Domaine | name | version | Signataire | Chaîne | Séparateur |
|---|---|---|---|---|---|
| Portefeuille API | HypercallApiSign | 1 | Portefeuille API | 999 | 0x462ae8a3a67da57ddd088e60be368536f992b8bf369d13e64e620c51993e5ebb |
| Portefeuille API | HypercallApiSign | 1 | Portefeuille API | 998 | 0x339bee4c00da9a5361f687797205c8d03f323659f5d9dc9e0505b9437ddee25e |
| Manager | HypercallManagerSign | 1 | Manager | 999 | 0xc9b5b0b8b0d9d7ba716326acbf795cfe431ef960a25a8f958d6569bea2f1516e |
| Manager | HypercallManagerSign | 1 | Manager | 998 | 0xd1f76b6138be892c14b71b0569bdb049cb44f239d34c78ef1ffaacd2466f9f18 |
| RSM | HypercallRsmSign | 1 | Signataire RSM | 999 | 0x3d0cae2af623c614099dbadd67a1e1457fabde576aa270a70a57e39bf338a7be |
| RSM | HypercallRsmSign | 1 | Signataire RSM | 998 | 0x650b282053fb61d3fd477bdc28f6434311fe905e27cc4ca643e87e802c45938c |
Calculez vous-même le séparateur et comparez-le avant de signer quoi que ce soit :
import { ethers } from "ethers";
const separator = ethers.TypedDataEncoder.hashDomain({
name: "HypercallApiSign",
version: "1",
chainId: 999,
verifyingContract: ethers.ZeroAddress
});
// 0x462ae8a3a67da57ddd088e60be368536f992b8bf369d13e64e620c51993e5ebb
Référence des messages
Matrice signataires et endpoints
| Message | Domaine | Signataire | Soumettre à | Exécute |
|---|---|---|---|---|
HLOrder | API | Portefeuille API | POST /v1/tee-perp/orders/submit, ou POST /v1/actions/hl_limit_order | Ordre limite Hyperliquid |
HLCancel | API | Portefeuille API | POST /v1/tee-perp/cancels/submit-by-oid, ou POST /v1/actions/hl_cancel_by_oid | Annulation par oid |
HLCancelByCloid | API | Portefeuille API | POST /v1/tee-perp/cancels/submit, ou POST /v1/actions/hl_cancel_by_cloid | Annulation par cloid |
HCPerpTriggerOrder | API | Portefeuille API | POST /v1/tee-perp/orders/submit-trigger | Ordre déclencheur natif (TEE uniquement) |
HCPerpOrderBatch | API | Portefeuille API | POST /v1/tee-perp/orders/submit-batch | Lot d'ordres natif (TEE uniquement) |
HCPerpLeverageChange | API | Portefeuille API | POST /v1/tee-perp/leverage/submit | Mise à jour du levier (TEE uniquement) |
HCPerpScheduleCancel | API | Portefeuille API | POST /v1/tee-perp/schedule-cancel/submit | Dead-man switch (TEE uniquement) |
HCUpdateApiWallet | Manager | Manager | POST /v1/actions/hc_update_api_wallet | Registre des portefeuilles API de l'Account |
HLAddApiWallet | Manager | Manager | POST /v1/actions/hl_add_api_wallet | Approbation de portefeuille API HyperCore |
HLSendAsset | Manager | Manager | POST /v1/actions/hl_send_asset | sendAsset HyperCore depuis l'Account |
HLSetAbstraction | Manager | Manager | POST /v1/actions/hl_set_abstraction | Mode de compte HyperCore (unifié uniquement) |
HCTransferOption | Manager | Manager | Non accepté | Réservé, rejeté on-chain |
HLOrder, HLCancel, HLCancelByCloid, HLSendAsset | RSM | Signataire RSM | Séquenceur uniquement | Ordres de récupération et balayages via l'Account |
System* | RSM | Signataire RSM | Séquenceur uniquement | Crédits, retraits, liquidation via l'Exchange |
Toutes les routes /v1/actions/{action} acceptent account, nonce, action et signature. POST /v1/actions/{action}/typed-data renvoie les données typées exactes à signer pour cette requête, ce qui est le moyen le plus simple de valider votre encodeur. GET /v1/directives/{directive_id} indique le résultat on-chain. Les schémas de requête se trouvent dans la Référence API.
Conventions de transmission
nonceet tous les champsuint64,uint128ouuint256sont des entiers JSON jusqu'à9007199254740991, ou des chaînes décimales. Utilisez des chaînes au-delà.signatureest une chaîne hexadécimale0xde 65 octets (r || s || v).vpeut valoir0,1,27ou28.- Les champs
bytes32sont en hexadécimal de 32 octets préfixé par0x. Les adresses sont en hexadécimal avec checksum ou en minuscules. - Les prix et tailles perp sont les entiers HyperCore
1e8, par exemple$50,000correspond à5000000000000et0.001coin à100000.
Directives du portefeuille API (HypercallApiSign)
Signées par un portefeuille API actif de l'Account. Utilisez le chain ID 999 et le name HypercallApiSign.
Les vecteurs de test utilisent un compte fictif et un nonce fixe afin que vous puissiez vérifier votre encodeur octet par octet. Le digest est keccak256(0x1901 || domainSeparator || directiveStructHash).
HLOrder
Un ordre limite Hyperliquid pour l'Account.
Structure :
struct LimitOrder {
uint32 asset;
bool isBuy;
uint64 limitPx;
uint64 sz;
bool reduceOnly;
uint8 encodedTif;
uint128 cloid;
}
struct HLOrder {
address account;
uint64 nonce;
LimitOrder action;
}
Type EIP-712 canonique :
HLOrder(address account,uint64 nonce,LimitOrder action)LimitOrder(uint32 asset,bool isBuy,uint64 limitPx,uint64 sz,bool reduceOnly,uint8 encodedTif,uint128 cloid)
Typehash : 0xe6facb816c5f9c321054ef43c7d8fb1ec750f65d630ec39c5c18119a6f4707dd. Signataire : portefeuille API. Action : version 1, id 1.
asset: l'indice d'actif Hyperliquid.GET /v1/tee-perp/marketsliste les marchés perp acceptés par Hypercall et leurs indices.isBuy:truepour acheter,falsepour vendre.limitPx,sz: prix et taille multipliés par1e8.reduceOnly:truesi l'ordre ne peut que réduire une position.encodedTif: ALO =1, GTC =2, IOC =3. Toute autre valeur est rejetée.cloid: identifiant d'ordre client, non nul. Vous l'utilisez ensuite pour annuler par cloid.
Exemple (ethers.js) :
const domain = {
name: "HypercallApiSign",
version: "1",
chainId: 999,
verifyingContract: ethers.ZeroAddress
};
const types = {
LimitOrder: [
{ name: "asset", type: "uint32" },
{ name: "isBuy", type: "bool" },
{ name: "limitPx", type: "uint64" },
{ name: "sz", type: "uint64" },
{ name: "reduceOnly", type: "bool" },
{ name: "encodedTif", type: "uint8" },
{ name: "cloid", type: "uint128" }
],
HLOrder: [
{ name: "account", type: "address" },
{ name: "nonce", type: "uint64" },
{ name: "action", type: "LimitOrder" }
]
};
const message = {
account: managedAccount,
nonce: selectedNonce,
action: {
asset: 0,
isBuy: true,
limitPx: 5000000000000n,
sz: 100000n,
reduceOnly: false,
encodedTif: 2,
cloid: selectedNonce
}
};
const signature = await apiWalletSigner.signTypedData(domain, types, message);
Vecteur de test (compte 0x1111111111111111111111111111111111111111, nonce 1760000000000, chaîne 999) :
| Étape | Valeur |
|---|---|
| Typehash | 0xe6facb816c5f9c321054ef43c7d8fb1ec750f65d630ec39c5c18119a6f4707dd |
| Hash de la structure d'action | 0x0fd024c6bf8f132123e63a78d50008d8c39c52e5409ef6ca87a4eec8f6eabb41 |
| Hash de la structure de directive | 0xd32948ee1f249b96124a6acdb5845d09aad8228512098598de6858d5484fe703 |
| Digest à signer | 0xc3c42699092fe20c7dbc4205a1027f55c28d33a682a64bd3f04e40f1d28693f5 |
Le vecteur de test utilise isBuy: true, limitPx: 5000000000000, sz: 100000, reduceOnly: false, encodedTif: 2, asset: 0, et cloid égal au nonce.
Soumission : POST /v1/tee-perp/orders/submit avec account, nonce, action et signature. Hypercall effectue la vérification de marge, puis une enclave sécurisée signe et envoie l'ordre Hyperliquid natif avec le builder code Hypercall attaché. Le manager de l'Account doit d'abord approuver ce builder avec Account.approveZeroFeeBuilder ; voir Onboarding. Voir Perps pour le flux complet.
{
"account": "0x1111111111111111111111111111111111111111",
"nonce": 1760000000000,
"action": {
"asset": 0,
"isBuy": true,
"limitPx": "5000000000000",
"sz": "100000",
"reduceOnly": false,
"encodedTif": 2,
"cloid": "1760000000000"
},
"signature": "0x<65 byte signature>"
}
Le même message signé est également accepté sur POST /v1/actions/hl_limit_order, qui l'encode en directive on-chain exécutée via Exchange.executeUserDirective et Account.performCoreAction.
HLCancel
Annule un ordre par son identifiant d'ordre Hyperliquid. L'enveloppe est HLCancel et la structure interne est CancelOrderByOid.
struct CancelOrderByOid {
uint32 asset;
uint64 oid; // Order ID assigned by HyperCore
}
struct HLCancel {
address account;
uint64 nonce;
CancelOrderByOid action;
}
HLCancel(address account,uint64 nonce,CancelOrderByOid action)CancelOrderByOid(uint32 asset,uint64 oid)
Typehash : 0x23c5529f34a875b6c0d11a6dfafdd945996dbdc5fbd1bdace2c2e0cf6a253a85. Signataire : portefeuille API. Action : version 1, id 10. Soumission : POST /v1/tee-perp/cancels/submit-by-oid, ou POST /v1/actions/hl_cancel_by_oid.
const types = {
CancelOrderByOid: [
{ name: "asset", type: "uint32" },
{ name: "oid", type: "uint64" }
],
HLCancel: [
{ name: "account", type: "address" },
{ name: "nonce", type: "uint64" },
{ name: "action", type: "CancelOrderByOid" }
]
};
const message = {
account: managedAccount,
nonce: selectedNonce,
action: { asset: 0, oid: 123456789n }
};
const signature = await apiWalletSigner.signTypedData(domain, types, message);
Vecteur de test (compte 0x1111111111111111111111111111111111111111, nonce 1760000000000, chaîne 999) :
| Étape | Valeur |
|---|---|
| Typehash | 0x23c5529f34a875b6c0d11a6dfafdd945996dbdc5fbd1bdace2c2e0cf6a253a85 |
| Hash de la structure d'action | 0xa34e7bb8af0d099f9c48095924e53067bcb9b542a816445b96abebbc5646b727 |
| Hash de la structure de directive | 0x69d560ba5ef3e88459bde7fb8252e55dbc33627373c8f0cfcf8ef0868f59e097 |
| Digest à signer | 0x5046aba9fb33c55ce736faf63734ea66914f3f168ff0aff2229fa6f31fa9b330 |
Le vecteur de test utilise asset: 0 et oid: 123456789.
HLCancelByCloid
Annule un ordre par l'identifiant d'ordre client que vous avez défini sur HLOrder.
struct CancelOrderByCloid {
uint32 asset;
uint128 cloid; // Client order ID
}
struct HLCancelByCloid {
address account;
uint64 nonce;
CancelOrderByCloid action;
}
HLCancelByCloid(address account,uint64 nonce,CancelOrderByCloid action)CancelOrderByCloid(uint32 asset,uint128 cloid)
Typehash : 0x10cbcfa56297fc737e4defee7b7937a52978ebbe5920e584317f7f25416836f5. Signataire : portefeuille API. Action : version 1, id 11. Soumission : POST /v1/tee-perp/cancels/submit, ou POST /v1/actions/hl_cancel_by_cloid.
const types = {
CancelOrderByCloid: [
{ name: "asset", type: "uint32" },
{ name: "cloid", type: "uint128" }
],
HLCancelByCloid: [
{ name: "account", type: "address" },
{ name: "nonce", type: "uint64" },
{ name: "action", type: "CancelOrderByCloid" }
]
};
const message = {
account: managedAccount,
nonce: selectedNonce,
action: { asset: 0, cloid: 1760000000000n }
};
const signature = await apiWalletSigner.signTypedData(domain, types, message);
Vecteur de test (compte 0x1111111111111111111111111111111111111111, nonce 1760000000000, chaîne 999) :
| Étape | Valeur |
|---|---|
| Typehash | 0x10cbcfa56297fc737e4defee7b7937a52978ebbe5920e584317f7f25416836f5 |
| Hash de la structure d'action | 0xfa4ab6440f946a6e279d90972d71223c768c01c8a91dc22703a6448dbcb966d0 |
| Hash de la structure de directive | 0x998efb01bb9c842eea80e8cc084b9e4e7ec13b2111790e1acbfec32e49060d9d |
| Digest à signer | 0x56af82a6aa7fa50907a23c6cfe3aa556af5aa087b1157163ebf6ea0240e8d29d |
Le vecteur de test utilise asset: 0 et cloid: 1760000000000.
Messages perp réservés au TEE
Ces quatre messages sont vérifiés par l'API Hypercall et non par le contrat Account, car l'enclave les exécute nativement sur Hyperliquid et aucune directive on-chain n'existe pour eux. Ils utilisent le même domaine HypercallApiSign et la même autorisation de portefeuille API que HLOrder (le signataire doit être un portefeuille API actif de l'Account, et l'Account doit être en marge de portefeuille). Leurs typehashes ne figurent pas dans les contrats. Les nonces sont un temps Unix en millisecondes.
PerpOrderTerms
HCPerpTriggerOrder et HCPerpOrderBatch intègrent tous deux cette structure. Un ordre enfant limite signe son octet TIF avec triggerPx = 0, isMarket = false, tpsl = 0. Un ordre enfant déclencheur signe encodedTif = 0, un triggerPx positif, et tpsl égal à 1 (take profit) ou 2 (stop loss).
struct PerpOrderTerms {
uint32 asset;
bool isBuy;
uint64 limitPx;
uint64 sz;
bool reduceOnly;
uint8 encodedTif;
uint64 triggerPx;
bool isMarket;
uint8 tpsl;
uint128 cloid;
}
HCPerpTriggerOrder
Un ordre stop-loss ou take-profit, soumis à POST /v1/tee-perp/orders/submit-trigger. Le champ action.orderType de la requête doit être un déclencheur.
struct HCPerpTriggerOrder {
address account;
uint64 nonce;
PerpOrderTerms order;
}
HCPerpTriggerOrder(address account,uint64 nonce,PerpOrderTerms action)PerpOrderTerms(uint32 asset,bool isBuy,uint64 limitPx,uint64 sz,bool reduceOnly,uint8 encodedTif,uint64 triggerPx,bool isMarket,uint8 tpsl,uint128 cloid)
Typehash : 0x2d3104ab255275839aad254429e4be789f64a8d16b8e3e7d5f30a0db3c887b5c
Vecteur de test (compte 0x1111111111111111111111111111111111111111, nonce 1760000000000, chaîne 999) :
| Étape | Valeur |
|---|---|
| Typehash | 0x2d3104ab255275839aad254429e4be789f64a8d16b8e3e7d5f30a0db3c887b5c |
| Hash de la structure d'action | 0x285b3186be219b92d7159419288c0dce9bc4ad7bfc9536e009ebf24bd67f434c |
| Hash de la structure de directive | 0xaa03e40b34b15e7e932ae827921930e7538387b596ef1040dbcc791e69021299 |
| Digest à signer | 0xc46aadc390b66c235af15e199e188ab23fb7f7f1b9237f6c2849c264c28d94da |
Le vecteur de test est une vente stop-loss au marché en reduce-only : asset: 0, isBuy: false, limitPx: 4800000000000 (pire prix), sz: 100000, reduceOnly: true, encodedTif: 0, triggerPx: 4900000000000, isMarket: true, tpsl: 2, cloid: 1760000000001.
HCPerpOrderBatch
Jusqu'à 100 ordres sous un même regroupement, soumis à POST /v1/tee-perp/orders/submit-batch. Chaque ordre doit utiliser un cloid distinct. grouping vaut 0 (aucun regroupement), 1 (normalTpsl) ou 2 (positionTpsl). Un lot compte comme un seul placement d'ordre au regard de la limite de débit.
struct HCPerpOrderBatch {
address account;
uint64 nonce;
uint8 grouping;
PerpOrderTerms[] orders;
}
HCPerpOrderBatch(address account,uint64 nonce,uint8 grouping,PerpOrderTerms[] orders)PerpOrderTerms(uint32 asset,bool isBuy,uint64 limitPx,uint64 sz,bool reduceOnly,uint8 encodedTif,uint64 triggerPx,bool isMarket,uint8 tpsl,uint128 cloid)
Typehash : 0x9d4f467a44f4b0d39f234f3b91888546ce31dcbb67ce791550901b9042c38f8b. Le tableau orders est encodé comme le keccak256 de la concaténation des hashs de structure PerpOrderTerms, dans l'ordre de soumission.
Vecteur de test (compte 0x1111111111111111111111111111111111111111, nonce 1760000000000, chaîne 999) :
| Étape | Valeur |
|---|---|
| Typehash | 0x9d4f467a44f4b0d39f234f3b91888546ce31dcbb67ce791550901b9042c38f8b |
| Hash du tableau d'ordres | 0x13fc75fcc69bf3b4ef7cdc3a0872c3cc1cf59440c74d366055109b6bd5ea7c98 |
| Hash de la structure de directive | 0x69d0b1131e386769823fe1ab3facbe8e6fc013f86a117cf95cb52b8ce2f274e0 |
| Digest à signer | 0x4b5cd34b1f254fdd9881b7674a3412807e16cade1f2ccc7a1e261482682fbd07 |
Le vecteur de test est grouping: 1 avec deux ordres : un achat limite GTC (limitPx: 5000000000000, sz: 100000, cloid: 1760000000000) suivi du stop-loss de l'exemple d'ordre déclencheur.
HCPerpLeverageChange
Définit le levier pour un actif, soumis à POST /v1/tee-perp/leverage/submit. leverage doit être strictement supérieur à zéro.
struct PerpLeverageChange {
uint32 asset;
bool isCross;
uint32 leverage;
}
struct HCPerpLeverageChange {
address account;
uint64 nonce;
PerpLeverageChange action;
}
HCPerpLeverageChange(address account,uint64 nonce,PerpLeverageChange action)PerpLeverageChange(uint32 asset,bool isCross,uint32 leverage)
Typehash : 0xe13845f0e6c16a5e1fc56b2d11fb0972faa2ec30b01e94d58c72147fa9b6a463
Vecteur de test (compte 0x1111111111111111111111111111111111111111, nonce 1760000000000, chaîne 999) :
| Étape | Valeur |
|---|---|
| Typehash | 0xe13845f0e6c16a5e1fc56b2d11fb0972faa2ec30b01e94d58c72147fa9b6a463 |
| Hash de la structure d'action | 0x0e6e271dd56192d7fb1f37ea2eaffecfbbe2d1f79cac78dce6a6930bb8cc253e |
| Hash de la structure de directive | 0xe04b169bbb0e20042308e5aad1036ce60eda75f484a4d6093dc60f2c2231129e |
| Digest à signer | 0xb2a43487152a7cecc73d2b6b84d817a58dd02c559b05289a8d8e1b5c3d25e266 |
Le vecteur de test fixe un levier cross de 5x sur asset: 0.
HCPerpScheduleCancel
Le dead-man switch de Hyperliquid : annule tous les ordres ouverts à time (millisecondes Unix, au moins sept secondes dans le futur). Soumis à POST /v1/tee-perp/schedule-cancel/submit. Pour supprimer une annulation programmée, omettez time dans la requête et signez time = 0. L'envoi explicite de 0 est rejeté.
struct PerpScheduleCancel {
uint64 time;
}
struct HCPerpScheduleCancel {
address account;
uint64 nonce;
PerpScheduleCancel action;
}
HCPerpScheduleCancel(address account,uint64 nonce,PerpScheduleCancel action)PerpScheduleCancel(uint64 time)
Typehash : 0xf21b6881e346bbf4b8d82e8ea507cf487e58dfc08776ad662591be7d6065bdfb
Vecteur de test (compte 0x1111111111111111111111111111111111111111, nonce 1760000000000, chaîne 999) :
| Étape | Valeur |
|---|---|
| Typehash | 0xf21b6881e346bbf4b8d82e8ea507cf487e58dfc08776ad662591be7d6065bdfb |
| Hash de la structure d'action | 0x0a3ebfe48ef28a79beeee4d56e524f8a5280c38562efb697e7b1d63b3d475afc |
| Hash de la structure de directive | 0xae64a13943a6a35b33aeb3095763b855c58c2119daf71e1e3228d8acf2645e8b |
| Digest à signer | 0xa01806f47299010b5963a516562be3c3b44fed4f4a9e2e56c4bb601630146cdc |
Le vecteur de test programme une annulation à time: 1760000060000.
Annulation préparée signée par le manager
POST /v1/tee-perp/cancels/submit-prepared est le chemin d'annulation signé par le manager. Il n'utilise pas de structure de données typées. Le manager signe le digest d'une annulation Hyperliquid native préparée, fournie sous forme de preparedRequest (base64) avec managerSignature en forme canonique low-s, ainsi qu'une authenticationSignature horodatée qui authentifie le portefeuille du manager. Voir la Référence API pour le schéma de la requête.
Directives du manager (HypercallManagerSign)
Signées par le manager de l'Account. Utilisez le chain ID 999 et le name HypercallManagerSign. L'Account exige signer == manager. Soumettez avec POST /v1/actions/{action}.
HCUpdateApiWallet
Ajoute, remplace ou supprime (addr = 0x0) le portefeuille API enregistré sous name sur l'Account.
struct UpdateApiWallet {
bytes32 name; // Wallet label, ASCII left-aligned and zero padded
address addr; // API wallet address, zero to remove
}
struct HCUpdateApiWallet {
address account;
uint64 nonce;
UpdateApiWallet action;
}
HCUpdateApiWallet(address account,uint64 nonce,UpdateApiWallet action)UpdateApiWallet(bytes32 name,address addr)
Typehash : 0x8ebe7d19374200e5dc3ae838db74b370da95bd2b3a8aec9de85d2398dd4a9257. Action : version 0, id 2. Soumission : POST /v1/actions/hc_update_api_wallet avec une action de la forme { "name": "0x...", "addr": "0x..." }.
const domain = {
name: "HypercallManagerSign",
version: "1",
chainId: 999,
verifyingContract: ethers.ZeroAddress
};
const types = {
UpdateApiWallet: [
{ name: "name", type: "bytes32" },
{ name: "addr", type: "address" }
],
HCUpdateApiWallet: [
{ name: "account", type: "address" },
{ name: "nonce", type: "uint64" },
{ name: "action", type: "UpdateApiWallet" }
]
};
const message = {
account: accountAddress,
nonce: selectedNonce,
action: {
name: ethers.encodeBytes32String("trading-bot"),
addr: apiWalletAddress
}
};
const signature = await managerSigner.signTypedData(domain, types, message);
Vecteur de test (compte 0x1111111111111111111111111111111111111111, nonce 1760000000000, chaîne 999) :
| Étape | Valeur |
|---|---|
| Typehash | 0x8ebe7d19374200e5dc3ae838db74b370da95bd2b3a8aec9de85d2398dd4a9257 |
| Hash de la structure d'action | 0x8b6c4a9db102e9d27c9a4069b39ba35e04948129359f0c15cd5103dd101ffce7 |
| Hash de la structure de directive | 0x830e291835ad182f290bc3d2bff09eaf9fd33acfbe44c6ad583218cd1a8232e5 |
| Digest à signer | 0x06589077544af449314db1fa8c7aac2d277cce9e833a04992d88161ede24cbe8 |
Le vecteur de test utilise le name trading-bot (0x74726164696e672d626f74 complété à droite par des zéros) et l'addr 0x2222222222222222222222222222222222222222. Voir Onboarding pour le flux complet du portefeuille API. L'Account émet ApiWalletUpdated(name, addr).
HLAddApiWallet
Approuve un portefeuille API Hyperliquid pour l'Account sur HyperCore.
struct AddApiWallet {
address apiWalletAddress;
string apiWalletName; // An empty name replaces the main API wallet
}
struct HLAddApiWallet {
address account;
uint64 nonce;
AddApiWallet action;
}
HLAddApiWallet(address account,uint64 nonce,AddApiWallet action)AddApiWallet(address apiWalletAddress,string apiWalletName)
Typehash : 0x71c0e0dfbddc3456015249946354324befde42b6851d1c9b26c6a29f2e0b1ac2. Action : version 1, id 9. Soumission : POST /v1/actions/hl_add_api_wallet.
apiWalletName est une string, donc son champ de structure est keccak256(bytes(apiWalletName)). Ethers et viem le font pour vous.
Vecteur de test (compte 0x1111111111111111111111111111111111111111, nonce 1760000000000, chaîne 999) :
| Étape | Valeur |
|---|---|
| Typehash | 0x71c0e0dfbddc3456015249946354324befde42b6851d1c9b26c6a29f2e0b1ac2 |
| Hash de la structure d'action | 0xed32a441b0ee59c0252f5dff3411766289c9c35c19e3152b0b2b204176c2c7cd |
| Hash de la structure de directive | 0xb990a3dfb4e8d96243539f8758b3a55249b217542bb4112f4f88ed67ec516ed9 |
| Digest à signer | 0x584886d020316085de0e0dec16331b8e990558be3e8fd004c47200abbebed518 |
Le vecteur de test utilise l'apiWalletAddress 0x2222222222222222222222222222222222222222 et l'apiWalletName hl-bot.
HLSendAsset
Envoie des actifs depuis l'Account sur HyperCore vers une destination.
struct SendAsset {
address destination; // Recipient
address subAccount; // Recipient sub-account, zero for main
uint32 srcDex; // Source dex: 0 = perps, 4294967295 = spot
uint32 dstDex; // Destination dex: 0 = perps, 4294967295 = spot
uint64 token; // HyperCore token index (0 = USDC)
uint64 amountWei; // Amount in HyperCore wei (USDC: 1e8 per dollar)
}
struct HLSendAsset {
address account;
uint64 nonce;
SendAsset action;
}
HLSendAsset(address account,uint64 nonce,SendAsset action)SendAsset(address destination,address subAccount,uint32 srcDex,uint32 dstDex,uint64 token,uint64 amountWei)
Typehash : 0x7feffdf7e7b191d5d27c2a209ca71c789289da73de203e99546abf9632860595. Action : version 1, id 13. Soumission : POST /v1/actions/hl_send_asset.
const types = {
SendAsset: [
{ name: "destination", type: "address" },
{ name: "subAccount", type: "address" },
{ name: "srcDex", type: "uint32" },
{ name: "dstDex", type: "uint32" },
{ name: "token", type: "uint64" },
{ name: "amountWei", type: "uint64" }
],
HLSendAsset: [
{ name: "account", type: "address" },
{ name: "nonce", type: "uint64" },
{ name: "action", type: "SendAsset" }
]
};
const message = {
account: accountAddress,
nonce: selectedNonce,
action: {
destination: recipientAddress,
subAccount: ethers.ZeroAddress,
srcDex: 0,
dstDex: 0xFFFFFFFF, // spot
token: 0, // USDC
amountWei: 500000000n // 5 USDC
}
};
const signature = await managerSigner.signTypedData(domain, types, message);
Vecteur de test (compte 0x1111111111111111111111111111111111111111, nonce 1760000000000, chaîne 999) :
| Étape | Valeur |
|---|---|
| Typehash | 0x7feffdf7e7b191d5d27c2a209ca71c789289da73de203e99546abf9632860595 |
| Hash de la structure d'action | 0x9b8c0290da19ea1069e14833023c4621a4f043354b36b4f17d4803b1fce6e656 |
| Hash de la structure de directive | 0xa0cb8a72188a61289fc2685c29a424605e0a2ee7b7af3e8cfee10e1c75153e08 |
| Digest à signer | 0x7c7037f27c659a1885f744778480e6847c5d08e98fb22517265ba708b6597d10 |
Le vecteur de test envoie 5 USDC (amountWei: 500000000) des perps (srcDex: 0) vers le spot (dstDex: 4294967295) avec pour destination l'Exchange de production 0xE6b7FaA216cabb2b38B392f577C9c826378b2240.
HLSetAbstraction
Définit le mode de compte HyperCore de l'Account. L'Account n'accepte que user égal à lui-même et abstraction = 2 (compte unifié) ; toute autre valeur provoque un revert. La marge de portefeuille (Portfolio Margin) l'exige.
struct SetAbstraction {
address user; // Must equal the Account
uint8 abstraction; // Must be 2 (unified account)
}
struct HLSetAbstraction {
address account;
uint64 nonce;
SetAbstraction action;
}
HLSetAbstraction(address account,uint64 nonce,SetAbstraction action)SetAbstraction(address user,uint8 abstraction)
Typehash : 0xcf5fddf081e5f2a9a45aa87cb1a3c42e5aa20164566b1ad2369b6b1318eac786. Action : version 1, id 16. Soumission : POST /v1/actions/hl_set_abstraction.
Vecteur de test (compte 0x1111111111111111111111111111111111111111, nonce 1760000000000, chaîne 999) :
| Étape | Valeur |
|---|---|
| Typehash | 0xcf5fddf081e5f2a9a45aa87cb1a3c42e5aa20164566b1ad2369b6b1318eac786 |
| Hash de la structure d'action | 0xef6c70a3c14b9e77c710c6b3b3ee681ca270ef884bd8a64fa4064a96f3dda84e |
| Hash de la structure de directive | 0xdda9d0fe82b63c728c4ac42585d5998a04cabaed0f957a2cafdf31a754829c3d |
| Digest à signer | 0xf49d7d8d74596e503d6a1bdfb26653533a12a5ba3816acd992d0bd4ef378f59d |
Le vecteur de test définit user sur l'Account et abstraction à 2.
HCTransferOption (réservé)
Les contrats définissent HCTransferOption(address account,uint64 nonce,TransferOption action)TransferOption(address recipient,address option,uint256 amountWei) (typehash 0xa218e1158788b23987f954edc7a07659a03a03fe5ba981a5bbe44d7a146e0819, version d'action 0, id 1), mais aucun type de signataire ne lui est attribué. L'Account effectue un revert avec Account__UserDirectiveNotSupported, et l'API rejette hc_transfer_option. Ne le signez pas. Déplacez les tokens d'option avec depositOption et les retraits à la place.
Transactions du manager sans signature
Certaines actions du manager sont des appels directs à l'Account, et non des messages EIP-712 : Account.approveZeroFeeBuilder(builder) approuve un builder Hyperliquid avec des frais maximum de 0 % et doit être appelé une fois avant le premier ordre perp (voir Onboarding). Account.transferTo(recipient, token, amount) transfère des tokens hors de l'Account sur HyperEVM. Les deux exigent msg.sender == manager et effectuent un revert tant que l'Account est en liquidation.
Directives RSM (HypercallRsmSign)
Signées par le signataire RSM et soumises par le séquenceur. Elles créditent les dépôts, traitent les retraits, démarrent et arrêtent les liquidations, et placent des ordres de récupération IOC reduce-only. Les market makers et les utilisateurs ne les signent ni ne les soumettent ; elles sont documentées afin que vous puissiez vérifier ce que le protocole peut faire à un Account. Utilisez le chain ID 999 et le name HypercallRsmSign. L'Exchange vérifie signer == rsmSigner (actuellement 0x502E7fAbF34E84EeB115C34FE947b79A94dF886E sur le réseau principal) et l'appelant doit détenir le SEQUENCER_ROLE.
Ordres et balayages RSM (exécutés par l'Account)
Ils réutilisent les structures HL sous le domaine RSM, donc les typehashes sont identiques à ceux de l'API et du manager, seul le séparateur de domaine diffère. L'Account applique des contraintes supplémentaires et les exécute même pendant une liquidation.
| Message | Typehash | Contrainte appliquée par l'Account |
|---|---|---|
HLOrder | 0xe6facb816c5f9c321054ef43c7d8fb1ec750f65d630ec39c5c18119a6f4707dd | encodedTif doit être IOC (3), et l'ordre doit être reduceOnly, ou une vente spot contre USDC (identifiants d'actifs spot de 10000 à 99999) limitée à 5 % au plus sous le prix spot HyperCore |
HLCancel | 0x23c5529f34a875b6c0d11a6dfafdd945996dbdc5fbd1bdace2c2e0cf6a253a85 | Aucune |
HLCancelByCloid | 0x10cbcfa56297fc737e4defee7b7937a52978ebbe5920e584317f7f25416836f5 | Aucune |
HLSendAsset | 0x7feffdf7e7b191d5d27c2a209ca71c789289da73de203e99546abf9632860595 | destination doit être l'Exchange |
Vecteur de test RSM HLOrder (compte 0x1111111111111111111111111111111111111111, nonce 1760000000000, chaîne 999) :
| Étape | Valeur |
|---|---|
| Typehash | 0xe6facb816c5f9c321054ef43c7d8fb1ec750f65d630ec39c5c18119a6f4707dd |
| Hash de la structure d'action | 0x39b4e0699f382aaad23f04740034e7c5581ba918139d2db63fbf586cc447e7db |
| Hash de la structure de directive | 0xe6dde5ad6d310b5ebb83c09ec28ee5568700473b885bb483b7437dca202af4f3 |
| Digest à signer | 0x57afa1e810804e768c05a467aa88ede15fdceedae5aaa840adff61a613aca469 |
Le vecteur RSM HLOrder est une vente IOC reduce-only (isBuy: false, limitPx: 4800000000000, sz: 100000, reduceOnly: true, encodedTif: 3, cloid égal au nonce). Exchange.executeRsmDirective vérifie la signature et transmet l'action à l'Account.
Actions système (exécutées par l'Exchange)
Version 255. Chaque enveloppe est de la forme System<Action>(address account,uint64 nonce,<Action> action)<Action>(...).
| Enveloppe | Type interne | Typehash |
|---|---|---|
SystemCreditToken | CreditToken(uint32 srcDex,uint32 dstDex,uint64 token,uint64 amountWei) | 0xe845f2049264182802994dae939dc8ac42d3ae543a7eeb530dd021428743f052 |
SystemCreditOption | CreditOption(bytes32 underlying,uint256 expiry,uint256 strike,bool isCall,uint256 amountWei) | 0x65aedd5af06882e1e62d752b43b72ec62a85cacf2ca59e8ec2affc57eed9d8ae |
SystemStartLiquidation | StartLiquidation(int256 equity,uint256 marginNeeded) | 0x92b6a135a656e489c24fb5511684842b0ab3895c22b51e4910dee90a7d23511e |
SystemStopLiquidation | StopLiquidation(uint256 startTime) | 0xe1af98778e9cfd1d1a679bb0b64b6dc8aa3fb152ff6469d0a81a1c7eb87a4bd3 |
SystemWithdrawToken | WithdrawToken(address destination,address subAccount,uint32 srcDex,uint32 dstDex,uint64 token,uint64 amountWei) | 0x634b866e9a922bb846e297973c7a456e641b88f4e97493da9b222084d799c883 |
Chaînes de type externes complètes :
SystemCreditToken(address account,uint64 nonce,CreditToken action)CreditToken(uint32 srcDex,uint32 dstDex,uint64 token,uint64 amountWei)
SystemCreditOption(address account,uint64 nonce,CreditOption action)CreditOption(bytes32 underlying,uint256 expiry,uint256 strike,bool isCall,uint256 amountWei)
SystemStartLiquidation(address account,uint64 nonce,StartLiquidation action)StartLiquidation(int256 equity,uint256 marginNeeded)
SystemStopLiquidation(address account,uint64 nonce,StopLiquidation action)StopLiquidation(uint256 startTime)
SystemWithdrawToken(address account,uint64 nonce,WithdrawToken action)WithdrawToken(address destination,address subAccount,uint32 srcDex,uint32 dstDex,uint64 token,uint64 amountWei)
- SystemCreditToken crédite l'Account de tokens spot ou perp depuis HyperCore.
amountWeidoit être non nul et l'Account doit être activé sur HyperCore. - SystemCreditOption émet des tokens d'option au profit de l'Account, en déployant la paire d'options si nécessaire.
underlyingest un mot OpenZeppelinShortString: ASCII aligné à gauche avec la longueur en octets dans le dernier octet (BTCvaut0x42544300...03). Les encodages non canoniques provoquent un revert. - SystemStartLiquidation enregistre les paramètres d'enchère et verrouille l'Account.
marginNeededdoit être non nul. - SystemStopLiquidation exige que
startTimesoit égal au début enregistré et rend l'Account à son manager. - SystemWithdrawToken met en file d'attente une livraison de Standard USDC sur HyperCore depuis le solde propre de l'Exchange. Il exige
subAccount = 0,srcDex = 0, undstDexégal à0ou4294967295,token = 0(USDC), et unamountWeimultiple entier de l'unité EVM. Un reçu HyperEVM seul ne prouve pas la livraison sur HyperCore.
Vecteur de test SystemCreditToken (compte 0x1111111111111111111111111111111111111111, nonce 1760000000000, chaîne 999) :
| Étape | Valeur |
|---|---|
| Typehash | 0xe845f2049264182802994dae939dc8ac42d3ae543a7eeb530dd021428743f052 |
| Hash de la structure d'action | 0xc69d7c6e5c36c9789d990c6316eaff3be43980583806f41f8a8e6461b7114011 |
| Hash de la structure de directive | 0x7ffa37cef7e08d3a2dd5501a8648899d37bc09ebb25d148c124e12c5047476e1 |
| Digest à signer | 0x95f75e5ddb4837de3f578b8aa0d714d4b02672b18c4929e3d2dda4a266de8254 |
Le vecteur crédite 5 USDC (srcDex et dstDex égaux à 4294967295, token: 0, amountWei: 500000000).
Vecteur de test SystemCreditOption (compte 0x1111111111111111111111111111111111111111, nonce 1760000000000, chaîne 999) :
| Étape | Valeur |
|---|---|
| Typehash | 0x65aedd5af06882e1e62d752b43b72ec62a85cacf2ca59e8ec2affc57eed9d8ae |
| Hash de la structure d'action | 0x4a8b563fc94d26c1da376145d5aa5d05f996232fcf9739ed0a662650e91861b6 |
| Hash de la structure de directive | 0x190b638f1a462469bf0d070248acfc86bbbb95ea8a9d3d97d33581c7d6bb5554 |
| Digest à signer | 0x86fb7c53bb7e139a4d5df7db2feae40e634efe09ea7509165d3cece75d75fce2 |
Le vecteur crédite un call BTC (underlying: 0x42544300...03, expiry: 1761811200, strike: 80000, isCall: true, amountWei: 1000000000000000000).
Vecteur de test SystemStartLiquidation (compte 0x1111111111111111111111111111111111111111, nonce 1760000000000, chaîne 999) :
| Étape | Valeur |
|---|---|
| Typehash | 0x92b6a135a656e489c24fb5511684842b0ab3895c22b51e4910dee90a7d23511e |
| Hash de la structure d'action | 0x4cd6a7f0997eba84ef82eabd429a0d9ca80e55bd6d89d2e67eda9970d87ec803 |
| Hash de la structure de directive | 0x84f18dc2577978d7890c9eb269fd787d99de37039b3a08e24745398feffbd0c5 |
| Digest à signer | 0xcc72c0e7829938c9ca0a4515d759f94cc96d2f24cd51a134a430f215ed5f5d4b |
Le vecteur utilise equity: -1500000000 et marginNeeded: 20000000000 (tous deux en USDC à six décimales).
Vecteur de test SystemStopLiquidation (compte 0x1111111111111111111111111111111111111111, nonce 1760000000000, chaîne 999) :
| Étape | Valeur |
|---|---|
| Typehash | 0xe1af98778e9cfd1d1a679bb0b64b6dc8aa3fb152ff6469d0a81a1c7eb87a4bd3 |
| Hash de la structure d'action | 0x1d900a795b328bd5fa734bd6d7f74634b98ca66eb5e45322fb1ba6400564b62b |
| Hash de la structure de directive | 0x977b9becdd26830f2cdf70ab40f72f24490fe6ed45822d1fc8c84120e9a46f40 |
| Digest à signer | 0xbe65f82782b14dba42e334e32dd7dcc6bf14c96824523723a186a7381f8f12af |
Le vecteur utilise startTime: 1760000000.
Vecteur de test SystemWithdrawToken (compte 0x1111111111111111111111111111111111111111, nonce 1760000000000, chaîne 999) :
| Étape | Valeur |
|---|---|
| Typehash | 0x634b866e9a922bb846e297973c7a456e641b88f4e97493da9b222084d799c883 |
| Hash de la structure d'action | 0x10bd8d4372a09e613a6b4fb7018fcccde857ebf6cc3327d6c9a3c0f81515a076 |
| Hash de la structure de directive | 0x86680427965513c65a7a170730b9f4fb2e2b40e22cd18338cb004b6a7872ada2 |
| Digest à signer | 0x65cc392038decb9ccdc23b0a4a1cfbe657d3417f8cd9ebf2319b3172fb7d885c |
Le vecteur retire 5 USDC (amountWei: 500000000) vers la destination 0x1111111111111111111111111111111111111111 avec srcDex: 0, dstDex: 0, token: 0.
Nonces
Chaque signataire dispose d'un espace de nonces indépendant, suivi à trois endroits.
- Contrat Account : un bitmap par signataire.
Account.isNonceUsed(signer, nonce)indique si un nonce a été consommé. Une directive utilisateur effectue un revert avecAccount__NonceAlreadyUseden cas de réutilisation. Il n'existe pas denextNonce; les trous sont autorisés et l'ordre n'a pas d'importance on-chain. - Contrat Exchange : un bitmap pour le signataire RSM, consultable avec
Exchange.isNonceUsed(signer, nonce). - Moteur : conserve les 100 nonces les plus élevés par signataire. Un nouveau nonce ne doit pas figurer dans cet ensemble, doit dépasser le plus petit nonce stocké une fois l'ensemble plein, et doit se situer strictement entre deux jours avant et un jour après l'heure du serveur en millisecondes.
Utilisez l'heure Unix actuelle en millisecondes comme base du nonce et incrémentez-la par signataire. Deux requêtes signées par le même portefeuille dans la même milliseconde nécessitent des nonces distincts, donc tenez un compteur. Pour les routes perp TEE, le nonce sert aussi d'ancre temporelle de la requête : utilisez donc de vrais horodatages en millisecondes plutôt que de petits entiers.
function isNonceUsed(address signer, uint256 nonce) external view returns (bool);
Flux de vérification des signatures
- Hors chaîne : le signataire construit le digest EIP-712 (
0x1901 || domainSeparator || structHash) et le signe. - API : Hypercall récupère le signataire, vérifie qu'il s'agit d'un portefeuille API actif ou du manager, effectue la vérification de marge du moteur pour les ordres, puis met la directive en file d'attente. La réponse indique l'étape réelle, les détails d'un éventuel rejet et le hash de transaction.
- Séquenceur : soumet
Exchange.executeUserDirective(directive, signature). L'Exchange vérifie que l'Account existe et transmet àAccount.executeUserDirective. - Account : reconstruit le digest à partir de sa propre adresse, du nonce et de l'action, récupère le signataire avec le séparateur API ou manager correspondant à cette action, vérifie l'autorisation, consomme le nonce, puis exécute. Les actions HL vont au CoreWriter de HyperCore. Les actions HC mettent à jour le registre des portefeuilles API.
- Client : interroge
GET /v1/directives/{directive_id}pour obtenir le statut final.
Les routes perp TEE s'arrêtent après l'étape API : c'est l'enclave, et non l'Account, qui exécute l'ordre sur Hyperliquid.
Example (HLOrder):
1. API wallet signs HLOrder with the managed account, a unique nonce, and one LimitOrder action
2. Client posts account, nonce, action, and signature to /v1/tee-perp/orders/submit
3. Hypercall recovers the API wallet and applies portfolio-margin admission
4. The enclave signs and sends the native Hyperliquid order with the Hypercall builder code
5. Client reads the stage from the response and polls for subsequent status
Éléments obsolètes et supprimés
Ces éléments figuraient dans des versions antérieures de cette page et ne font plus partie du système déployé. Ils sont listés afin que les intégrations qui en dépendent puissent être migrées.
- Encodage Processor et ActionCaster. Le contrat
Processoret l'encodage des messages ActionCaster ont été supprimés dans Exchange0.2.0(février 2026). Les directives Account passent désormais parExchange.executeUserDirectiveet le CoreWriter. L'Exchange0.6.1déployé ne possède aucun des anciens points d'entrée. - Points d'entrée de l'Exchange avec leurs propres structures.
hlRequestOrder,hlRequestCancel,hlRequestCancelByCloid,hlActionSendAsset,hcActionWithdrawToken,hcActionWithdrawOption,rsmCommandRebalanceetrsmCommandRepayn'existent plus. Leurs remplaçants :
| Message supprimé | Remplacement |
|---|---|
HLRequestCancel (lot de HLCancel{asset,oid} plus nonce) | HLCancel avec un CancelOrderByOid par directive |
HLRequestCancelByCloid | HLCancelByCloid avec un CancelOrderByCloid par directive |
HLActionSendAsset (account, nonce, destination, srcDex, dstDex, token, amountWei) | HLSendAsset avec SendAsset, qui ajoute subAccount |
HCActionWithdrawToken | SystemWithdrawToken signé par le RSM, exécuté par le séquenceur après approbation du retrait par le moteur |
HCActionWithdrawOption | Les crédits d'options sont des SystemCreditOption RSM ; les dépôts utilisent depositOption |
RsmCommandRebalance | HLOrder signé par le RSM (IOC reduce-only) |
RsmCommandRepay | HLSendAsset signé par le RSM vers l'Exchange |
- Anciennes fonctions d'ordres.
placeCoreOrders,cancelCoreOrdersetcancelCoreOrdersByCloidutilisaient un encodage MsgPack et le domaineCoreSignatures("Exchange", chain ID1337). Elles sont supprimées. nextNonce. Le compteur on-chainnextNonce[signer]n'existe plus. Seul le bitmap des nonces utilisés (isNonceUsed) subsiste.- Séparateurs du réseau principal marqués TBD. Le texte précédent indiquait les séparateurs du réseau principal pour le manager et le RSM comme TBD. Les trois sont fixés et listés ci-dessus.
HCTransferOption. Défini mais jamais activé ; voir ci-dessus.
Considérations de sécurité
- Clés : conservez la clé du manager sur un portefeuille matériel. Les portefeuilles API ne signent que les ordres et les annulations ; utilisez des clés distinctes pour chaque système.
- Rejeu de nonce : ne réutilisez jamais un nonce. Suivez les nonces hors chaîne et incrémentez-les de manière atomique.
- Domaine : signez toujours avec le chain ID
999sur le réseau principal (998sur testnet), et comparez le séparateur que vous calculez au tableau ci-dessus. - Vérifiez ce que vous signez : appelez
POST /v1/actions/{action}/typed-dataet comparez le résultat avec votre propre encodeur avant de signer avec un portefeuille matériel. - La vérification on-chain fait foi : l'API pré-vérifie les signatures, mais l'Account revérifie chaque directive on-chain. Ne considérez pas un accusé de réception de l'API comme une exécution.
- Manager ou portefeuille API : les managers contrôlent la propriété, les portefeuilles API et les mouvements d'actifs. Les portefeuilles API ne signent que des messages de trading. Utilisez des clés distinctes.
Références
- Onboarding pour la création d'un Account et la configuration du portefeuille API
- Vue d'ensemble des contrats pour les adresses déployées et les types de directives
- Perps pour le flux des ordres perp
- Authentification et signature pour la signature des ordres d'options