Exchange Precompileは、固定アドレス0x0000000000000000000000000000000000000065に存在するシステムスマートコントラクトです。Solidity開発者に、Injectiveチェーンのexchangeモジュールと直接連携するための、gas効率の高いネイティブな手段を提供します。このprecompileを活用することで、スマートコントラクトは以下のようなexchange関連のアクションをシームレスに実行できます:
- サブアカウントへの資金の入金と引き出し。
- スポットおよびデリバティブ注文の作成またはキャンセル。
- サブアカウント残高とオープンポジションのクエリ。
- 他のアカウントまたはコントラクトへの認可グラントの管理。
Precompileの呼び出し:直接アクセス vs. プロキシアクセス
Exchange Precompileとの連携には、2つの主要なアプローチがあります:
1. 直接アクセス(自己呼び出しコントラクト)
このモードでは、スマートコントラクトが自身の代わりにprecompileと連携します。コントラクト自体が、自身の資金を使用してexchangeモジュールでの操作を実行し、自身のポジションを管理するアクターです。
例:
exchange.deposit(address(this), subaccountID, denom, amount);
このメソッドは簡単で、コントラクトが本質的に自身のリソースを管理する権限を持っているため、明示的な認可グラントは不要です。
2. プロキシアクセス(別のユーザーの代わりに呼び出す)
スマートコントラクトは、外部ユーザーアカウントの代わりにexchange操作を実行する仲介者として設計することもできます。このシナリオでは、コントラクトはprecompileを呼び出し、第三者のアドレスをsenderまたは操作対象のアカウントとして指定します。
例:
exchange.deposit(userAddress, subaccountID, denom, amount);
これを成功させるには、スマートコントラクト(grantee)がユーザー(userAddress、granter)によって指定されたアクションを実行する明示的な認可を受ける必要があります。この認可は、precompileが提供するapproveおよびrevokeメソッドを使用して管理されます。ユーザーの資金のセキュリティを確保するために、これらの認可を慎重に扱うことが重要です。
コントラクトに代わりに特定のアクションを実行する権限を付与するには:
exchange.approve(grantee, msgTypes, spendLimit, duration);
grantee: 認可されるコントラクトのアドレス。
msgTypes: granteeが実行を許可されるメッセージタイプの配列(例:MsgCreateDerivativeLimitOrder、MsgDeposit)。完全なリストはExchangeTypes.solまたはInjective Protocolのprotobuf定義を参照してください。
spendLimit: granteeがメッセージタイプごとまたはグラント全体で使用できる指定トークンの最大量を定義するCosmos.Coin構造体の配列。
duration: 認可が有効な期間(秒単位)。
以前に付与した認可を取り消すには:
exchange.revoke(grantee, msgTypes);
認可が現在存在するかどうかを確認するには:
exchange.allowance(grantee, granter, msgType);
例:直接メソッド
以下のExchangeDemoコントラクトは、スマートコントラクトが直接アクセスメソッドを使用する方法を示しています。資金の入金、資金の引き出し、デリバティブ指値注文の作成、サブアカウントポジションのクエリなどの基本的なexchangeアクションを、すべて自身のサブアカウントと資金を使用して実行します。
Exchange.solおよびExchangeTypes.solファイルには、precompileと連携するために必要なインターフェース定義とデータ構造が含まれています。これらは通常、公式のInjective Solidityコントラクトリポジトリで利用可能であるか、プロジェクトの依存関係として含めることができます。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../src/Exchange.sol"; // Contains IExchangeModule interface
import "../src/ExchangeTypes.sol"; // Contains necessary structs like DerivativeOrder
contract ExchangeDemo {
address constant exchangeContract = 0x0000000000000000000000000000000000000065;
IExchangeModule exchange = IExchangeModule(exchangeContract);
/***************************************************************************
* Calling the precompile directly (contract acts on its own behalf)
****************************************************************************/
/**
* @notice Deposits funds from the contract's balance into one of its exchange subaccounts.
* @param subaccountID The target subaccount ID (derived from the contract's address).
* @param denom The denomination of the asset to deposit (e.g., "inj").
* @param amount The quantity of the asset to deposit.
* @return success Boolean indicating if the deposit was successful.
*/
function deposit(
string calldata subaccountID,
string calldata denom,
uint256 amount
) external returns (bool) {
try exchange.deposit(address(this), subaccountID, denom, amount) returns (bool success) {
return success;
} catch Error(string memory reason) {
revert(string(abi.encodePacked("Deposit error: ", reason)));
} catch {
revert("Unknown error during deposit");
}
}
/**
* @notice Withdraws funds from one of the contract's exchange subaccounts to its main balance.
* @param subaccountID The source subaccount ID.
* @param denom The denomination of the asset to withdraw.
* @param amount The quantity of the asset to withdraw.
* @return success Boolean indicating if the withdrawal was successful.
*/
function withdraw(
string calldata subaccountID,
string calldata denom,
uint256 amount
) external returns (bool) {
try exchange.withdraw(address(this), subaccountID, denom, amount) returns (bool success) {
return success;
} catch Error(string memory reason) {
revert(string(abi.encodePacked("Withdraw error: ", reason)));
} catch {
revert("Unknown error during withdraw");
}
}
/**
* @notice Queries the derivative positions for a given subaccount of this contract.
* @param subaccountID The subaccount ID to query.
* @return positions An array of DerivativePosition structs.
*/
function subaccountPositions(
string calldata subaccountID
) external view returns (IExchangeModule.DerivativePosition[] memory positions) {
// Note: View functions calling precompiles might behave differently based on node configuration
// For on-chain state, this is fine. For off-chain queries, direct gRPC/API queries are often preferred.
return exchange.subaccountPositions(subaccountID);
}
/**
* @notice Creates a new derivative limit order from the contract's subaccount.
* @param order The DerivativeOrder struct containing order details.
* @return response The response struct containing details like order hash.
*/
function createDerivativeLimitOrder(
IExchangeModule.DerivativeOrder calldata order
) external returns (IExchangeModule.CreateDerivativeLimitOrderResponse memory response) {
try exchange.createDerivativeLimitOrder(address(this), order) returns (IExchangeModule.CreateDerivativeLimitOrderResponse memory resp) {
return resp;
} catch Error(string memory reason) {
revert(string(abi.encodePacked("CreateDerivativeLimitOrder error: ", reason)));
} catch {
revert("Unknown error during createDerivativeLimitOrder");
}
}
}
ビルドを開始する
このExchangeDemoスマートコントラクトのビルド、デプロイ、インタラクション方法(サブアカウントのセットアップと資金供給を含む)の詳細な手順については、solidity-contractsリポジトリの包括的なデモを参照してください。
まとめ
Exchange Precompileは、洗練されたプロトコル統合型のトレーディングロジックをInjective上のスマートコントラクトに直接組み込むことを可能にする強力なツールです。コントラクトが自身のポートフォリオを管理する場合でも、(approveとrevokeによるプロキシパターンを使用して)他のユーザーのための多機能なトレーディングインターフェースとして機能する場合でも、このprecompileはSolidityを使用してコアexchangeモジュールとインタラクションするための、クリーンで安全かつ効率的な方法を提供します。
自己完結型のコントラクトロジックには直接呼び出しを優先し、より広いInjectiveエコシステム向けの再利用可能なコントラクトインターフェースを構築する際には、堅牢な認可を備えたプロキシパターンを慎重に実装してください。
\ Last modified on April 24, 2026