Bu sayfa otomatik olarak çevrilmiştir. İngilizce orijinal kanonik versiyondur. İngilizce oku →
Ana içeriğe geç

Kimlik Doğrulama ve İmzalama

Yazma işlemleri için EIP-712 imza gereksinimleri.

Üretim imzalama domain'i

Üretim ortamı için chain ID 999 kullanın. Testnet, Hypercall daha fazla testnet HYPE edinene kadar geçici olarak devre dışıdır.

Genel Bakış​

Tüm yazma işlemleri EIP-712 tipli veri imzası gerektirir. İmzalayan taraf şunlardan biri olmalıdır:

  1. Cüzdan adresinin kendisi (doğrudan imzalama), VEYA
  2. Cüzdan için yetkilendirilmiş bir ajan (bkz. Ajan yetkilendirmesi)

EIP-712 Domain​

Domain ayırıcı:

{
"name": "Hypercall",
"version": "1",
"chainId": 999,
"verifyingContract": "0x0000000000000000000000000000000000000000"
}

Chain ID: 999 (üretim)

Mesaj Türleri​

PlaceOrder​

Açık route içeren struct:

struct PlaceOrder {
address wallet;
string symbol;
string side;
string size;
string price;
string tif;
string route;
string clientId;
uint64 nonce;
}

Route belirtilmediğinde kullanılan struct:

struct PlaceOrder {
address wallet;
string symbol;
string side;
string size;
string price;
string tif;
string clientId;
uint64 nonce;
}

Alan gereksinimleri:

  • wallet: Cüzdan adresi (0x önekli hex string)
  • symbol: Opsiyon sembolü (ör. "BTC-20250131-100000-C")
  • side: "Buy" veya "Sell" (birebir string eşleşmesi gerekir)
  • size: String olarak büyüklük (ör. "0.1") - JSON'da gönderilen değerle BİREBİR eşleşmelidir
  • price: String olarak fiyat (ör. "100.0") - JSON'da gönderilen değerle BİREBİR eşleşmelidir
  • tif: Time-in-force: "gtc", "ioc" veya "fok" (birebir string eşleşmesi gerekir)
  • route: İsteğe bağlı emir yönlendirmesi: "best_execution" veya "book_only" (mevcutsa birebir string eşleşmesi gerekir). POST /bulk_order yalnızca "book_only" kabul eder. "rfq_only" imzalanan sözlüğün bir parçasıdır ancak şu anda tüm emir endpoint'leri bunu reddeder; RFQ ile işlem için RFQ endpoint'lerini kullanın.
  • clientId: İstemci tarafından verilen emir ID'si (string, boş "" olabilir)
  • nonce: Milisaniye zaman damgası nonce'u (uint64), imzalayan başına benzersiz. Bkz. Nonce Yönetimi

Kritik: price ve size, hem imzalanan mesajda hem de JSON istek gövdesinde string OLMALIDIR. String biçimlendirmesi birebir eşleşmelidir.

Varsayılan route: route gönderin. Bu alanı içermeyen bir emir yine kabul edilir ve best_execution olarak yönlendirilir, ancak POST /order yanıtında Deprecation, Sunset ve Warning başlıkları döner ve yayımlanan sunset tarihi (4 Temmuz 2026) geçmiştir. Route içermeyen biçim, ek bir geçiş süresi tanınmadan kaldırılabilir. JSON'da route alanını çıkarırsanız, tipli veriden de çıkarın.

PlaceOrderReduceOnly​

Yalnızca pozisyon azaltan bir emir (JSON gövdesinde "reduce_only": true) ayrı bir struct imzalar. Açık bir route gerektirir.

struct PlaceOrderReduceOnly {
address wallet;
string symbol;
string side;
string size;
string price;
string tif;
string route;
string clientId;
bool reduceOnly;
uint64 nonce;
}

reduceOnly değeri true olmalı ve istek gövdesiyle eşleşmelidir. İmzalı bir route içermeyen reduce-only emir missing_field hatasıyla reddedilir.

ReplaceOrder​

PUT /order ve PUT /bulk_order içindeki her giriş bir ReplaceOrder imzalar. Bu struct'ta route alanı yoktur; JSON gövdesindeki route anahtarı yok sayılır.

struct ReplaceOrder {
address wallet;
string orderId;
string symbol;
string side;
string size;
string price;
string tif;
string clientId;
uint64 nonce;
}

orderId, değiştirilen emrin ondalık string karşılığıdır. Reduce-only bir değiştirme ("reduce_only": true), clientId ile nonce arasına bool reduceOnly ekleyen ReplaceOrderReduceOnly struct'ını imzalar. TypeScript SDK her iki tip haritasını da dışa aktarır.

CancelOrder​

Struct:

