暗号資産取引所 API は署名とレート制限で分かれる── 取引所を増やしても壊れない構成にする
REST と WebSocket という形は各社共通でも、署名の作り方とレート制限の数え方は揃っていません。差異をどこに閉じ込めるかを、bitFlyer と Binance の実装で具体的に見ます。

中央集権型の取引所につないだ経験があると、分散型取引所(DEX)の統合も同じ手順で進められそうに見えます。ところが実際には、対応関係が素直ではありません。API キーに相当するものは秘密鍵であり、注文の送信は取引所への HTTP リクエストではなくブロックチェーンへのトランザクションで、板の参照に相当する処理は複数の経路から選ぶことになります。
この違いを吸収するうえで有効なのが、読み取りと送信を別々の経路として設計するという切り分けです。本稿では Uniswap を例に、統合方法の選択肢、読み取り経路の選び分け、送信前に決めておくべき事項、そして失敗したときの扱いを整理します。仕様の出典は末尾に挙げています。
Uniswap の開発者ドキュメントは、統合の方法として API・TypeScript SDK・オンチェーンでの直接操作の 3 つを示しています。API は短時間で組み込める経路、SDK は独自の統合を組む経路、オンチェーンはプロトコルの層で直接構築する経路という位置づけです。
どれを選ぶかで、運用の手間・遅延・障害時の挙動が変わります。API は導入が速い代わりに提供側の可用性に依存します。SDK は制御の幅が広がる分、バージョン追随の責任がこちらに来ます。コントラクト直接呼び出しは最も自由ですが、ルーティングや価格計算も自前になります。
実務上の落としどころは、3 つのどれかに決め打ちせず、呼び出し部分を差し替え可能にしておくことです。要件が固まる前は API で組み、独自の実行経路が必要になった時点で SDK やコントラクト直接に移す、という進め方が現実的です。呼び出しを業務ロジックに直書きしていると、この移行が全面改修になります。

