Hyperliquid API の接続と認証── API ウォレットと nonce で発注の権限を設計する
ブロックチェーン

Hyperliquid API の接続と認証── API ウォレットと nonce で発注の権限を設計する

FTL編集部

中央集権型の取引所に接続するときは、管理画面で API キーとシークレットを発行し、権限にチェックを入れれば準備が終わります。Hyperliquid にはその意味での API キーがありません。リクエストはすべてウォレットの秘密鍵による署名で認証され、「誰が発注したか」は署名から復元されたアドレスで決まります。

この仕組みを理解しないまま、入金に使ったウォレットの鍵をそのまま発注サーバーに置く構成がよく見られます。動きはしますが、サーバーが侵害されれば資金ごと失います。本稿では、公式ドキュメントと公式 Python SDK の記載をもとに、鍵の分け方、サブアカウントの扱い、nonce の設計、署名で詰まったときの切り分けを整理します。レート制限は別稿で扱っています。

鍵は 2 種類に分ける ── マスターと API ウォレット

Hyperliquid の口座は、入金に使ったウォレットのアドレスそのものです。これを公式ドキュメントではマスターアカウントと呼びます。マスターの鍵は、入出金・送金・ステーキングを含むすべての操作に署名できます。

発注のために用意されているのが API ウォレット(エージェントウォレットとも呼ばれます)です。マスターが approveAgent というアクションに署名して、別に生成した鍵のアドレスを登録します。登録された鍵は、マスターやそのサブアカウントに代わって署名できます。

公式 Python SDK のサンプルには、エージェントは資金の送金や出金の権限を持たないと明記されています。発注サーバーに置く鍵が漏れても、相手にできるのは発注と取消までで、資金を外へ動かすことはできません。この差が、鍵を分ける理由のすべてです。

  • マスターの鍵 — 入出金、API ウォレットの登録と解除にだけ使う。発注サーバーには置かず、ハードウェアウォレットや運用担当の手元で管理する
  • API ウォレットの鍵 — 発注・取消・建玉の調整に使う。発注サーバーに置き、漏れたら登録を解除して作り直す

注意したいのは、API ウォレットは署名にしか使わない点です。残高や建玉を /info で照会するときは、マスターやサブアカウントの実際のアドレスを渡します。API ウォレットのアドレスで照会すると、エラーではなく空の結果が返ります。口座が空になったように見えるので、監視の実装で取り違えると誤報の原因になります。

Hyperliquid の鍵の構成を示した図。マスターアカウントの鍵は入出金と API ウォレットの登録だけを担い、発注プロセスごとに別の API ウォレットを割り当てる。サブアカウントは鍵を持たず、vaultAddress で宛先を指定する。nonce は署名した鍵ごとに管理される
資金を動かせる鍵と、発注だけに使う鍵を分ける

API ウォレットの枠と有効期限

API ウォレットは無制限には登録できません。公式ドキュメントの記載では、1 つの口座に名前なしを 1 つ、名前付きを 3 つまで登録でき、サブアカウント 1 つごとに名前付きが 2 つ追加されます。

登録の動作にも癖があります。名前なしで新しいアドレスを登録すると、既存の名前なしの API ウォレットは解除されます。既存と同じ名前で登録した場合も、その名前の API ウォレットが解除されます。運用中の鍵を、別の作業で意図せず無効にしてしまう経路があるということです。名前は用途ごとに決めて、台帳で管理します。

有効期限は、名前の後ろに valid_until とタイムスタンプを付けて指定でき、最長で 180 日先までです。期限切れの鍵は署名が通らなくなるので、更新の手順と期限の監視を運用に組み込みます。

API ウォレットとその nonce の状態は、次のいずれかで削除(プルーニング)されることがあります。

  • 登録が解除されたとき
  • 有効期限が切れたとき
  • 登録した口座の資金がなくなったとき

ここで公式ドキュメントが強く求めているのが、API ウォレットのアドレスを使い回さないことです。nonce の記録が消えたあとに同じアドレスを登録し直すと、過去に署名した要求が再送されたときに受理されてしまう可能性があります。鍵を作り直すときは、必ず新しく生成します。

サブアカウントと Vault は鍵を持たない

戦略ごとに証拠金を分けたいときは、サブアカウントを使います。累計の取引量が 10 万ドルに達すると 10 個まで作成でき、取引量 1 億ドルごとに 1 つずつ、最大 50 個まで増えます。手数料の階層はマスターと共通です。

設計上の要点は、サブアカウントと Vault には秘密鍵が無いことです。サブアカウントで発注するときは、マスター(または登録した API ウォレット)が署名し、リクエストの vaultAddress にサブアカウントのアドレスを入れます。宛先を署名とは別に指定する形なので、vaultAddress の入れ間違いは、別の戦略の口座へ発注する事故に直結します。宛先は設定値として外に出し、起動時に /info の subAccounts で、そのアドレスが自分の配下にあるかを照合します。

アドレスの素性は userRole で確認できます。返る role は user・agent・vault・subAccount・missing のいずれかで、agent なら紐づく口座、subAccount ならマスターのアドレスも返ります。設定を読み込んだ直後にこれを通しておくと、鍵と宛先の取り違えを発注の前に止められます。

nonce は署名した鍵ごとに 100 個