struct CancelOrder {
address wallet;
string orderId;
uint64 nonce;
}

Alan gereksinimleri:

  • wallet: Cüzdan adresi
  • orderId: String olarak emir ID'si (ör. "123")
  • nonce: Benzersiz nonce

CancelOrderByClientId​

Struct:

struct CancelOrderByClientId {
address wallet;
string clientId;
uint64 nonce;
}

Alan gereksinimleri:

  • wallet: Cüzdan adresi
  • clientId: İstemci emir ID'si (string)
  • nonce: Benzersiz nonce

ApproveAgent​

Struct:

struct ApproveAgent {
address agent;
uint64 nonce;
}

Alan gereksinimleri:

  • agent: Yetkilendirilecek ajan cüzdan adresi
  • nonce: Benzersiz nonce

Not: Ajanı yetkilendiren cüzdan, geri elde edilen imzadan türetilir.

RevokeAgent​

Struct:

struct RevokeAgent {
address agent;
uint64 nonce;
}

Alan gereksinimleri:

  • agent: Yetkisi kaldırılacak ajan cüzdan adresi
  • nonce: Benzersiz nonce

RevokeAllAgents​

DELETE /revoke-all-agents, imzalayan cüzdana ait tüm ajanları kaldırır.

struct RevokeAllAgents {
uint64 nonce;
}

Risk simülasyonu​

POST /risk/simulate/portfolio ve POST /risk/simulate/orders, herkese açık ve salt okunur engine-authority istekleridir. İmza, kimlik doğrulama veya nonce gerektirmezler. wallet alanı, değerlendirilecek hesap snapshot'ını seçer.

Portföy isteği örneği:

curl -X POST https://api.hypercall.xyz/risk/simulate/portfolio \
-H 'Content-Type: application/json' \
-d '{
"wallet": "0x1111111111111111111111111111111111111111",
"add_positions": true,
"positions": [
{"symbol": "BTC-20261231-100000-C", "quantity": "1.25"}
]
}'

Atomik emir isteği örneği:

curl -X POST https://api.hypercall.xyz/risk/simulate/orders \
-H 'Content-Type: application/json' \
-d '{
"wallet": "0x1111111111111111111111111111111111111111",
"execution_mode": "atomic",
"hypothetical_open_orders": [
{"symbol": "BTC-PERP", "side": "Buy", "size": "0.1", "price": "100000", "reduce_only": false}
],
"orders": [
{"symbol": "BTC-20261231-100000-C", "side": "Buy", "size": "1", "price": "4200", "reduce_only": false},
{"symbol": "BTC-20261231-120000-C", "side": "Sell", "size": "1", "price": "1800", "reduce_only": false}
]
}'

hypothetical_open_orders isteğe bağlıdır. Girişleri, defterde bekleyen GTC emirler olarak ele alınır ve orders öncesinde dizi sırasıyla tek tek kabul edilir. Yalnızca bu istek için, hesabın yetkili canlı açık emirleri ve aktif rezervasyonlarıyla birlikte değerlendirilirler. Engine durumu değiştirilmez. Başarılı bir simülasyonda simulated ve delta, varsayımsal dizinin tamamını ve önerilen bekleyen emri ya da atomik paketi içerir. İki emir dizisi toplamda en fazla 50 giriş içerebilir.

Simülasyon yanıtları birer snapshot'tır, gerçekleşme garantisi değildir. Yönlendirme, RPI erişilebilirliği, eşleştirme, nonce kabulü ve gelecekteki işlem durdurma durumu simüle edilmez. Engine durumu ilerledikçe sonraki gerçek bir emir farklı sonuçlanabilir.

İmzalama Süreci​

Adım 1: Mesajı Oluşturun​

Açık route içeren PlaceOrder örneği:

const message = {
wallet: "0x1111111111111111111111111111111111111111",
symbol: "BTC-20250131-100000-C",
side: "Buy",
size: "0.1", // MUST be string
price: "100.0", // MUST be string
tif: "gtc",
route: "best_execution",
clientId: "mm-1",
nonce: Date.now() // current ms epoch; send this exact value in the body
};

Adım 2: Domain'i Tanımlayın​

const domain = {
name: "Hypercall",
version: "1",
chainId: 999,
verifyingContract: "0x0000000000000000000000000000000000000000"
};

Adım 3: Tipli Veriyi İmzalayın​

ethers.js v6 kullanarak (v5'te metot adı _signTypedData'dır):

const signature = await signer.signTypedData(domain, {
PlaceOrder: [
{ name: "wallet", type: "address" },
{ name: "symbol", type: "string" },
{ name: "side", type: "string" },
{ name: "size", type: "string" },
{ name: "price", type: "string" },
{ name: "tif", type: "string" },
{ name: "route", type: "string" },
{ name: "clientId", type: "string" },
{ name: "nonce", type: "uint64" }
]
}, message);