オンチェーンのデータを取る経路は大きく 2 つです。Subgraph のようなインデックス済みのデータを問い合わせる方法と、ノードに対して状態を直接参照する方法です。
Subgraph は集計済みのデータを扱いやすい形で返します。プールの一覧、流動性の推移、過去のスワップといった分析用途では、こちらが圧倒的に扱いやすくなります。
query TopPools($first: Int!) {
pools(first: $first, orderBy: totalValueLockedUSD, orderDirection: desc) {
id
feeTier
liquidity
token0 { symbol decimals }
token1 { symbol decimals }
totalValueLockedUSD
}
}
ただし、Subgraph が返すのはインデックス済みの状態であり、チェーンの最新状態とは差があります。この差は普段は小さくても、混雑時には広がります。残高や実効価格の判断にそのまま使うと、実際には成立しない前提で送信することになります。
したがって、経路は用途で分けます。分析・画面表示・履歴はインデックス経由、送信直前の判断はノード直接参照とし、どちらの経路のデータなのかをコード上で区別できるようにしておきます。型を分けてしまうのが確実で、同じ「価格」という名前の値を両方の経路から取れる状態にしておくと、いずれ取り違えます。
ノード側にも制約があります。マネージドの RPC を使う場合、呼び出しには単位あたりの上限があり、取得できる過去ブロックの範囲やログ検索の件数にも制限がかかります。銘柄ごとに 1 回ずつ問い合わせる実装は、対象が増えた時点で上限に当たります。複数の読み取りを 1 回の呼び出しにまとめる仕組みを最初から使い、1 画面・1 判断あたりの呼び出し回数を設計時に数えておきます。ここを後から直すと、読み取り側の構造をほぼ全面的に書き換えることになります。
送信側は、承認・見積もり・期限の 3 点を先に決めます。
まず承認です。ERC20 のトークンを他のコントラクトに動かしてもらうには、あらかじめ承認が要ります。Uniswap は Permit2 という仕組みを用意しており、これを使う場合はトークンコントラクト側で Permit2 に対する承認を一度だけ行います。ドキュメントでは USDC.approve(permit2Address, totalAmount) のような形で、セキュリティを最大化するために type(uint256).max による無制限承認が推奨されています。
無制限承認を「推奨」と読むと違和感がありますが、これは Permit2 側で制御を効かせる前提だからです。Permit2 には 2 つの方式があり、SignatureTransfer は署名に基づく転送を扱い、権限はそのトランザクションの中でだけ存在します。AllowanceTransfer は特定の相手に対して金額と期間を指定した権限を与えます。トークンコントラクトに対する承認を広く取っておき、実際に動かせる範囲は Permit2 の側で絞る、という構造です。
次に見積もりです。板を持たない方式では、投入量が大きいほど実効価格が提示価格から離れます。許容できる下限を指定せずに送信すると、送信から確定までの間に他の取引でプールの残高が動き、意図しない比率で約定します。
/** 見積もりから、送信に使う最小受取量と期限を決める。 */
function buildGuards(quotedOut: bigint, slippageBps: number, ttlSec: number) {
if (slippageBps < 0 || slippageBps > 1000) {
// 10% を超える許容幅は、設定ミスとして弾く。実運用で必要になることはまずない。
throw new Error(`slippageBps out of range: ${slippageBps}`);
}
const minAmountOut =
(quotedOut * BigInt(10_000 - slippageBps)) / 10_000n;
// 期限はブロックのタイムスタンプと比較される。長すぎる期限は、
// 混雑で滞留したトランザクションが不利な価格で成立する余地を残す。
const deadline = BigInt(Math.floor(Date.now() / 1000) + ttlSec);
return { minAmountOut, deadline };
}
3 つ目が期限です。期限を長く取ると、送信したトランザクションが混雑で滞留し、状況が変わってから成立することがあります。短くすれば失敗が増えます。どちらも失敗の形が違うだけで、期限を決めないという選択肢はありません。
Uniswap は v2・v3・v4 が並行して存在します。v4 では Hooks によってプールごとに独自のロジックを定義できるため、「Uniswap に対応する」という言い方だけでは仕様が決まりません。
実装に入る前に、対象とするバージョンと、対象とするプールを確定させます。ここが決まっていないと、テストで何を期待値にすればよいかも決まりません。Hooks を持つプールでは、同じ操作でも通常のプールと挙動が変わり得るため、対応するプールの範囲を要件として書き下しておく必要があります。
実行経路にも選択肢があります。Universal Router のような、複数の操作を 1 つのトランザクションにまとめる仕組みを使うのか、個別に呼ぶのか。UniswapX のようにフィラーによって約定する方式を含めるのか。これらは後から足せる性質のものではなく、送信側の設計そのものに関わります。
トランザクションは失敗します。ガスの見積もり不足、期限切れ、最小受取量に届かない、承認が足りない。これらは異常ではなく、想定される結果の一部です。
設計上の要点は 2 つあります。1 つは、送信したトランザクションのハッシュを、業務側の識別子と紐づけて必ず記録することです。記録がないと、失敗したのか、まだ確定していないのかを後から区別できません。もう 1 つは、再送の扱いです。手数料が足りずに滞留した場合、同じ nonce でガス価格を上げて置き換えることになりますが、これは「もう 1 回送る」のとは違う操作です。単純な再送を実装すると、二重に約定する余地が生まれます。
確定の判定も決めておきます。何ブロック後に確定とみなすかは、対象チェーンと金額によって変わります。1 ブロックで確定として扱う実装は、再編成が起きたときに残高がずれます。逆に確定を待ちすぎると、次の送信が滞ります。金額の帯ごとに待つブロック数を決めておくと、この判断を実行時に迷わずに済みます。
送信を並行させる場合は、nonce の管理が別の論点になります。同じアカウントから同時に複数のトランザクションを出すと、nonce は送信側が採番することになり、1 つでも詰まると後続がすべて止まります。実務では、送信するアカウントを用途ごとに分けて、詰まりの影響範囲を切っておくのが単純で効きます。1 つのアカウントに全部を集約した構成は、平時は問題なく動き、混雑した日に一斉に止まります。
DEX の統合は、読み取りと送信を分けて設計すると整理できます。読み取りはインデックス経由とノード直接参照を用途で分け、コード上で取り違えないようにします。送信は承認・見積もり・期限の 3 点を先に決め、最小受取量と期限を必ず指定します。Permit2 を使うなら、トークン側の承認を広く取り、Permit2 側で金額と期間を絞る構造を理解して設定します。対象バージョンとプールは実装前に固定し、失敗と再送は正常系として設計に織り込みます。統合方法そのものは要件で変わるため、呼び出し部分は差し替え可能にしておきます。
金融テクノロジー総合研究所では、DEX を含むオンチェーン連携の設計・実装を受託しています。既存システムへの組み込みや、実行経路の見直しからもご相談いただけます。Crypto DEX API 開発の詳細もあわせてご覧ください。ご相談はお問い合わせよりご連絡ください。
FTL の技術スタックと受託開発の進め方は FTLの技術とは? にまとめています。