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 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 imzaları gerektirir. İmzalayan taraf şunlardan biri olmalıdır:

  1. Cüzdan adresinin kendisi (doğrudan imzalama), VEYA
  2. Cüzdan için yetkilendirilmiş bir agent (bkz. Agent auth)

EIP-712 Domain

Domain separator:

{
"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 atlandığında 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 ön ekli hex string)
  • symbol: Opsiyon sembolü (örn. "BTC-20250131-100000-C")
  • side: "Buy" veya "Sell" (tam string eşleşmesi gereklidir)
  • size: String olarak büyüklük (örn. "0.1") - JSON'da gönderilenle birebir aynı OLMALIDIR
  • price: String olarak fiyat (örn. "100.0") - JSON'da gönderilenle birebir aynı OLMALIDIR
  • tif: Time-in-force: "gtc", "ioc" veya "fok" (tam string eşleşmesi gereklidir)
  • route: İsteğe bağlı emir yönlendirmesi: "best_execution", "book_only" veya "rfq_only" (mevcut olduğunda tam string eşleşmesi gereklidir)
  • clientId: İstemci tarafından sağlanan emir ID'si (string, boş olabilir "")
  • nonce: Yeniden oynatma (replay) korumasına yönelik benzersiz nonce (uint64)

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

Route varsayılanı: route, en az 4 Temmuz 2026'ya kadar isteğe bağlıdır. JSON'dan çıkarıldığında, tipli veriden de çıkarın. Sunucu, atlanan route değerini best_execution olarak değerlendirir. POST /order, atlanan route için deprecation başlıkları döndürür. İstemciler route göndermelidir; 4 Temmuz 2026'dan önce zorunlu olmayacaktır, ancak daha sonra zorunlu hale gelebilir.

CancelOrder

Struct:

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

Alan gereksinimleri:

  • wallet: Cüzdan adresi
  • orderId: String olarak emir ID'si (örn. "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 agent cüzdan adresi
  • nonce: Benzersiz nonce

Not: Agent'ı yetkilendiren cüzdan, kurtarılan imzadan türetilir.

RevokeAgent

Struct:

struct RevokeAgent {
address agent;
uint64 nonce;
}

Alan gereksinimleri:

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

İmzalama Süreci

Adım 1: Mesajı Oluşturun

Açık route içeren PlaceOrder için örnek:

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: 123
};

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 kullanarak:

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ğerlerini kullanmalıdır:

{
"wallet": "0x1111111111111111111111111111111111111111",
"symbol": "BTC-20250131-100000-C",
"price": "100.0", // Same string as signed
"size": "0.1", // Same string as signed
"side": "Buy",
"tif": "gtc",
"route": "best_execution",
"client_id": "mm-1",
"nonce": 123,
"signature": "0x..."
}

Nonce Yönetimi

Gereksinimler:

  • Nonce'lar her cüzdan için benzersiz OLMALIDIR
  • Nonce'lar artan şekilde OLMALIDIR (yeniden oynatma saldırılarını önler)
  • Nonce'lar katı monotonluk açısından doğrulanmaz (boşluklara izin verilir)

En iyi uygulamalar:

  • Her cüzdan için kalıcı bir sayaç kullanın
  • Her başarılı imzadan sonra artırın
  • Nonce boşluklarını sorunsuz şekilde yönetin (örn. bir istek başarısız olursa aynı nonce ile yeniden deneyin)

Agent Yetkilendirmesi

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

  1. Agent'ı onaylayın (tek seferlik):

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

    • PlaceOrder / CancelOrder mesajlarını imzalamak için agent cüzdanını kullanın
    • wallet alanını işlem cüzdanı adresine ayarlayın
    • Middleware, agent'ın söz konusu cüzdan için yetkili olduğunu doğrular

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

Perp Emirleri (Hyperliquid Uyumlu)

Perp emirleri, farklı bir EIP-712 domain'i ve mesaj formatı kullanır (Hyperliquid Core uyumluluğu):

Domain:

{
"name": "Exchange",
"version": "1",
"chainId": 1337,
"verifyingContract": "0x0000000000000000000000000000000000000000"
}

Mesaj: MessagePack ile kodlanmış emir verisi içeren Agent struct'ı.

Alanların tam listesi için güncel imza kodlama rehberine bakın.

Yaygın Hatalar

"Signature verification failed"

Nedenler:

  1. price veya size string yerine sayı olarak gönderildi
  2. String formatı imzalama ile gönderim arasında değişti (örn. "100.0" ve "100")
  3. Yanlış nonce
  4. Yanlış domain (chain ID, name, version)
  5. Agent cüzdan için yetkilendirilmemiş

"Unauthorized: signer not authorized for wallet"

Neden: İmzalayan, cüzdanın kendisi değildir ve yetkili bir agent da değildir.

Çözüm: POST /approve-agent üzerinden agent'ı onaylayın veya doğrudan cüzdan ile imzalayın.

Uygulama Örnekleri

Python (eth_account)

from eth_account import Account
from eth_account.messages import encode_structured_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": 123
}

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_structured_data(structured_msg)
signed = Account.sign_message(encoded, private_key)
signature = signed.signature.hex()

JavaScript (ethers.js)

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: 123
};

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

İmzaları Test Etme

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

  1. Kendi implementasyonunuzla imza üretin
  2. POST /order üzerinden test emri gönderin
  3. Yanıtı doğrulayın: status="ACKED" veya nedeni ile birlikte status="REJECTED"
  4. "signature_verification_failed" alırsanız, şunları kontrol edin:
    • price ve size alanlarının string formatı
    • Domain parametreleri (özellikle chainId)
    • Nonce doğruluğu

Güvenlik Hususları

  1. Özel anahtarları asla ifşa etmeyin: Donanım cüzdanları veya güvenli anahtar yönetimi kullanın
  2. Nonce yönetimi: Her cüzdan için kalıcı ve artan nonce'lar kullanın
  3. Agent yetkilendirmesi: GET /authorized-agents üzerinden yetkili agent'ları düzenli olarak denetleyin
  4. String kodlaması: price ve size alanlarının hem imzalamada hem de istekte string olduğundan emin olun

Referanslar