Adım 4: İsteği Gönderin​

Kritik: JSON istek gövdesi, price ve size için birebir aynı string değerleri kullanmalıdır:

const body = {
wallet: message.wallet,
symbol: message.symbol,
price: message.price, // same string as signed
size: message.size, // same string as signed
side: message.side,
tif: message.tif,
route: message.route,
client_id: message.clientId,
nonce: message.nonce, // same value as signed
signature
};

Nonce Yönetimi​

Gereksinimler:

  • Nonce'lar, milisaniye cinsinden sunucu saatinin kesinlikle iki gün öncesi ile bir gün sonrası arasında olmalıdır; bu nedenle milisaniye cinsinden güncel Unix zamanını kullanın. 1 veya 123 gibi küçük sayaçlar reddedilir.
  • Nonce'lar imzalama anahtarı başına takip edilir. Emirler ve iptallerde, imzayı bir ajan atıyorsa bu anahtar ajanınkidir; ajan onayı ve yetki kaldırmada ise sahip cüzdanınkidir.
  • Bir nonce yeniden kullanılamaz. Emir nonce'ları POST /order, toplu emirler ve WebSocket PlaceOrder arasında ortaktır; bir kanalda kullanılan nonce başka bir kanalda yeniden kullanılamaz.
  • Boşluklara izin verilir. Engine, imzalayan başına en son 100 nonce'u tutar ve 100'e ulaştığında yeni nonce, tutulan en küçük nonce'tan büyük olmalıdır.

En iyi uygulamalar:

  • Başlangıç değerini milisaniye epoch zamanından alın ve imzalayan başına son nonce'u kalıcı olarak saklayarak max(now_ms, last + 1) döndürün
  • Aynı anahtarla imza atan tüm süreçlerde tek bir nonce üreticisi paylaşın
  • Bir istek başarısız olursa, yeni bir nonce ile tekrar imzalayın

Ajan Yetkilendirmesi​

İmzalama için bir ajan cüzdanı kullanıyorsanız:

  1. Ajanı onaylayın (tek seferlik):

    POST /approve-agent
    {
    "agent": "0x...",
    "nonce": 1791273600000,
    "signature": "0x..." # Signed by wallet owner
    }
  2. Emirleri ajan cüzdanıyla imzalayın:

    • PlaceOrder / CancelOrder mesajlarını imzalamak için ajan cüzdanını kullanın
    • wallet alanını işlem yapılan cüzdan adresine ayarlayın
    • Middleware, ajanın o cüzdan için yetkili olduğunu doğrular

Ajan yetkilendirmesinin tüm ayrıntıları için Ajan yetkilendirmesi sayfasına bakın.

Perp Emirleri​

Perp emirleri yukarıdaki Hypercall domain'ini kullanmaz. Bunlar, Hypercall Hesabınıza kayıtlı bir API cüzdanı tarafından HypercallApiSign domain'inde (chain ID 999, sıfır verifying contract) bir HLOrder olarak imzalanır. Struct ve birimler için EIP-712 İmzalama sayfasına bakın.

TEE yolu API üzerinden isteğe bağlıdır: TEE endpoint'lerini çağırarak bu yolu seçersiniz. Hypercall uygulamasında ise varsayılandır. Kullanmak için imzalı emri account, nonce, action ve signature ile birlikte POST /v1/tee-perp/orders/submit adresine gönderin. Hypercall teminat kontrolünü yapar, ardından güvenli bir enclave Hesabınız için yerel Hyperliquid emrini imzalayıp gönderir. Her perp emri %0 ücretli Hypercall builder kodunu taşır; bu nedenle Hesap yöneticisinin ilk emirden önce bu builder'ı bir kez onaylaması gerekir (uygulamadaki Enable trading adımı). Onay olmadan emir builder_not_approved hatasıyla reddedilir. Akış için Perps, istek ve yanıt şeması için API Referansı sayfalarına bakın.