イーサリアムでは、アドレスごとに 1 つの nonce を 1 ずつ増やして使います。Hyperliquid は板取引で毎秒多数の要求をさばくため、仕組みが違います。署名した鍵ごとに、使われた nonce のうち大きいもの 100 個が記録され、新しい要求の nonce は、その中の最小値より大きく、かつ未使用である必要があります。

さらに nonce は、ブロックの時刻を基準に 2 日前から 1 日後までの範囲に収まっていなければなりません。リクエストの nonce には現在時刻のミリ秒を入れることが推奨されています。サーバーの時計が大きくずれていると、この条件で拒否されます。

見落としやすいのは、nonce の管理単位が口座ではなく署名した鍵だという点です。1 つの API ウォレットでマスターと複数のサブアカウントに署名すると、すべてが 1 つの nonce の集合を共有します。複数のプロセスが同じ鍵で同時に送ると、互いの nonce が衝突します。

公式ドキュメントの推奨は次のとおりです。

  • 発注プロセスごとに API ウォレットを 1 つ — サブアカウントを並行して動かすなら、サブアカウントごとに別の API ウォレットを割り当てる
  • nonce はアドレスごとの原子的なカウンタで採番 — カウンタは現在時刻のミリ秒まで進めてよい
  • 発注と取消は 0.1 秒ごとにまとめて送る — IOC・GTC と、優先して処理される ALO は別のまとまりにする

この形にしておけば、2 秒以内の順序の入れ替わりは許容されます。前節の API ウォレットの枠と合わせると、同時に動かせる発注プロセスの数は、登録できる API ウォレットの数で上限が決まることになります。プロセスを増やす計画があるなら、サブアカウントの設計と一緒に枠を見積もります。

なお、一部のアクションでは expiresAfter で有効期限を付けられます。古くなった要求を確実に捨てられる一方、期限切れで取り消された要求はアドレス単位のレート制限を通常の 5 倍消費します。期限は短くしすぎないようにします。

署名の 2 方式と、原因を語らないエラー

署名には 2 つの方式があります。発注や取消などの L1 アクションと、送金・出金・API ウォレットの登録などのユーザー署名アクションです。後者のリクエストには hyperliquidChain(本番は Mainnet、テストネットは Testnet)と、署名に使うチェーンの ID を表す signatureChainId が入ります。

署名が誤っていると、ネットワークは別のアドレスを復元します。そのため返るのは「署名が不正」ではなく、User or API Wallet 0x... does not exist や Must deposit before performing actions といった、口座が存在しないかのようなエラーです。原因はメッセージから読み取れません。

公式ドキュメントが挙げている典型的な誤りは次のとおりです。

  • 2 つの署名方式の取り違え
  • エンコード時のフィールドの順序の違い(順序が署名結果に影響する)
  • 数値の末尾のゼロ
  • アドレスの大文字(署名と送信の前に小文字へそろえる)

加えて、手元で署名を検証して正しいアドレスが復元できても、署名が正しいとは限りません。検証に使う内容がアクションから組み立て直されたもので、実際に署名した内容と一致していない場合があるためです。

結論として、署名は自前で実装せず、公式 SDK に任せるのが公式の推奨でもあります。公式は Python SDK のみで、Rust や TypeScript はコミュニティ製です。他の言語で実装する場合は、Python SDK の出力と 1 行ずつ突き合わせ、どこで食い違うかをログで追います。

テストネットで通しておく順序

テストネットの接続先は https://api.hyperliquid-testnet.xyz です。テスト用の USDC は 1,000 ずつ受け取れますが、同じアドレスで本番に入金した実績が必要です。検証用のアドレスを新しく作ると、ここで止まります。

本番へ移す前に、テストネットで次の順に確認します。

  • マスターで API ウォレットを登録し、userRole で agent と返ることを確かめる
  • API ウォレットで発注と取消を行い、照会はマスターのアドレスで行う
  • vaultAddress を指定してサブアカウントで発注し、別の口座に入らないことを確かめる
  • API ウォレットで出金を試み、拒否されることを確かめる
  • 同じ鍵で 2 プロセスから送り、nonce の衝突がどう見えるかを記録しておく

最後の 2 つは異常系の確認です。権限の境界と衝突時の見え方を先に知っておくと、本番で拒否が出たときに、署名の誤りなのか運用の誤りなのかをすぐに切り分けられます。

まとめ

Hyperliquid には API キーが無く、認証は署名で行います。資金を動かせるマスターの鍵は発注サーバーに置かず、出金できない API ウォレットを発注プロセスごとに割り当てます。API ウォレットは名前なし 1 つと名前付き 3 つ、サブアカウントごとに 2 つが上限で、有効期限は最長 180 日です。サブアカウントは鍵を持たず、vaultAddress で宛先を指定します。nonce は署名した鍵ごとに管理されるため、鍵を共有するプロセスは衝突します。署名の誤りは口座が存在しないかのようなエラーとして返るので、公式 SDK に任せ、テストネットで権限の境界まで確認してから本番へ移します。

金融テクノロジー総合研究所では、暗号資産取引所への接続基盤の設計と実装を受託しています。鍵の管理方式の見直しや、複数の戦略を並行して動かす発注基盤の設計からご相談いただけます。Hyperliquid API 対応の詳細もあわせてご覧ください。ご相談はお問い合わせよりご連絡ください。

参考資料

記事一覧に戻る