Hyperliquid'in kendi Exchange domain'i (chain ID 1337, MessagePack Agent payload'ları) Hypercall API tarafından kabul edilmez.

Yaygın Hatalar​

unauthorized (HTTP 401): "Signer 0x... is not authorized to act for wallet 0x..."​

EIP-712 geri elde etme işlemi her zaman bir adres üretir. İmzaladığınız herhangi bir şey gönderdiğinizden farklıysa, geri elde edilen adres sizin anahtarınız olmaz ve istek bir imza hatası yerine burada başarısız olur.

Nedenler:

  1. price veya size string biçimlendirmesi imzalama ile gönderme arasında değişti (ör. "100.0" ile "100")
  2. İmzalanan bir alan JSON gövdesinden farklı (route, clientId/client_id, nonce, tif), ya da route imzalandı ancak gövdede yok, veya tam tersi
  3. Yanlış domain (chain ID, name, version, verifying contract)
  4. İstek için yanlış struct (örneğin PUT /order için ReplaceOrder yerine PlaceOrder)
  5. İmzalayan gerçekten ne cüzdanın kendisi ne de onaylı bir ajan. Ajanı POST /approve-agent ile onaylayın veya doğrudan cüzdanla imzalayın

Mesaj tanımadığınız bir imzalayan adresi gösteriyorsa, neden 1 ile 4 arasındakilerden biridir.

signature_verification_failed (HTTP 400)​

Neden: İmza hiç çözümlenemedi veya geri elde edilemedi; örneğin uzunluk yanlış ya da hex geçersiz.

invalid_parameter (HTTP 400): "price must be provided as a string for signature verification"​

Neden: price veya size JSON sayısı olarak gönderildi. Her ikisini de string olarak gönderin.

Uygulama Örnekleri​

Python (eth_account 0.10 veya üzeri)​

import time

from eth_account import Account
from eth_account.messages import encode_typed_data

domain = {
"name": "Hypercall",
"version": "1",
"chainId": 999,
"verifyingContract": "0x0000000000000000000000000000000000000000"
}

message = {
"wallet": "0x1111111111111111111111111111111111111111",
"symbol": "BTC-20250131-100000-C",
"side": "Buy",
"size": "0.1",
"price": "100.0",
"tif": "gtc",
"route": "best_execution",
"clientId": "mm-1",
"nonce": int(time.time() * 1000) # current ms epoch; send this exact value in the body
}

types = {
"EIP712Domain": [
{"name": "name", "type": "string"},
{"name": "version", "type": "string"},
{"name": "chainId", "type": "uint256"},
{"name": "verifyingContract", "type": "address"}
],
"PlaceOrder": [
{"name": "wallet", "type": "address"},
{"name": "symbol", "type": "string"},
{"name": "side", "type": "string"},
{"name": "size", "type": "string"},
{"name": "price", "type": "string"},
{"name": "tif", "type": "string"},
{"name": "route", "type": "string"},
{"name": "clientId", "type": "string"},
{"name": "nonce", "type": "uint64"}
]
}

structured_msg = {
"types": types,
"domain": domain,
"primaryType": "PlaceOrder",
"message": message
}

encoded = encode_typed_data(full_message=structured_msg)
signed = Account.sign_message(encoded, private_key)
signature = signed.signature.hex()

JavaScript (ethers.js v6)​

const { ethers } = require("ethers");

const domain = {
name: "Hypercall",
version: "1",
chainId: 999,
verifyingContract: "0x0000000000000000000000000000000000000000"
};

const types = {
PlaceOrder: [
{ name: "wallet", type: "address" },
{ name: "symbol", type: "string" },
{ name: "side", type: "string" },
{ name: "size", type: "string" },
{ name: "price", type: "string" },
{ name: "tif", type: "string" },
{ name: "route", type: "string" },
{ name: "clientId", type: "string" },
{ name: "nonce", type: "uint64" }
]
};

const message = {
wallet: "0x1111111111111111111111111111111111111111",
symbol: "BTC-20250131-100000-C",
side: "Buy",
size: "0.1",
price: "100.0",
tif: "gtc",
route: "best_execution",
clientId: "mm-1",
nonce: Date.now() // current ms epoch; send this exact value in the body
};

const signature = await signer.signTypedData(domain, types, message);

İmzaları Test Etme​

İmza üretimini test etmek için örnek:

  1. Kendi uygulamanızla imza üretin
  2. POST /order ile test emri gönderin
  3. Yanıtı doğrulayın: status değeri "ACKED" olan HTTP 200 ya da reason içeren "REJECTED"
  4. İstek, tanımadığınız bir imzalayan adresiyle HTTP 401 unauthorized veya HTTP 400 signature_verification_failed hatasıyla başarısız olursa şunları kontrol edin:
    • price ve size alanlarının string biçimlendirmesi
    • Domain parametreleri (özellikle chainId)
    • route ve nonce dahil, imzalanan her alanın gövdeyle eşleşmesi

Güvenlik Hususları​

  1. Özel anahtarları asla açığa çıkarmayın: Donanım cüzdanları veya güvenli anahtar yönetimi kullanın
  2. Nonce yönetimi: İmzalama anahtarı başına kalıcı, milisaniye zaman damgalı nonce'lar kullanın
  3. Ajan yetkilendirmesi: Yetkili ajanları GET /authorized-agents ile düzenli olarak denetleyin
  4. String kodlaması: price ve size alanlarının hem imzalamada hem de istekte string olduğundan emin olun

Referanslar​