Change Log
2024-08-06
- Added support for the following messages in the chain "exchange" module:
- MsgDecreasePositionMargin
- MsgUpdateSpotMarket
- MsgUpdateDerivativeMarket
- MsgAuthorizeStakeGrants
- MsgActivateStakeGrantmodule
- Python SDK v1.6.1: add min_notional to all market classes
- Go SDK v1.51.1: add min_notional to all market structs
2024-07-30
- Updated requests and responses messages with parameters added in chain upgrade to v1.13
- Updated the API documentation to include all queries and messages for the
tendermint
module - Updated the API documentation to include all queries and messages for the
IBC transfer
module - Updated the API documentation to include all queries and messages for the
IBC core channel
module - Updated the API documentation to include all queries and messages for the
IBC core client
module - Updated the API documentation to include all queries and messages for the
IBC core connection
module - Updated the API documentation to include all queries and messages for the
permissions
module - Python SDK v1.6.0
- Added support for all queries from the
tendermint
module - Added support for all queries from the
IBC transfer
module - Added support for all queries from the
IBC core channel
module - Added support for all queries from the
IBC core client
module - Added support for all queries from the
IBC core connection
module - Added support for all queries from the
permissions
module
- Added support for all queries from the
2024-03-08
- Updated the API documentation to include all queries and messages for the
distribution
andchain exchange
modules - Python SDK v1.4.0
- Added support for all queries and messages from the
distribution
module - Added support for all queries and messages from the
chain exchange
module
- Added support for all queries and messages from the
2024-01-25
- Python SDK v1.2.0
- Improved message based gas estimator to consider that Post Only orders creation require more gas than normal orders
2024-01-02
- Python SDK v1.0 and Go SDK v1.49
- Added logic to support use of Client Order ID (CID) new identifier in OrderInfo
- New chain stream support
- Remove support for
sentry
nodes in mainnet network. The only supported node option in mainnet islb
- Migrated all proto objects dependency to support chain version 1.12
- Added logic to cover all bank module queries
- Added logic in Python SDK to support the initialization of tokens with all the tokens from the chain (DenomsMetadata)
- Added logic in Go SDK to allow the initialization of markets and tokens from the chain (without using the local .ini files). Also included functionality to initialize the tokens wilh all the tokens from the chain (DenomsMetadata)
- Added support for wasm, tokenfactory and wasmx modules, including example script for all their endpoints
2023-09-06
- Python SDK v0.8 release
- Network class was moved from
pyinjective.constant
topyinjective.core.network
- Configuration to use secure or insecure channels has been moved into the Network class
- The Composer can be created now by the AsyncClient, taking markets and tokens from the chain information instead of using the local configuration files
- Changed the cookies management logic. All cookies management is done now by Network
- Network class was moved from
2023-08-28
- Added IP rate limits documentation
Introduction
Welcome to Injective's documentation!
Here you can find a comprehensive overview of our protocol, as well as tutorials, guides and general resources for developers and API traders.
If you would like to ask any questions or be a part of our community, please join our Discord Group or Telegram Group. We have a dedicated channel in our Discord group for questions related to the API.
Clients
Python Client
Dependencies
Ubuntu
sudo apt install python3.X-dev autoconf automake build-essential libffi-dev libtool pkg-config
Fedora
sudo dnf install python3-devel autoconf automake gcc gcc-c++ libffi-devel libtool make pkgconfig
macOS
brew install autoconf automake libtool
Installation
Install injective-py from PyPI using pip
.
pip install injective-py
Reference
Markets and Tokens information
Example - Traditional Composer instantiation
from pyinjective.composer import Composer
from pyinjective.transaction import Transaction
from pyinjective.core.network import Network
network = Network.testnet()
composer = Composer(network=network.string())
Python SDK traditionally relied on local configuration files to get the list of available markets and tokens in each network (mainnet, testnet and devnet).
Since version 0.8 the SDK is able also to get the markets and tokens information directly from the chain data (through the Indexer process). The benefit of this approach is that it is not necessary to update the SDK version when a new market is created in the chain or a new token is added.
- To use the markets and tokens information from the local configuration files, create the Composer instance in the traditional way
Example - Get the composer instance through the AsyncClient
from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.async_client import AsyncClient
from pyinjective.transaction import Transaction
from pyinjective.core.network import Network
network = Network.testnet()
client = AsyncClient(network)
composer = await client.composer()
- To get the markets and tokens information directly from the chain, create the Composer instance through the AsyncClient
By default the AsyncClient and the Composer will only initialize the tokens that are part of an active market. In order to let them use any of the tokens available in the chain, the user has to execute the initialize_tokens_from_chain_denoms
in the AsyncClient before the creation of the Composer.
Example - Initialize with all tokens from the chain
from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.async_client import AsyncClient
from pyinjective.transaction import Transaction
from pyinjective.core.network import Network
network = Network.testnet()
client = AsyncClient(network)
await client.initialize_tokens_from_chain_denoms()
composer = await client.composer()
Golang Client
1. Create your own client repo and go.mod file
go mod init foo
2. Import SDK into go.mod
module foo
go 1.18
require ( github.com/InjectiveLabs/sdk-go v1.39.4 )
Consult the sdk-go repository to find the latest release and replace the version in your go.mod file. Version v1.39.4 is only an example and must be replaced with the newest release
3. Download the package
Download the package using go mod download
go mod download github.com/InjectiveLabs/sdk-go
Markets and Tokens information
Example - Traditional ChainClient instantiation
package main
import (
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
"os"
"github.com/InjectiveLabs/sdk-go/client/common"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
// initialize grpc client
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
fmt.Println(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
fmt.Println(err)
}
}
Go SDK traditionally relied on local configuration files to get the list of available markets and tokens in each network (mainnet, testnet and devnet).
Since version 1.49 the SDK is able also to get the markets and tokens information directly from the chain data (through the Indexer process). The benefit of this approach is that it is not necessary to update the SDK version when a new market is created in the chain or a new token is added.
Example - Get markets and tokens from Indexer (ExchangeClient)
package main
import (
"context"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/core"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
"os"
"github.com/InjectiveLabs/sdk-go/client/common"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
// initialize grpc client
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := core.NewMarketsAssistantUsingExchangeClient(ctx, exchangeClient)
if err != nil {
panic(err)
}
}
- To get the markets and tokens information directly from the chain, create an instance of MarketsAssistant using the
NewMarketsAssistantUsingExchangeClient
function and passing the ExchangeClient as parameter
Example - MarketsAssistant with all tokens
package main
import (
"context"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/core"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
"os"
"github.com/InjectiveLabs/sdk-go/client/common"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
// initialize grpc client
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := core.NewMarketsAssistantWithAllTokens(ctx, exchangeClient, chainClient)
if err != nil {
panic(err)
}
}
By default the MarketsAssistant will only initialize the tokens that are part of an active market. In order to let it use any of the tokens available in the chain, the user has to create the MarketsAssistant instance using the function NewMarketsAssistantWithAllTokens
.
The MarketsAssistant instance can be used with the following ChainClient functions:
CreateSpotOrder
CreateDerivativeOrder
Reference
Typescript Client
Installation
Install the @injectivelabs/sdk-ts
npm package using yarn
yarn add @injectivelabs/sdk-ts
Reference
To see Typescript examples please check the Typescript SDK documentation page listed above
For other languages
Currently Injective provides SDKs only for Go, Python and TypeScript. To interact with the nodes using a different language please connect directly using the gRPC proto objects. The compiled proto files for C++, C# and Rust can be found in InjectiveLabs/injective-proto
Overview
Injective is a DeFi focused layer-1 blockchain built for the next generation of decentralized derivatives exchanges. The Injective Chain is a Tendermint-based IBC-compatible blockchain which supports a decentralized orderbook-based DEX protocol and a trustless ERC-20 token bridge to the Ethereum blockchain.
It is the first decentralized exchange focused layer-1 blockchain for perpetual swaps, futures, and spot trading that unlocks the full potential of decentralized derivatives and borderless DeFi. Every component of the protocol has been built to be fully trustless, censorship-resistant, publicly verifiable, and front-running resistant.
By providing the unrestricted and unprecedented ability to express diverse views in decentralized financial markets, we strive to empower individuals with the ability to more efficiently allocate capital in our society.
Architecture Overview
Injective enables traders to create and trade on arbitrary spot and derivative markets. The entire process includes on-chain limit orderbook management, on-chain trade execution, on-chain order matching, on-chain transaction settlement, and on-chain trading incentive distribution through the logic codified by the Injective Chain's exchange module.
Architecturally there are two main services that traders should concern themselves with:
- The Injective Chain node (the Chain API)
- The Injective Exchange API
The trading lifecycle is as follows:
- First, traders cryptographically sign a transaction containing one or more order messages (e.g.
MsgBatchCreateDerivativeLimitOrders
,MsgCreateSpotMarketOrder
,MsgCancelDerivativeLimitOrder
, etc. ). - Then the transaction is broadcasted to an Injective Chain node.
- The transaction is then added to the mempool and becomes included in a block. More details on this process can be found here.
- The handler for each respective message is run. During handler execution, order cancel and liquidation messages are processed immediately, whereas order creation messages are added to a queue.
- At the end of the block, the batch auction process for order matching begins.
- First, the queued market orders are executed against the resting orderbook (which does NOT include the new orders from the current block) and are cleared at a uniform clearing price.
- Second, the queued limit orders are matched against each other and the resting orderbook to result in an uncrossed orderbook. Limit orders created in that block are cleared at a uniform clearing price while resting limit orders created in previous blocks are cleared at an equal or better price than their limit order price.
- The funds are settled accordingly, with positions being created for derivative trades and assets being swapped for spot trades.
- Events containing the trade and settlement information are emitted by the Chain.
- The Injective Exchange API backend indexes the events and pushes updates to all subscribed traders.
Key Differences To CEX
- All information is public which includes things like untriggered Stop/Take orders or pending orders in the mempool.
- The data stored on-chain is minimal for performance reasons and reflects only the current state; exchange dApps provide additional historical data as well as a user interface for traders through the Injective Exchange API backend.
- Usually a DEX has front-running issues, but those are mitigated at Injective through fast block times and FBA (Frequent Batch Auction).
- The order of execution is different. Any new exchange action is a new transaction and is not executed immediately. Instead, it is added to a queue (mempool) and executed once the block is committed. At the time of the block commit, all included transactions happen more or less instantly. Firstly, code that is inside the handler is executed in the transaction sequence which is decided by the miner. This is not a problem since the sequence does not affect matching prices due to FBA and thus fairness is guaranteed.
To summarize the sequence of state changes on the Injective Chain:
- Mempool: A queue of pending transactions.
- BeginBlocker: Code that is executed at the beginning of every block. We use it for certain maintenance tasks (details can be found in the exchange module documentation).
- Handler: Code that is executed when a transaction is included in a block.
- EndBlocker: Code that is executed at the end of every block. We use it to match orders, calculate changes in funds, and update positions.
Comparison to CEX
Centralized Exchange (CEX) | Decentralized Exchange (DEX) |
---|---|
Exchange Gateway | Injective Chain Handler |
Exchange Matching Engine | Injective Chain EndBlocker |
Exchange Trade Report | Injective Chain EndBlocker |
Co-location | Injective Node (Decentralized Validators) |
Frequent Batch Auction (FBA)
The goal is to further prevent any Front-Running in a decentralized setting. Most DEX's suffer from this as all information is public and traders can collude with miners or pay high gas fees enabling them to front-run any trades. We mitigate this by combining fast block times with a Frequent Batch Auction:
In any given block:
- Calculate one uniform clearing price for all market orders and execute them. For an example for the market order matching in FBA fashion, look here.
- Limit orders are combined with the resting orderbook and orders are matched as long as there is still negative spread. The limit orders are all matched at one uniform clearing price. For an example for the limit order matching in FBA fashion, look here.
Trading Fees and Gas
If you are a trader on existing centralized exchanges, you will be familiar with the concept of trading fees. Traders are charged a fee for each successful trade. However, for a DEX, there are additional gas costs that must be paid to the network. And luckily, the gas fee from trading on Injective is very minimal.
- If you are a trader using a DEX UI, you don't need to worry about gas costs because the exchange dApp will pay them for you. However, you will pay trading fees in full.
- If you are using the API, then you will need to pay the gas costs.
- The gas costs are currently minimal, 20K transactions will cost about 1 INJ.
- You can set the fee_recipient to your own wallet address to save 40% of all trading fees.
Note: trading from bank balances, which automatically uses the default subaccount 0, will cost roughly 15% more gas than trading from other subaccounts. API traders can use other subaccounts to trade to avoid the extra gas fees—read here for more information.
Mark Price Margin Requirement
Quantity = 2 BTC, InitialMarginRatio = 0.05
MarkPrice = $45,000, EntryPrice = $43,000
Margin ≥ 2 * 0.05 * $45,000 = $4,500
MarginLong ≥ max(2 * (0.05 * $45,000 - ($45,000 - $43,000)), $4,500)
MarginLong ≥ max($500, $4,500) = $4,500
MarginShort ≥ max(2 * (0.05 * $45,000 - ($43,000 - $45,000)), $4,500)
MarginShort ≥ max($8,500, $4,500) = $8,500
So in this case if the trader wanted to create a short position with
an entry price which essentially starts at a loss of $2,000 as
unrealized PNL, he would need to post at a minimum $8,500 as margin,
rather than the usual required $4,500.
You might be familiar with margin requirements on Centralized Exchanges. When creating a new position, it must fulfill the following requirement:
Margin >= InitialMarginRatio * Quantity * EntryPrice
For example in a market with maximally 20x leverage, your initial margin must be at least 0.05 of the order's notional (entryPrice * quantity
). On Injective additionally the margin must also fulfill the following mark price requirement:
Margin >= Quantity * (InitialMarginRatio * MarkPrice - PNL)
where PNL
is the expected profit and loss of the position if it was closed at the MarkPrice.
Liquidations
Long Position:
Quantity = 1 BTC, MaintenanceMarginRatio = 0.05
EntryPrice = $50,000, Margin = $5,000
Now the MarkPrice drops down to $47,300, which is below the liquidation price of $47,368.42 (when margin = $2,368.42, maintenance ratio ≈ .04999998).
The position is auto-closed via reduce-only order:
Sell order:
Quantity = 1 BTC, Price = $0, Margin = $0
Assuming it gets matched with a clearing price of 47,100:
Liquidation Payout = Position Margin + PNL = $5,000 - $2,900 = $2,100
Liquidator Profit = $2,100 * 0.5 = $1,050
Insurance Fund Profit = $2,100 * 0.5 = $1,050
When your position falls below the maintenance margin ratio, the position can and likely will be liquidated by anyone running the liquidator bot. You will loose your entire position and all funds remaining in the position. On-chain, a reduce-only market order of the same size as the position is automatically created. The market order will have a worst price defined as Infinity or 0, implying it will be matched at whatever prices are available in the order book.
One key difference is that the payout from executing the reduce-only market order will not go towards the position owner. Instead, half of the remaining funds are transferred to the liquidator bot and the other half is transferred to the insurance fund.
If the payout in the position was negative, i.e., the position's negative PNL was greater than its margin, then the insurance fund will cover the missing funds.
Note: liquidations are executed immediately in a block before any other order matching occurs.
Fee Discounts
Fee discounts are enabled by looking at the past trailing 30 day window. As long as you meet both conditions for a tier (volume traded AND staked amount), you will receive the respective discounts.
- Note that there is a caching mechanism in place which can take up to one day before being updated with a new tier.
- Negative maker fee markets are not eligible for discounts.
Funding Rate
The hourly funding rate on perpetual markets determines the percentage that traders on one side have to pay to the other side each hour. If the rate is positive, longs pay shorts. If the rate is negative, shorts pay longs. The further trade prices deviate from the mark price within the hour, the higher the funding rate will be up to a maximum of 0.0625% (1.5% per day).
Closing a Position
Suppose you have an open position:
- Direction = Long
- Margin = $5,000
- EntryPrice = $50,000
- Quantity = 0.5 BTC
You create a new vanilla order for
- Direction = Sell
- Margin = $10,000
- Price = $35,000
- Quantity = 0.75 BTC
which is fully matched. First, the position is fully closed:
- OrderMarginUsedForClosing = OrderMargin * CloseQuantity / OrderQuantity
- OrderMarginUsedForClosing = $10,000 * 0.5 / 0.75 = $6,667
The proportional closing order margin is then used for the payout:
- Payout = PNL + PositionMargin + OrderMarginUsedForClosing
- Payout = ($35,000-$50,000) * 0.5 + $5,000 + $6,667 = $4,167
And a new position is opened in the opposite direction:
- Direction = Short
- Margin = $3,333
- Price = $35,000
- Quantity = 0.25 BTC
There are two ways to close a position:
Closing via Reduce-Only Order
When you close a position via a reduce-only order, no additional margin is used from the order. All reduce-only orders have a margin of zero. In addition, reduce-only orders are only used to close positions, not to open new ones.
Closing via Vanilla Order
You can also close a position via vanilla orders. When a sell vanilla order is getting matched while you have an open Long position, the position will be closed at the price of the sell order. Depending on the size of the order and position, the position may be either
- partially closed
- fully closed
- or fully closed with subsequent opening of a new position in the opposite direction.
Note that how the margin inside the order is used depends on which of the three scenarios you are in. If you close a position via vanilla order, the margin is only used to cover PNL payouts, not to go into the position. If the order subsequently opens a new position in the opposite direction (scenario 3), the remaining proportional margin will go towards the new position.
Trading Rewards
Assume you have a trading rewards campaign with 100 INJ as rewards:
Reward Tokens: 100 INJ
Trader Reward Points = 100
Total Reward Points = 1,000
Trader Rewards = Trader Reward Points / Total Reward Points * Reward Tokens
Trader Rewards = 100 / 1,000 * 100 INJ = 10 INJ
During a given campaign, the exchange will record each trader's cumulative trading reward points obtained from trading fees (with boosts applied, if applicable) from all eligible markets. At the end of each campaign each trader will receive a pro-rata percentage of the trading rewards pool based off their trading rewards points from that campaign epoch. Those rewards will be automatically deposited into the trader's respective wallets, it's not necessary to manually withdraw them.
Reduce-Only Order Precedence
Imagine a trader has the following position:
- LONG:
1 BTC
with EntryPrice of $59,000
And the following SELL orders:
Buy Price | Quantity | Order Type |
---|---|---|
$66,500 | 0.2 BTC | Vanilla |
$65,500 | 0.1 BTC | Reduce-only |
$65,400 | 0.1 BTC | Vanilla |
$64,500 | 0.3 BTC | Vanilla |
$63,500 | 0.1 BTC | Reduce-only |
This has some implications when placing new orders.
Upon placing a reduce-only order:
We check if any reduce-only orders would be invalid after executing all of the trader's other limit sell orders that have better prices in the same direction.
In our example, consider a new reduce-only order of 0.4 BTC
at $64,600
.
Sell Price | Quantity | Order Type |
---|---|---|
$66,500 | 0.2 BTC | Vanilla |
$65,500 | 0.1 BTC | Reduce-only |
$65,400 | 0.1 BTC | Vanilla |
$64,600 | 0.4 BTC | Reduce-only |
$64,500 | 0.3 BTC | Vanilla |
$63,500 | 0.1 BTC | Reduce-only |
This is perfectly valid and no further action is required. If the buy price hit $65,500 and all limit sell orders less than or equal to that price were filled, then the long position would be closed. If the price hit $66,500 and the vanilla sell order was filled, then the trader would open a 0.2 BTC short position. But what if the reduce-only order was for 0.5 BTC
instead?
Sell Price | Quantity | Order Type |
---|---|---|
$66,500 | 0.2 BTC | Vanilla |
$65,500 | 0.1 BTC | Reduce-only |
$65,400 | 0.1 BTC | Vanilla |
$64,600 | 0.5 BTC | Reduce-only |
$64,500 | 0.3 BTC | Vanilla |
$63,500 | 0.1 BTC | Reduce-only |
If the orders are getting matched, once the last vanilla order of 0.1 BTC at $65,400 is filled, the position will have been reduced to 1 BTC - 0.1 BTC - 0.3 BTC - 0.5 BTC - 0.1 BTC = 0 BTC
. The next reduce-only order of 0.1 BTC at $65,500 will thus be invalid.
To prevent that, we automatically cancel all reduce-only orders at a price where the cumulative sum of orders up to and including the reduce-only order would add up to more than the trader’s current long amount. Another way to think about it: we find the reduce-only order with the highest price such that all orders (vanilla and reduce-only) including and below that price add up in quantity to less than the long quantity. All reduce-only orders above that price will be canceled so that no reduce-only orders exist when the position is closed or short. The same concept applies to reduce-only orders on short positions, but we look for the lowest price instead of the highest on buy orders so that no reduce-only orders exist when the position is closed or long.
Upon placing a vanilla limit order:
We check if any reduce-only limit orders would be invalidated if all the orders up to and including the new vanilla limit order were filled.
In our example, consider a new vanilla order of 0.4 BTC
at $64,600
.
Sell Price | Quantity | Order Type |
---|---|---|
$66,500 | 0.2 BTC | Vanilla |
$65,500 | 0.1 BTC | Reduce-only |
$65,400 | 0.1 BTC | Vanilla |
$64,600 | 0.4 BTC | Vanilla |
$64,500 | 0.3 BTC | Vanilla |
$63,500 | 0.1 BTC | Reduce-only |
Again this perfectly valid and no further action is required because all order quantities up to the highest priced reduce-only order add up to ≤ the long position quantity. But what if the order was for 0.5 BTC
instead?
Sell Price | Quantity | Order Type |
---|---|---|
$66,500 | 0.2 BTC | Vanilla |
$65,500 | 0.1 BTC | Reduce-only |
$65,400 | 0.1 BTC | Vanilla |
$64,600 | 0.5 BTC | Vanilla |
$64,500 | 0.3 BTC | Vanilla |
$63,500 | 0.1 BTC | Reduce-only |
If the orders are getting matched, once the last reduce-only order of $65,500 is reached, the position will have been reduced to 1 BTC - 0.1 BTC - 0.3 BTC - 0.5 BTC - 0.1 BTC = 0 BTC
. A reduce-only order of 0.1 BTC after that will thus be invalid.
To prevent this, we automatically cancel the existing 0.1 BTC reduce-only order. In other words, new vanilla limit orders can invalidate and auto-cancel existing reduce-only limit orders if the reduce-only order becomes invalid at its price.
Rate Limits
The public mainnet and testnet nodes have a request rate limit associated to the requester IP address. The limits are:
- 20 requests/second for the "chain" group
- 50 requests/second for the "indexer" group
Each endpoint's section in this document clarifies which group the endpoint belongs to. When the limit is reached the server will respond sending an error response with code 429.
Order types
- BUY (1): A standard buy order to purchase an asset at either the current market price or a set limit price. Market orders in Injective also have a price to stablish a limit to the market price the order will be executed with.
- SELL (2): A standard sell order to sell an asset at either the current market price or a set limit price. Market orders in Injective also have a price to stablish a limit to the market price the order will be executed with.
- STOP_BUY (3): A stop-loss buy order converts into a regular buy order once the oracle price reaches or surpasses a specified trigger price.
- STOP_SELL (4): A stop-loss sell order becomes a regular sell order once the oracle price drops to or below a specified trigger price.
- TAKE_BUY (5): A take-profit buy order converts into a regular buy order once the oracle price reaches or surpasses a specified trigger price.
- TAKE_SELL (6): A take-profit sell order becomes a regular sell order once the oracle price drops to or below a specified trigger price.
- BUY_PO (7): Post-Only Buy. This order type ensures that the order will only be added to the order book and not match with a pre-existing order. It guarantees that you will be the market "maker" and not the "taker".
- SELL_PO (8): Post-Only Sell. Similar to BUY_PO, this ensures that your sell order will only add liquidity to the order book and not match with a pre-existing order.
- BUY_ATOMIC (9): An atomic buy order is a market order that gets executed instantly, bypassing the Frequent Batch Auctions (FBA). It's intended for smart contracts that need to execute a trade instantly. A higher fee is paid defined in the global exchange parameters (currently it is two times the normal trading fee).
- SELL_ATOMIC (10): An atomic sell order is similar to a BUY_ATOMIC, and it gets executed instantly at the current market price, bypassing the FBA.
Market and Limit Order Examples
Adding a Spot Market Buy Order
Maker Fee = -0.01%
Taker Fee = 0.1%
Market Buy Order:
Quantity = 1,000 INJ
Worst Price = 5 USDT
→ The account's available balance is decremented by 5,000 USDT + Taker Fee = 5,005 USDT
.
Upon matching with a resting sell order with price of 4 USDT
the new account balances are calculated as:
Trading Fee = 1,000 * 4 * 0.001 = 4 USDT
Credit Amount = 1,000 INJ
Debit Amount = 1,000 * 4 + 4 = 4,004 USDT
Clearing Refund = 5,005 - 4,004 = 1,001 USDT
Adding a Spot Market Sell Order
Maker Fee = -0.01%
Taker Fee = 0.1%
Market Sell Order:
Quantity = 1,000 INJ
Worst Price = 3 USDT
→ The account's available balance is decremented by 1,000 INJ
.
Upon matching with a resting sell order with price of 4 USDT
the new account balances are calculated as:
Trading Fee = 1,000 * 4 * 0.001 = 4 USDT
Debit Amount = 1,000 INJ
Credit Amount = 1,000 * 4 - 4 = 3,996 USDT
Clearing Refund = 0
Adding a Spot Limit Buy Order
Maker Fee = -0.01%
Taker Fee = 0.1%
We initially assume taker fees for the limit order in case the limit order is matched immediately. With price and quantity of:
Quantity = 1,000 INJ
Price = 5 USDT
→ The account's available balance is decremented by 5,000 USDT + Taker Fee = 5,005 USDT
.
After the order is submitted:
- If Matched Immediately: the limit order is filled and no fees are refunded since taker fees were previously deducted from the account's available balance. However, if Post-Only was selected, then the order will not be matched and will be rejected, with the trading fees being refunded. Assuming a clearing price of 4 USDT and a non Post-Only order:
Trading Fee = 1,000 * 4 * 0.001 = 4 USDT
Credit Amount = 5,000 - 4,000 = 1,000 INJ
Debit Amount = 1,000 * 4 + 4 = 4,004 USDT
Clearing Refund = 5,005 - 4,004 = 1,001 USDT
Unmatched Fee Refund = 0 USDT
- If Entirely Unmatched, the order becomes a resting limit order and we refund the taker fee:
Fee Refund = 1,000 * 5 * (0.001) = 5 USDT
- If Filled Later by Market Order, a maker fee will be charged, or a rebate will be credited. Since the order is filled by Market Order, the clearing price will be the price set in the limit order:
Trading Fee Rebate = 1,000 * 5 * -0.0001 = 0.5 USDT
Credit Amount = 1,000 INJ + 0.5 USDT
Debit Amount (in quote asset) = 1,000 * 5 = 5,000 USDT
If Partially Matched Immediately: the portion of the limit order that is filled immediately is charged taker fees with the rest being charged/credited maker fees/rebates. Assuming half the order is matched at a clearing price of 4 USDT and half the order is filled by Market Order at 5 USDT:
- Portion Immediately Filled:
Taker Trading Fee = 500 * 4 * 0.001 = 2 USDT
Credit Amount = 500 INJ
Debit Amount (Including Fees) = 500 * 4 + 2 = 2,002 USDT
Clearing Refund = (quantity of order filled * limit price) - (quantity of order filled * clearing price) + (proportional difference between limit fees and clearing fees)= (500 * 5) - (500 * 4) + ((500 * 5) * 0.001 - (500 * 4) * 0.001) = 500.5 USDT
Unmatched Fee Refund = quantity of order unfilled * limit price * taker fee rate = 500 * 5 * 0.001 = 2.5 USDT
- Rest of Order Filled Later by Market Order:
Maker Trading Fee Rebate = 500 * 5 * -0.0001 = 0.25 USDT
Credit Amount = 500 INJ
Debit Amount = 500 * 5 = 2,500 USDT
Clearing Refund = 0 USDT
- In Total:
Net Trading Fee = 2 - 0.25 = 1.75 USDT
Credit Amount (Including Maker Fee Rebates) = 1000 INJ + 0.25 USDT
Debit Amount (Including Taker Fees) = 4,502 USDT
- Portion Immediately Filled:
Adding a Spot Limit Sell Order
Maker Fee = -0.01%
Taker Fee = 0.1%
We initially assume taker fees for the limit order in case the limit order is matched immediately. With price and quantity of:
Quantity = 1,000 INJ
Price = 3 USDT
→ The account's available balance is decremented by 1,000 INJ
.
After the order is submitted:
- If Matched Immediately: the limit order is filled and taker fees are deducted, unless Post-Only is selected, in which case the order will not be matched and will be rejected with no trading fees being charged. Assuming a clearing price of 4 USDT:
Trading Fee = 1,000 * 4 * 0.001 = 4 USDT
Credit Amount = 1,000 * 4 - 4 = 3,996 USDT
Debit Amount = 1,000 INJ
Clearing Refund = 0 ETH
Fee Refund/Rebate = 0 USDT
- If Filled Later by Market Order, a maker fee rebate will be credited. Since the order is filled by Market Order, the clearing price will be the price set in the limit order:
Maker Trading Rebate = 1,000 * 3 * 0.0001 = 0.3 USDT
Credit Amount (in quote asset) = 1,000 * 3 + 0.3 = 3,000.3 USDT
Debit Amount (in base asset) = 1,000 INJ
- If Partially Matched Immediately: the portion of the limit order that is filled immediately is charged taker fees with the rest being charged maker fees. Similar logic to a spot limit buy order applies.
Derivative Market Order Payouts
The payouts for derivative market orders work the same way as for derivative limit orders, with the one difference being they are cancelled if not immediately matched. See spot market and derivative limit orders as reference.
Adding a Derivative Limit Buy Order
Quantity = 1,000 INJ
,Price = 5 USDT
,Margin = 1,000 USDT
TakerFeeRate = 0.001
MakerFeeRate = -0.0001
→ The account's available balance is decremented by Margin + Taker Fee = 1000 + 5000 * 0.001 = 1005 USDT
.
After creation:
If Unmatched, the order becomes a resting limit order (maker) and we refund the taker fee on vanilla orders (reduce-only orders don't pay upfront fees):
Fee Refund = 5 USDT
If Matched:
Assuming:
- a clearing price of 4 USDT
an existing
SHORT
position:Position Quantity = 600 INJ
Position Entry Price = 4.5 USDT
Position Margin = 400 USDT
Would result in:
1. Closing existing position with proportional order margin for closing:
CloseExecutionMargin = ExecutionMargin * CloseQuantity / OrderQuantity = 1000 * 600 / 1000 = 600 USDT
- Where
CloseExecutionMargin = Portion of margin used to close position
- And
ExecutionMargin = Margin supplied in new order
- Where
ClosingPayout = PNL + PositionMargin * CloseQuantity / PositionQuantity + CloseExecutionMargin
Short PNL = CloseQuantity * (EntryPrice - FillPrice) = 600 * (4.5 - 4) = 300 USDT
ClosingPayout = 300 + 400 * 600 / 600 + 600 = 1300 USDT
2. Opening new position in opposite direction:
a new
LONG
position:Position Quantity = 400 INJ
Position Entry Price = 4 USDT
NewPositionMargin = ExecutionMargin - CloseExecutionMargin = 1000 - 600 = 400 USDT
3. Refunding margin difference from order price vs. clearing price:
- Since the order was placed with 5x leverage at a price of 5 USDT, some margin is refunded with the new clearing price to maintain the 5x leverage.
Margin Refund = NewPositionMargin - NewPositionMarginRequired = 400 - 400 * 4 / 5 = 80 USDT
4. Refunding fee difference from order price vs. clearing price:
PriceDelta = Price - ClearingPrice = 5 - 4 = 1 USDT
ClearingFeeRefund = FillQuantity * PriceDelta * TakerFeeRate = 1000 * 1 * 0.001 = 1 USDT
- In the case of matching a sell order, this would have been a charge, not a refund
Market Order Matching
Existing Orderbook
Sells | Buys | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
New Orders
- 1x market buy order for 0.2 BTC with worst price 64,360
- 1x market buy order for 0.4 BTC with worst price 66,000
- 1x market sell order for 0.1 BTC with worst price 60,000
- 1x market sell order for 0.2 BTC with worst price 61,000
- 1x market sell order for 0.3 BTC with worst price 69,000
Resulting Orderbook
Sells | Buys | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
Market Buys: Matching the highest priced market buy order first for 0.4 BTC. Now for the second market buy order only 0.1 BTC is left at matchable price, meaning the other 0.1 BTC in the order will be cancelled. Both orders will be matched with the single resting limit order at a price of 64,360 for a total quantity of 0.5 BTC.
Market Sells: Matching the first two market sell orders for at a matching price of (64,210*0.1 + 64,205*0.2) / 0.3 = 64,206.67
for a total quantity of 0.3 BTC. The resting limit orders are both matched at their specified price points of 64,210 and 64,205. Since the last market sell order of 69,000 cannot be fulfilled, it is cancelled.
Limit Order Matching
Existing Orderbook
Sells | Buys | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
New Orders
Sells | Buys | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
Matching Orders
All new orders are incorporated into the existing orderbook. In our case this results in a negative spread:
Sells | Buys | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
As long as negative spread exists, orders are matched against each other. The first buy order is fully matched:
Sells | Buys | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
Now the second buy order can still be fully matched:
Sells | Buys | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
This is the end of the matching, since no more negative spread exists (64,220 > 62,210
).
All orders will be matched with a uniform clearing price within the range of the last sell order price and the last buy order price.
- Last sell order price: 64,220
- Last buy order price: 64,360
- 64,220 >= Clearing price >= 64,360
Step 1: Check if clearing price range is out of bounds regarding the resting orderbook mid price.
- Resting orderbook mid price: (64,250+64,210)/2 = 64,230
- Is within range of clearing price ✅ (if not, a clearing price of either last buy or last sell price would be used)
Step 2: Check if clearing price range is out of bounds regarding the mark price.
- Let's assume mark price is 64,300
- Is within range of clearing price ✅ (if not, a clearing price of either last buy or last sell price would be used)
Step 3: Set clearing price = mid price or mark price for spot or perpetual markets, respectively, or in the case where these prices are out of bounds, use last buy or last sell price.
Resources
Here you can find a comprehensive overview of the exchange ecosystem on Injective, guides and general resources for developers and API traders.
Coin denoms and market IDs for testnet and mainnet can be found on the Injective testnet explorer and mainnet explorer under the Markets tab and Assets tab.
Explorer
A Web interface that allows you to search for information on the Injective Chain
Faucet
A web-based service that provides free tokens to users on testnet and allows them to experiment on the Injective Chain.
Status
Monitor the uptime of all public services.
Message Broadcaster
In the examples included in this documentation you will see all the steps required to interact with the chain, from deriving a public key from a private key, creating messages to query the chain or creating orders, to creating and broadcasting transactions to the chain. Before going to the examples of all the possible actions it is important to state that you can avoid implementing yourself all the steps to create and configure correctly a transaction. If you are not interested in defining all the low level aspects you can use the component called MsgBroadcasterWithPk. To use the broadcaster you just need to create an instance of MsgBroadcasterWithPk, and once all the messages to be included in the transaction have been created, use the broadcast method, passing the messages as a parameter. The broadcaster will take care of: - Calculate the gas fee to pay for the transaction - Create the transaction and configure it - Sign the transaction - Broadcast it to the chain
Broadcaster for standard account
Calculate gas fee simulating the transaction
Example - Calculate gas fee simulating the transaction:
import asyncio
import os
import uuid
from decimal import Decimal
import dotenv
from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
private_key_in_hexa = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
composer = ProtoMsgComposer(network=network.string())
message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
network=network,
private_key=private_key_in_hexa,
)
priv_key = PrivateKey.from_hex(private_key_in_hexa)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
subaccount_id = address.get_subaccount_id(index=0)
# prepare trade info
fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
spot_market_id_create = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
spot_orders_to_create = [
composer.spot_order(
market_id=spot_market_id_create,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal("3"),
quantity=Decimal("55"),
order_type="BUY",
cid=(str(uuid.uuid4())),
),
composer.spot_order(
market_id=spot_market_id_create,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal("300"),
quantity=Decimal("55"),
order_type="SELL",
cid=str(uuid.uuid4()),
),
]
# prepare tx msg
msg = composer.msg_batch_update_orders(
sender=address.to_acc_bech32(),
spot_orders_to_create=spot_orders_to_create,
)
# broadcast the transaction
result = await message_broadcaster.broadcast([msg])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
For the broadcaster to calculate the gas fee running the simulation, create an instance of MsgBroadcasterWithPk
with the message new_using_simulation
.
This is the most common broadcaster configuration. Unless you are using grantee accounts (delegated accounts with authz) you should use this one.
Calculate gas fee without simulation
Example - Calculate gas fee without simulation:
import asyncio
import os
import uuid
from decimal import Decimal
import dotenv
from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
private_key_in_hexa = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
composer = ProtoMsgComposer(network=network.string())
message_broadcaster = MsgBroadcasterWithPk.new_without_simulation(
network=network,
private_key=private_key_in_hexa,
)
priv_key = PrivateKey.from_hex(private_key_in_hexa)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
subaccount_id = address.get_subaccount_id(index=0)
# prepare trade info
fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
spot_market_id_create = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
spot_orders_to_create = [
composer.spot_order(
market_id=spot_market_id_create,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal("3"),
quantity=Decimal("55"),
order_type="BUY",
cid=str(uuid.uuid4()),
),
composer.spot_order(
market_id=spot_market_id_create,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal("300"),
quantity=Decimal("55"),
order_type="SELL",
cid=str(uuid.uuid4()),
),
]
# prepare tx msg
msg = composer.msg_batch_update_orders(
sender=address.to_acc_bech32(),
spot_orders_to_create=spot_orders_to_create,
)
# broadcast the transaction
result = await message_broadcaster.broadcast([msg])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
For the broadcaster to calculate the gas fee based on the messages included without running the simulation, create an instance of MsgBroadcasterWithPk
with the message new_without_simulation
.
Broadcaster for grantee account
This is the required broadcaster configuration when operating with grantee accounts. The broadcaster will take care of creating the MsgExec
message, so that the user keeps passing the same messages to the broadcast
method that are passed when using the standard broadcaster with non-grantee accounts.
Calculate gas fee simulating the transaction
Example - Calculate gas fee simulating the transaction:
import asyncio
import os
import uuid
from decimal import Decimal
import dotenv
from pyinjective.async_client import AsyncClient
from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import Address, PrivateKey
async def main() -> None:
dotenv.load_dotenv()
private_key_in_hexa = os.getenv("INJECTIVE_GRANTEE_PRIVATE_KEY")
granter_inj_address = os.getenv("INJECTIVE_GRANTER_PUBLIC_ADDRESS")
# select network: local, testnet, mainnet
network = Network.testnet()
composer = ProtoMsgComposer(network=network.string())
# initialize grpc client
client = AsyncClient(network)
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(private_key_in_hexa)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
message_broadcaster = MsgBroadcasterWithPk.new_for_grantee_account_using_simulation(
network=network,
grantee_private_key=private_key_in_hexa,
)
# prepare tx msg
market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
granter_address = Address.from_acc_bech32(granter_inj_address)
granter_subaccount_id = granter_address.get_subaccount_id(index=0)
msg = composer.msg_create_spot_limit_order(
market_id=market_id,
sender=granter_inj_address,
subaccount_id=granter_subaccount_id,
fee_recipient=address.to_acc_bech32(),
price=Decimal("7.523"),
quantity=Decimal("0.01"),
order_type="BUY",
cid=str(uuid.uuid4()),
)
# broadcast the transaction
result = await message_broadcaster.broadcast([msg])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
For the broadcaster to calculate the gas fee running the simulation, create an instance of MsgBroadcasterWithPk
with the message new_for_grantee_account_using_simulation
.
Calculate gas fee without simulation
Example - Calculate gas fee without simulation:
import asyncio
import os
import uuid
from decimal import Decimal
import dotenv
from pyinjective.async_client import AsyncClient
from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import Address, PrivateKey
async def main() -> None:
dotenv.load_dotenv()
private_key_in_hexa = os.getenv("INJECTIVE_GRANTEE_PRIVATE_KEY")
granter_inj_address = os.getenv("INJECTIVE_GRANTER_PUBLIC_ADDRESS")
# select network: local, testnet, mainnet
network = Network.testnet()
composer = ProtoMsgComposer(network=network.string())
# initialize grpc client
client = AsyncClient(network)
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(private_key_in_hexa)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
message_broadcaster = MsgBroadcasterWithPk.new_for_grantee_account_without_simulation(
network=network,
grantee_private_key=private_key_in_hexa,
)
# prepare tx msg
market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
granter_address = Address.from_acc_bech32(granter_inj_address)
granter_subaccount_id = granter_address.get_subaccount_id(index=0)
msg = composer.msg_create_spot_limit_order(
market_id=market_id,
sender=granter_inj_address,
subaccount_id=granter_subaccount_id,
fee_recipient=address.to_acc_bech32(),
price=Decimal("7.523"),
quantity=Decimal("0.01"),
order_type="BUY",
cid=str(uuid.uuid4()),
)
# broadcast the transaction
result = await message_broadcaster.broadcast([msg])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
For the broadcaster to calculate the gas fee based on the messages included without running the simulation, create an instance of MsgBroadcasterWithPk
with the message new_for_grantee_account_without_simulation
.
NOTE:
There an important consideration when using the Transaction Broadcaster calculating the gas cost without simulation to send a MsgBatchUpdateOrders message.
The logic that estimates the gas cost for the MsgBatchUpdateOrders correclty calculates the gas required for each order action (creation or cancelation) it includes. But there is no easy way to calculate the gas cost when canceling all orders for a market id using one of the following parameters: spot_market_ids_to_cancel_all
, derivative_market_ids_to_cancel_all
or binary_options_market_ids_to_cancel_all
. The complexity is related to the fact that the gas cost depends on the number of orders to be cancelled.
By default the estimation logic calculates a gas cost considering the number of orders to cancel for each market id is 20.
To improve the gas cost calculation when using the MsgBatchUpdateOrders message to cancel all orders for one or more markets you can change the number of estimated orders to cancel per market running the following command:
BatchUpdateOrdersGasLimitEstimator.AVERAGE_CANCEL_ALL_AFFECTED_ORDERS = 30
Fine-tunning gas fee local estimation
As mentioned before the gas estimation without using simulation is implemented by using fixed values as gas cost for certain messages and actions. Since the real gas cost can differ at some point from the estimator calculations, the Python SDK allows the developer to fine-tune certain gas cost values in order to improve the gas cost estimation. In the next tables you can find the global values used for gas estimation calculations, that can be modified in your application:
Module | Global Variable | Description |
---|---|---|
pyinjective.core.gas_limit_estimator |
SPOT_ORDER_CREATION_GAS_LIMIT |
The gas cost associated to the creation of one spot order |
pyinjective.core.gas_limit_estimator |
DERIVATIVE_ORDER_CREATION_GAS_LIMIT |
The gas cost associated to the creation of one derivative order |
pyinjective.core.gas_limit_estimator |
SPOT_ORDER_CANCELATION_GAS_LIMIT |
The gas cost associated to the cancellation of one spot order |
pyinjective.core.gas_limit_estimator |
DERIVATIVE_ORDER_CANCELATION_GAS_LIMIT |
The gas cost associated to the cancellation of one derivative order |
pyinjective.core.gas_limit_estimator |
SPOT_POST_ONLY_ORDER_MULTIPLIER |
Multiplier to increase the gas cost for post only spot orders (in addition to the normal spot order cost) |
pyinjective.core.gas_limit_estimator |
DERIVATIVE_POST_ONLY_ORDER_MULTIPLIER |
Multiplier to increase the gas cost for post only derivative orders (in addition to the normal derivative order cost) |
Class | Global Variable | Description |
---|---|---|
MessageBasedTransactionFeeCalculator |
TRANSACTION_GAS_LIMIT |
The gas cost associated to the TX processing |
GasLimitEstimator |
GENERAL_MESSAGE_GAS_LIMIT |
Generic base gas cost for any message |
GasLimitEstimator |
BASIC_REFERENCE_GAS_LIMIT |
Base gas cost for messages not related to orders. Each type of message will calculate its cost multiplying this reference cost by a multiplier |
DefaultGasLimitEstimator |
DEFAULT_GAS_LIMIT |
The gas cost for all messages for which there is no especial estimator implemented |
BatchUpdateOrdersGasLimitEstimator |
CANCEL_ALL_SPOT_MARKET_GAS_LIMIT |
This is an estimation of the gas cost per spot order cancel when cancelling all orders for a spot market |
BatchUpdateOrdersGasLimitEstimator |
CANCEL_ALL_DERIVATIVE_MARKET_GAS_LIMIT |
This is an estimation of the gas cost per derivative order cancel when cancelling all orders for a derivative market |
BatchUpdateOrdersGasLimitEstimator |
MESSAGE_GAS_LIMIT |
Estimation of the general gas amount required for a MsgBatchUpdateOrders (not for particular actions, but for the general message processing) |
BatchUpdateOrdersGasLimitEstimator |
AVERAGE_CANCEL_ALL_AFFECTED_ORDERS |
This global represents the expected number of orders to be cancelled when executing a "cancel all orders for a market" action |
ExecGasLimitEstimator |
DEFAULT_GAS_LIMIT |
Estimation of the general gas amount required for a MsgExec (for the general message processing) |
GenericExchangeGasLimitEstimator |
BASIC_REFERENCE_GAS_LIMIT |
Base gas cost for messages not related to orders. Each type of message will calculate its cost multiplying this reference cost by a multiplier |
Indexer API
The Indexer API is read-only whereas the Chain API is write and also includes a limited set of API requests to read data. The Chain API reads query the blockchain state from the node directly as opposed to the Indexer API which reconstructs state from events emitted by chain.
On a high-level the end-user trading applications and Injective Products use the Indexer API to read data and the Chain API to write data to the blockchain. Even though it’s possible to develop trading applications using the Chain API only, the Indexer API includes more methods, streaming support, gRPC, and also allows you to fetch historical data (the Chain API queries the blockchain state which doesn’t include historical records).
- InjectiveAccountsRPC
InjectiveAccountsRPC defines the gRPC API of the Exchange Accounts provider.
SubaccountsList
Get a list of subaccounts for a specific address.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
account_address = "inj1clw20s2uxeyxtam6f7m84vgae92s9eh7vygagt"
subacc_list = await client.fetch_subaccounts_list(account_address)
print(subacc_list)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
accountAddress := "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku"
res, err := exchangeClient.GetSubaccountsList(ctx, accountAddress)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
account_address | String | Injective address of the account to query for subaccounts | Yes |
Response Parameters
Response Example:
{
"subaccounts":[
"0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001",
"0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000002",
"0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000000"
]
}
{
"subaccounts": [
"0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001",
"0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000002"
]
}
Parameter | Type | Description |
---|---|---|
subaccounts | String Array | Subaccounts list |
SubaccountHistory
Get the subaccount's transfer history.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
subaccount = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
denom = "inj"
transfer_types = ["withdraw", "deposit"]
skip = 1
limit = 15
end_time = 1665118340224
pagination = PaginationOption(skip=skip, limit=limit, end_time=end_time)
subacc_history = await client.fetch_subaccount_history(
subaccount_id=subaccount,
denom=denom,
transfer_types=transfer_types,
pagination=pagination,
)
print(subacc_history)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
accountPB "github.com/InjectiveLabs/sdk-go/exchange/accounts_rpc/pb"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
denom := "inj"
subaccountId := "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
transferTypes := []string{"deposit"}
skip := uint64(0)
limit := int32(10)
req := accountPB.SubaccountHistoryRequest{
Denom: denom,
SubaccountId: subaccountId,
TransferTypes: transferTypes,
Skip: skip,
Limit: limit,
}
res, err := exchangeClient.GetSubaccountHistory(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | ID of the subaccount to get the history from | Yes |
denom | String | Filter by token denom | No |
transfer_types | String Array | Filter by transfer types. Valid options: internal, external, withdraw, deposit | No |
skip | Integer | Skip the first N items from the result | No |
limit | Integer | Maximum number of items to be returned | No |
end_time | Integer | Upper bound (inclusive) of account transfer history executed_at unix timestamp | No |
Response Parameters
Response Example:
{
"transfers":[
{
"transferType":"deposit",
"srcAccountAddress":"inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"dstSubaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"amount":{
"denom":"inj",
"amount":"2000000000000000000"
},
"executedAt":"1665117493543",
"srcSubaccountId":"",
"dstAccountAddress":""
},
{
"transferType":"deposit",
"srcAccountAddress":"inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"dstSubaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"amount":{
"denom":"inj",
"amount":"15000000000000000000"
},
"executedAt":"1660313668990",
"srcSubaccountId":"",
"dstAccountAddress":""
}
],
"paging":{
"total":"3",
"from":0,
"to":0,
"countBySubaccount":"0",
"next":[
]
}
}
{
"transfers": [
{
"transfer_type": "deposit",
"src_account_address": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"dst_subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"amount": {
"denom": "inj",
"amount": "50000000000000000000"
},
"executed_at": 1651492257605
},
{
"transfer_type": "deposit",
"src_account_address": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"dst_subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"amount": {
"denom": "inj",
"amount": "1000000000000000000"
},
"executed_at": 1652453978939
}
],
"paging": [
{
"total": 3
}
]
}
Parameter | Type | Description |
---|---|---|
transfers | SubaccountBalanceTransfer Array | Transfers list |
paging | Paging | Pagination details |
SubaccountBalanceTransfer
Parameter | Type | Description |
---|---|---|
transfer_type | String | Type of subaccount balance transfer |
src_subaccount_id | String | Subaccount ID of the sending side |
src_account_address | String | Account address of the sending side |
dst_subaccount_id | String | Subaccount ID of the receiving side |
dst_account_address | String | Account address of the receiving side |
amount | CosmosCoin | Transfer amount |
executed_at | Integer | Transfer timestamp (in milliseconds) |
CosmosCoin
Parameter | Type | Description |
---|---|---|
denom | String | Token denom |
amount | String | Token amount |
Paging
Parameter | Type | Description |
---|---|---|
total | Integer | Total number of available records |
from | Integer | Record index start |
to | Integer | Record index end |
count_by_subaccount | Integer | Count entries by subaccount |
next | String Array | List of tokens to navigate to the next pages |
SubaccountBalance
Get the balance of a subaccount for a specific denom.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
subaccount_id = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
denom = "inj"
balance = await client.fetch_subaccount_balance(subaccount_id=subaccount_id, denom=denom)
print(balance)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
network := common.LoadNetwork("mainnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
subaccountId := "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
denom := "inj"
res, err := exchangeClient.GetSubaccountBalance(ctx, subaccountId, denom)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | ID of the subaccount to get the balances from | Yes |
denom | String | Filter by token denom | Yes |
Response Parameters
Response Example:
{
"balance":{
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"accountAddress":"inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"denom":"inj",
"deposit":{
"totalBalance":"0",
"availableBalance":"0"
}
}
}
{
"balance": {
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"account_address": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"denom": "inj",
"deposit": {
"total_balance": "1492235700000000000000",
"available_balance": "1492235700000000000000"
}
}
}
Parameter | Type | Description |
---|---|---|
balance | SubaccountBalance | Balance details |
SubaccountBalance
Parameter | Type | Description |
---|---|---|
subaccount_id | String | Subaccount ID |
account_address | String | Injective address of the account the subaccount belongs to |
denom | String | Token denom |
deposit | SubaccountDeposit | Deposit details |
SubaccountDeposit
Parameter | Type | Description |
---|---|---|
total_balance | String | Total balance |
available_balance | String | Available balance |
SubaccountBalancesList
List the subaccount's balances for all denoms.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
subaccount = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
denoms = ["inj", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"]
subacc_balances_list = await client.fetch_subaccount_balances_list(subaccount_id=subaccount, denoms=denoms)
print(subacc_balances_list)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
subaccountId := "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
res, err := exchangeClient.GetSubaccountBalancesList(ctx, subaccountId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | ID of the subaccount to get the balances from | Yes |
denoms | String | Filter balances by denoms. If not set, the balances of all the denoms for the subaccount are provided | No |
Response Parameters
Response Example:
{
"balances":[
{
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"accountAddress":"inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"deposit":{
"totalBalance":"131721505.337958346262317217",
"availableBalance":"0.337958346262317217"
}
},
{
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"accountAddress":"inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"denom":"inj",
"deposit":{
"totalBalance":"0",
"availableBalance":"0"
}
}
]
}
{
"balances": [
{
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"account_address": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
"deposit": {
"total_balance": "200501904612800.13082016560359584",
"available_balance": "200358014975479.130820165603595295"
}
},
{
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"account_address": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"denom": "inj",
"deposit": {
"total_balance": "53790000010000000003",
"available_balance": "52790000010000000003"
}
},
{
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"account_address": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"denom": "ibc/C4CFF46FD6DE35CA4CF4CE031E643C8FDC9BA4B99AE598E9B0ED98FE3A2319F9",
"deposit": {
"total_balance": "1000000",
"available_balance": "1000000"
}
}
]
}
Parameter | Type | Description |
---|---|---|
balances | SubaccountBalance Array | List of subaccount balances |
SubaccountBalance
Parameter | Type | Description |
---|---|---|
subaccount_id | String | Subaccount ID |
account_address | String | Injective address of the account the subaccount belongs to |
denom | String | Token denom |
deposit | SubaccountDeposit | Deposit details |
SubaccountDeposit
Parameter | Type | Description |
---|---|---|
total_balance | String | Total balance |
available_balance | String | Available balance |
SubaccountOrderSummary
Get a summary of the subaccount's active/unfilled orders.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
subaccount = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
order_direction = "buy"
market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
subacc_order_summary = await client.fetch_subaccount_order_summary(
subaccount_id=subaccount, order_direction=order_direction, market_id=market_id
)
print(subacc_order_summary)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
accountPB "github.com/InjectiveLabs/sdk-go/exchange/accounts_rpc/pb"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"
subaccountId := "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
orderDirection := "buy"
req := accountPB.SubaccountOrderSummaryRequest{
MarketId: marketId,
SubaccountId: subaccountId,
OrderDirection: orderDirection,
}
res, err := exchangeClient.GetSubaccountOrderSummary(ctx, &req)
if err != nil {
fmt.Println(err)
}
fmt.Println("spot orders:", res.SpotOrdersTotal)
fmt.Println("derivative orders:", res.DerivativeOrdersTotal)
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | ID of the subaccount to get the summary from | Yes |
market_id | String | Limit the order summary to a specific market | No |
order_direction | String | Filter by the direction of the orders. Valid options: buy, sell | No |
Response Parameters
Response Example:
{
"derivativeOrdersTotal":"1",
"spotOrdersTotal":"0"
}
spot orders: 1
derivative orders: 7
Parameter | Type | Description |
---|---|---|
spot_orders_total | Integer | Total count of subaccount's spot orders in given market and direction |
derivative_orders_total | Integer | Total count of subaccount's derivative orders in given market and direction |
StreamSubaccountBalance
Stream the subaccount's balance for all denoms.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from typing import Any, Dict
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def balance_event_processor(event: Dict[str, Any]):
print(event)
def stream_error_processor(exception: RpcError):
print(f"There was an error listening to balance updates ({exception})")
def stream_closed_processor():
print("The balance updates stream has been closed")
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
subaccount_id = "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001"
denoms = ["inj", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"]
task = asyncio.get_event_loop().create_task(
client.listen_subaccount_balance_updates(
subaccount_id=subaccount_id,
callback=balance_event_processor,
on_end_callback=stream_closed_processor,
on_status_callback=stream_error_processor,
denoms=denoms,
)
)
await asyncio.sleep(delay=60)
task.cancel()
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
subaccountId := "0x1b99514e320ae0087be7f87b1e3057853c43b799000000000000000000000000"
stream, err := exchangeClient.StreamSubaccountBalance(ctx, subaccountId)
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
return
default:
res, err := stream.Recv()
if err != nil {
fmt.Println(err)
return
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
}
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | ID of the subaccount to get the balances from | Yes |
denoms | String Array | Filter balances by denoms. If not set, the balances of all the denoms for the subaccount are provided | No |
Response Parameters
Streaming Response Example:
{
"balance": {
"subaccountId": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"accountAddress": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
"deposit": {
"totalBalance": "200493439765890.695319283887814576",
"availableBalance": "200493414240390.695319283887814031"
}
},
"timestamp": 1654234765000
}
{
"balance": {
"subaccountId": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"accountAddress": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
"deposit": {
"totalBalance": "200493847328858.695319283887814576",
"availableBalance": "200493821803358.695319283887814031"
}
},
"timestamp": 1654234804000
}
{
"balance": {
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"account_address": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
"deposit": {
"total_balance": "200503979400874.28368413692326264",
"available_balance": "200360046875708.283684136923262095"
}
},
"timestamp": 1653037703000
}{
"balance": {
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"account_address": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
"deposit": {
"total_balance": "200503560511302.28368413692326264",
"available_balance": "200359627986136.283684136923262095"
}
},
"timestamp": 1653037744000
}
Parameter | Type | Description |
---|---|---|
balance | SubaccountBalance | Subaccount balance |
timestamp | Integer | Operation timestamp in Unix milliseconds |
SubaccountBalance
Parameter | Type | Description |
---|---|---|
subaccount_id | String | Subaccount ID |
account_address | String | Injective address of the account the subaccount belongs to |
denom | String | Token denom |
deposit | SubaccountDeposit | Deposit details |
SubaccountDeposit
Parameter | Type | Description |
---|---|---|
total_balance | String | Total balance |
available_balance | String | Available balance |
OrderStates
Get orders with an order hash. This request will return market orders and limit orders in all states [booked, partial_filled, filled, canceled]. For filled and canceled orders, there is a TTL of 3 minutes. Should your order be filled or canceled you will still be able to fetch it for 3 minutes.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
spot_order_hashes = [
"0xce0d9b701f77cd6ddfda5dd3a4fe7b2d53ba83e5d6c054fb2e9e886200b7b7bb",
"0x2e2245b5431638d76c6e0cc6268970418a1b1b7df60a8e94b8cf37eae6105542",
]
derivative_order_hashes = [
"0x82113f3998999bdc3892feaab2c4e53ba06c5fe887a2d5f9763397240f24da50",
"0xbb1f036001378cecb5fff1cc69303919985b5bf058c32f37d5aaf9b804c07a06",
]
orders = await client.fetch_order_states(
spot_order_hashes=spot_order_hashes, derivative_order_hashes=derivative_order_hashes
)
print(orders)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
accountPB "github.com/InjectiveLabs/sdk-go/exchange/accounts_rpc/pb"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
spotOrderHashes := []string{"0x0b156df549747187210ca5381f0291f179d76d613d0bae1a3c4fd2e3c0504b7c"}
derivativeOrderHashes := []string{"0x82113f3998999bdc3892feaab2c4e53ba06c5fe887a2d5f9763397240f24da50"}
req := accountPB.OrderStatesRequest{
SpotOrderHashes: spotOrderHashes,
DerivativeOrderHashes: derivativeOrderHashes,
}
res, err := exchangeClient.GetOrderStates(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
spot_order_hashes | String Array | Array with the order hashes you want to fetch in spot markets | No |
derivative_order_hashes | String Array | Array with the order hashes you want to fetch in derivative markets | No |
Response Parameters
Response Example:
{
"spotOrderStates": [
{
"orderHash": "0xb7b556d6eab10c4c185a660be44757a8a6715fb16db39708f2f76d9ce5ae8617",
"subaccountId": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"marketId": "0x0511ddc4e6586f3bfe1acb2dd905f8b8a82c97e1edaef654b12ca7e6031ca0fa",
"orderType": "limit",
"orderSide": "buy",
"state": "booked",
"quantityFilled": "0",
"quantityRemaining": "1000000",
"createdAt": 1654080262300,
"updatedAt": 1654080262300
}
],
"derivativeOrderStates": [
{
"orderHash": "0x4228f9a56a5bb50de4ceadc64df694c77e7752d58b71a7c557a27ec10e1a094e",
"subaccountId": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"marketId": "0x1c79dac019f73e4060494ab1b4fcba734350656d6fc4d474f6a238c13c6f9ced",
"orderType": "limit",
"orderSide": "buy",
"state": "booked",
"quantityFilled": "0",
"quantityRemaining": "1",
"createdAt": 1654235059957,
"updatedAt": 1654235059957
}
]
}
{
"spot_order_states": [
{
"order_hash": "0xb7b556d6eab10c4c185a660be44757a8a6715fb16db39708f2f76d9ce5ae8617",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"market_id": "0x0511ddc4e6586f3bfe1acb2dd905f8b8a82c97e1edaef654b12ca7e6031ca0fa",
"order_type": "limit",
"order_side": "buy",
"state": "booked",
"quantity_filled": "0",
"quantity_remaining": "1000000",
"created_at": 1654080262300,
"updated_at": 1654080262300
}
],
"derivative_order_states": [
{
"order_hash": "0x4228f9a56a5bb50de4ceadc64df694c77e7752d58b71a7c557a27ec10e1a094e",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"market_id": "0x1c79dac019f73e4060494ab1b4fcba734350656d6fc4d474f6a238c13c6f9ced",
"order_type": "limit",
"order_side": "buy",
"state": "booked",
"quantity_filled": "0",
"quantity_remaining": "1",
"created_at": 1654235059957,
"updated_at": 1654235059957
}
]
}
Parameter | Type | Description |
---|---|---|
spot_order_states | OrderStateRecord Array | List of the spot order state records |
derivative_order_states | OrderStateRecord Array | List of the derivative order state records |
OrderStateRecord
Parameter | Type | Description |
---|---|---|
order_hash | String | Hash of the order |
subaccount_id | String | The subaccountId that this order belongs to |
market_id | String | The Market ID of the order |
order_type | String | The type of the order |
order_side | String | The side of the order |
state | String | The order state. Should be one of: booked, partial_filled, filled, canceled |
quantity_filled | String | The filled quantity of the order |
quantity_remaining | String | The unfilled quantity of the order |
created_at | Integer | Order committed timestamp in UNIX milliseconds |
updated_at | Integer | Order updated timestamp in UNIX milliseconds |
price | String | Order price |
margin | String | Margin for derivative order |
Portfolio
Get an overview of your portfolio.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
account_address = "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku"
portfolio = await client.fetch_portfolio(account_address=account_address)
print(portfolio)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
accountAddress := "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku"
res, err := exchangeClient.GetPortfolio(ctx, accountAddress)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
account_address | String | The Injective address | Yes |
Response Parameters
Response Example:
{
"portfolio":{
"portfolioValue":"6229.040631548905238875",
"availableBalance":"92.4500010811984646",
"lockedBalance":"13218.3573583009093604",
"unrealizedPnl":"-7081.766727833202586125",
"subaccounts":[
{
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000002",
"availableBalance":"0",
"lockedBalance":"0",
"unrealizedPnl":"0"
},
{
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000006",
"availableBalance":"0",
"lockedBalance":"0",
"unrealizedPnl":"0"
},
{
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000008",
"availableBalance":"0",
"lockedBalance":"0",
"unrealizedPnl":"0"
},
{
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000009",
"availableBalance":"0",
"lockedBalance":"0",
"unrealizedPnl":"0"
},
{
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f971347490200000061746f6d2d75736474",
"availableBalance":"0.00000066622556",
"lockedBalance":"0",
"unrealizedPnl":"0"
},
{
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"availableBalance":"0.0000003382963046",
"lockedBalance":"13218.3573583009093604",
"unrealizedPnl":"-7081.766727833202586125"
},
{
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f971347490200000000696e6a2d75736474",
"availableBalance":"0.0000000766766",
"lockedBalance":"0",
"unrealizedPnl":"0"
},
{
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000001",
"availableBalance":"92.45",
"lockedBalance":"0",
"unrealizedPnl":"0"
},
{
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000003",
"availableBalance":"0",
"lockedBalance":"0",
"unrealizedPnl":"0"
},
{
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000007",
"availableBalance":"0",
"lockedBalance":"0",
"unrealizedPnl":"0"
},
{
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000004",
"availableBalance":"0",
"lockedBalance":"0",
"unrealizedPnl":"0"
},
{
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000005",
"availableBalance":"0",
"lockedBalance":"0",
"unrealizedPnl":"0"
}
]
}
}
{
"portfolio": {
"portfolio_value": "16961.63886335580191347385",
"available_balance": "10127.8309908372442029",
"locked_balance": "8192.6038127728038576",
"unrealized_pnl": "-1358.79594025424614702615",
"subaccounts": [
{
"subaccount_id": "0x792bb0b9001d71a8efcb3c026ba4e34608a68a8c000000000000000000000000",
"available_balance": "10127.8309908372442029",
"locked_balance": "8192.6038127728038576",
"unrealized_pnl": "-1358.79594025424614702615"
}
]
}
}
Parameter | Type | Description |
---|---|---|
portfolio | AccountPortfolio | Portfolio details |
AccountPortfolio
Parameter | Type | Description |
---|---|---|
portfolio_value | String | The account's portfolio value in USD |
available_balance | String | The account's available balance value in USD |
locked_balance | String | The account's locked balance value in USD |
unrealized_pnl | String | The account's total unrealized PnL value in USD |
subaccounts | SubaccountPortfolio Array | List of all subaccounts' portfolio |
SubaccountPortfolio
Parameter | Type | Description |
---|---|---|
subaccount_id | String | The subaccount ID |
available_balance | String | The subaccount's available balance value in USD |
locked_balance | String | The subaccount's locked balance value in USD |
unrealized_pnl | String | The subaccount's total unrealized PnL value in USD |
Rewards
Get the rewards for Trade & Earn, the request will fetch all addresses for the latest epoch (-1) by default.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
account_address = "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku"
epoch = -1
rewards = await client.fetch_rewards(account_address=account_address, epoch=epoch)
print(rewards)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
accountPB "github.com/InjectiveLabs/sdk-go/exchange/accounts_rpc/pb"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
accountAddress := "inj1rwv4zn3jptsqs7l8lpa3uvzhs57y8duemete9e"
epoch := int64(1)
req := accountPB.RewardsRequest{
Epoch: epoch,
AccountAddress: accountAddress,
}
res, err := exchangeClient.GetRewards(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
epoch | Integer | The distribution epoch sequence number. -1 for latest | No |
account_address | String | Account address for the rewards distribution | No |
Response Parameters
Response Example:
{
"rewards":[
{
"accountAddress":"inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"rewards":[
{
"denom":"inj",
"amount":"11169382212463849"
}
],
"distributedAt":"1672218001897"
}
]
}
{
"rewards": [
{
"account_address": "inj1rwv4zn3jptsqs7l8lpa3uvzhs57y8duemete9e",
"rewards": [
{
"denom": "inj",
"amount": "755104058929571177652"
}
],
"distributed_at": 1642582800716
}
]
}
Parameter | Type | Description |
---|---|---|
rewards | Reward Array | The trading rewards distributed |
Reward
Parameter | Type | Description |
---|---|---|
account_address | String | Account Injective address |
rewards | Coin Array | Reward coins distributed |
distributed_at | Integer | Rewards distribution timestamp in UNIX milliseconds |
Coin
Parameter | Type | Description |
---|---|---|
denom | String | Token denom |
amount | String | Token amount |
- InjectiveSpotExchangeRPC
InjectiveSpotExchangeRPC defines the gRPC API of the Spot Exchange provider.
Market
Get details of a single spot market.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
market = await client.fetch_spot_market(market_id=market_id)
print(market)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"
res, err := exchangeClient.GetSpotMarket(ctx, marketId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | MarketId of the market we want to fetch | Yes |
Response Parameters
Response Example:
{
"market":{
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"marketStatus":"active",
"ticker":"INJ/USDT",
"baseDenom":"inj",
"baseTokenMeta":{
"name":"Injective Protocol",
"address":"0xe28b3B32B6c345A34Ff64674606124Dd5Aceca30",
"symbol":"INJ",
"logo":"https://static.alchemyapi.io/images/assets/7226.png",
"decimals":18,
"updatedAt":"1683119359318"
},
"quoteDenom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"quoteTokenMeta":{
"name":"Testnet Tether USDT",
"address":"0x0000000000000000000000000000000000000000",
"symbol":"USDT",
"logo":"https://static.alchemyapi.io/images/assets/825.png",
"decimals":6,
"updatedAt":"1683119359320"
},
"makerFeeRate":"-0.0001",
"takerFeeRate":"0.001",
"serviceProviderFee":"0.4",
"minPriceTickSize":"0.000000000000001",
"minQuantityTickSize":"1000000000000000",
"minNotional": "1000000"
}
}
{
"market": {
"market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
"market_status": "active",
"ticker": "INJ/USDT",
"base_denom": "inj",
"base_token_meta": {
"name": "Injective Protocol",
"address": "0xe28b3B32B6c345A34Ff64674606124Dd5Aceca30",
"symbol": "INJ",
"logo": "https://static.alchemyapi.io/images/assets/7226.png",
"decimals": 18,
"updated_at": 1650978921934
},
"quote_denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
"maker_fee_rate": "0.001",
"taker_fee_rate": "0.002",
"service_provider_fee": "0.4",
"min_price_tick_size": "0.000000000000001",
"min_quantity_tick_size": "1000000000000000",
"min_notional": "1000000"
}
}
Parameter | Type | Description |
---|---|---|
market | SpotMarketInfo | Info about particular spot market |
SpotMarketInfo
Parameter | Type | Description |
---|---|---|
base_denom | String | Coin denom of the base asset |
market_id | String | ID of the spot market of interest |
market_status | String | The status of the market (Should be one of: ["active", "paused", "suspended", "demolished", "expired"]) |
min_quantity_tick_size | String | Defines the minimum required tick size for the order's quantity |
quote_token_meta | TokenMeta | Token metadata for quote asset, only for Ethereum-based assets |
service_provider_fee | String | Percentage of the transaction fee shared with the service provider |
base_token_meta | TokenMeta | Token metadata for base asset, only for Ethereum-based assets |
maker_fee_rate | String | Defines the fee percentage makers pay (or receive, if negative) in quote asset when trading |
min_price_tick_size | String | Defines the minimum required tick size for the order's price |
quote_denom | String | Coin denom of the quote asset |
taker_fee_rate | String | Defines the fee percentage takers pay (in the quote asset) when trading |
ticker | String | A name of the pair in format AAA/BBB, where AAA is base asset, BBB is quote asset |
min_notional | String | Defines the minimum required notional for an order to be accepted |
TokenMeta
Parameter | Type | Description |
---|---|---|
address | String | Token's Ethereum contract address |
decimals | Integer | Token decimals |
logo | String | URL to the logo image |
name | String | Token full name |
symbol | String | Token symbol short name |
updatedAt | Integer | Token metadata fetched timestamp in UNIX millis |
Markets
Get a list of spot markets.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
market_status = "active"
base_denom = "inj"
quote_denom = "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"
market = await client.fetch_spot_markets(
market_statuses=[market_status], base_denom=base_denom, quote_denom=quote_denom
)
print(market)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
spotExchangePB "github.com/InjectiveLabs/sdk-go/exchange/spot_exchange_rpc/pb"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketStatus := "active"
quoteDenom := "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7"
req := spotExchangePB.MarketsRequest{
MarketStatus: marketStatus,
QuoteDenom: quoteDenom,
}
res, err := exchangeClient.GetSpotMarkets(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_statuses | String Array | Filter by status of the market (Should be any of: ["active", "paused", "suspended", "demolished", "expired"]) | No |
base_denom | String | Filter by the Coin denomination of the base currency | No |
quote_denom | String | Filter by the Coin denomination of the quote currency | No |
Response Parameters
Response Example:
{
"markets":[
{
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"marketStatus":"active",
"ticker":"INJ/USDT",
"baseDenom":"inj",
"baseTokenMeta":{
"name":"Injective Protocol",
"address":"0xe28b3B32B6c345A34Ff64674606124Dd5Aceca30",
"symbol":"INJ",
"logo":"https://static.alchemyapi.io/images/assets/7226.png",
"decimals":18,
"updatedAt":"1683119359318"
},
"quoteDenom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"quoteTokenMeta":{
"name":"Testnet Tether USDT",
"address":"0x0000000000000000000000000000000000000000",
"symbol":"USDT",
"logo":"https://static.alchemyapi.io/images/assets/825.png",
"decimals":6,
"updatedAt":"1683119359320"
},
"makerFeeRate":"-0.0001",
"takerFeeRate":"0.001",
"serviceProviderFee":"0.4",
"minPriceTickSize":"0.000000000000001",
"minQuantityTickSize":"1000000000000000",
"minNotional":"1000000"
}
]
}
{
"markets": [
{
"market_id": "0x01edfab47f124748dc89998eb33144af734484ba07099014594321729a0ca16b",
"market_status": "active",
"ticker": "AAVE/USDT",
"base_denom": "peggy0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9",
"base_token_meta": {
"name": "Aave",
"address": "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9",
"symbol": "AAVE",
"logo": "https://static.alchemyapi.io/images/assets/7278.png",
"decimals": 18,
"updated_at": 1650978921846
},
"quote_denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
"maker_fee_rate": "0.001",
"taker_fee_rate": "0.002",
"service_provider_fee": "0.4",
"min_price_tick_size": "0.000000000000001",
"min_quantity_tick_size": "1000000000000000"
},
{
"market_id": "0xe8bf0467208c24209c1cf0fd64833fa43eb6e8035869f9d043dbff815ab76d01",
"market_status": "active",
"ticker": "UNI/USDT",
"base_denom": "peggy0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984",
"base_token_meta": {
"name": "Uniswap",
"address": "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984",
"symbol": "UNI",
"logo": "https://static.alchemyapi.io/images/assets/7083.png",
"decimals": 18,
"updated_at": 1650978922133
},
"quote_denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
"maker_fee_rate": "0.001",
"taker_fee_rate": "0.002",
"service_provider_fee": "0.4",
"min_price_tick_size": "0.000000000000001",
"min_quantity_tick_size": "1000000000000000",
"min_notional": "1000000"
}
]
}
Parameter | Type | Description |
---|---|---|
markets | SpotMarketInfo Array | List of spot markets |
SpotMarketInfo
Parameter | Type | Description |
---|---|---|
base_denom | String | Coin denom of the base asset |
market_id | String | ID of the spot market of interest |
market_status | String | The status of the market (Should be one of: ["active", "paused", "suspended", "demolished", "expired"]) |
min_quantity_tick_size | String | Defines the minimum required tick size for the order's quantity |
quote_token_meta | TokenMeta | Token metadata for quote asset, only for Ethereum-based assets |
service_provider_fee | String | Percentage of the transaction fee shared with the service provider |
base_token_meta | TokenMeta | Token metadata for base asset, only for Ethereum-based assets |
maker_fee_rate | String | Defines the fee percentage makers pay (or receive, if negative) in quote asset when trading |
min_price_tick_size | String | Defines the minimum required tick size for the order's price |
quote_denom | String | Coin denom of the quote asset |
taker_fee_rate | String | Defines the fee percentage takers pay (in the quote asset) when trading |
ticker | String | A name of the pair in format AAA/BBB, where AAA is base asset, BBB is quote asset |
min_notional | String | Defines the minimum required notional for an order to be accepted |
TokenMeta
Parameter | Type | Description |
---|---|---|
address | String | Token's Ethereum contract address |
decimals | Integer | Token decimals |
logo | String | URL to the logo image |
name | String | Token full name |
symbol | String | Token symbol short name |
updatedAt | Integer | Token metadata fetched timestamp in UNIX millis |
StreamMarkets
Stream live updates of spot markets.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from typing import Any, Dict
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def market_event_processor(event: Dict[str, Any]):
print(event)
def stream_error_processor(exception: RpcError):
print(f"There was an error listening to spot markets updates ({exception})")
def stream_closed_processor():
print("The spot markets updates stream has been closed")
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.mainnet()
client = AsyncClient(network)
task = asyncio.get_event_loop().create_task(
client.listen_spot_markets_updates(
callback=market_event_processor,
on_end_callback=stream_closed_processor,
on_status_callback=stream_error_processor,
)
)
await asyncio.sleep(delay=60)
task.cancel()
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketIds := []string{"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"}
stream, err := exchangeClient.StreamSpotMarket(ctx, marketIds)
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
return
default:
res, err := stream.Recv()
if err != nil {
fmt.Println(err)
return
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
}
}
Parameter | Type | Description | Required |
---|---|---|---|
market_ids | String Array | List of market IDs for updates streaming, empty means 'ALL' spot markets | No |
Response Parameters
Streaming Response Example:
{
"market":{
"marketId":"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
"marketStatus":"active",
"ticker":"INJ/USDT",
"baseDenom":"inj",
"baseTokenMeta":{
"name":"Injective Protocol",
"address":"0xe28b3B32B6c345A34Ff64674606124Dd5Aceca30",
"symbol":"INJ",
"logo":"https://static.alchemyapi.io/images/assets/7226.png",
"decimals":18,
"updatedAt":1632535055751
},
"quoteDenom":"peggy0x69efCB62D98f4a6ff5a0b0CFaa4AAbB122e85e08",
"quoteTokenMeta":{
"name":"Tether",
"address":"0x69efCB62D98f4a6ff5a0b0CFaa4AAbB122e85e08",
"symbol":"USDT",
"logo":"https://static.alchemyapi.io/images/assets/825.png",
"decimals":6,
"updatedAt":1632535055759
},
"makerFeeRate":"0.001",
"takerFeeRate":"0.002",
"serviceProviderRate":"0.4",
"minPriceTickSize":"0.000000000000001",
"minQuantityTickSize":"1000000000000000",
"minNotional":"0"
},
"operationType":"update",
"timestamp":1632535055790
}
{
"market": {
"market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
"market_status": "active",
"ticker": "INJ/USDT",
"base_denom": "inj",
"base_token_meta": {
"name": "Injective Protocol",
"address": "0xe28b3B32B6c345A34Ff64674606124Dd5Aceca30",
"symbol": "INJ",
"logo": "https://static.alchemyapi.io/images/assets/7226.png",
"decimals": 18,
"updated_at": 1632535055751
},
"quote_denom": "peggy0x69efCB62D98f4a6ff5a0b0CFaa4AAbB122e85e08",
"quote_token_meta": {
"name": "Tether",
"address": "0x69efCB62D98f4a6ff5a0b0CFaa4AAbB122e85e08",
"symbol": "USDT",
"logo": "https://static.alchemyapi.io/images/assets/825.png",
"decimals": 6,
"updated_at": 1632535055759
},
"maker_fee_rate": "0.001",
"taker_fee_rate": "0.002",
"service_provider_fee": "0.4",
"min_price_tick_size": "0.000000000000001",
"min_quantity_tick_size": "1000000000000000",
"min_notional": "0",
},
"operation_type": "update",
"timestamp": 1632535055790
}
Parameter | Type | Description |
---|---|---|
market | SpotMarketInfo | Info about particular spot market |
operation_type | String | Update type (Should be one of: ["insert", "replace", "update", "invalidate"]) |
timestamp | Integer | Operation timestamp in UNIX millis |
SpotMarketInfo
Parameter | Type | Description |
---|---|---|
base_denom | String | Coin denom of the base asset |
market_id | String | ID of the spot market of interest |
market_status | String | The status of the market (Should be one of: ["active", "paused", "suspended", "demolished", "expired"]) |
min_quantity_tick_size | String | Defines the minimum required tick size for the order's quantity |
quote_token_meta | TokenMeta | Token metadata for quote asset, only for Ethereum-based assets |
service_provider_fee | String | Percentage of the transaction fee shared with the service provider |
base_token_meta | TokenMeta | Token metadata for base asset, only for Ethereum-based assets |
maker_fee_rate | String | Defines the fee percentage makers pay (or receive, if negative) in quote asset when trading |
min_price_tick_size | String | Defines the minimum required tick size for the order's price |
quote_denom | String | Coin denom of the quote asset |
taker_fee_rate | String | Defines the fee percentage takers pay (in the quote asset) when trading |
ticker | String | A name of the pair in format AAA/BBB, where AAA is base asset, BBB is quote asset |
min_notional | String | Defines the minimum required notional for an order to be accepted |
TokenMeta
Parameter | Type | Description |
---|---|---|
address | String | Token's Ethereum contract address |
decimals | Integer | Token decimals |
logo | String | URL to the logo image |
name | String | Token full name |
symbol | String | Token symbol short name |
updatedAt | Integer | Token metadata fetched timestamp in UNIX millis |
OrdersHistory
List history of orders (all states) for a spot market.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
market_ids = ["0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"]
subaccount_id = "0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000"
skip = 10
limit = 3
order_types = ["buy_po"]
pagination = PaginationOption(skip=skip, limit=limit)
orders = await client.fetch_spot_orders_history(
subaccount_id=subaccount_id,
market_ids=market_ids,
order_types=order_types,
pagination=pagination,
)
print(orders)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
spotExchangePB "github.com/InjectiveLabs/sdk-go/exchange/spot_exchange_rpc/pb"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
subaccountId := "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
skip := uint64(0)
limit := int32(10)
orderTypes := []string{"buy_po"}
req := spotExchangePB.OrdersHistoryRequest{
SubaccountId: subaccountId,
MarketId: marketId,
Skip: skip,
Limit: limit,
OrderTypes: orderTypes,
}
res, err := exchangeClient.GetHistoricalSpotOrders(ctx, &req)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | Filter by subaccount ID | No |
market_ids | String Array | Filter by multiple market IDs | No |
order_types | String Array | The order types to be included (Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell", "buy_po", "sell_po"]) | No |
direction | String | Filter by order direction (Should be one of: ["buy", "sell"]) | No |
state | String | The order state (Should be one of: ["booked", "partial_filled", "filled", "canceled"]) | No |
execution_types | String Array | The execution of the order (Should be one of: ["limit", "market"]) | No |
trade_id | String | Filter by the trade's trade id | No |
active_markets_only | Bool | Return only orders for active markets | No |
cid | String | Filter by the custom client order id of the trade's order | No |
pagination | PaginationOption | Pagination configuration | No |
Response Parameters
Response Example:
{
"orders":[
{
"orderHash":"0x4e6629ce45597a3dc3941c5382cc7bc542d52fbcc6b03c4fd604c94a9bec0cc1",
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"subaccountId":"0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000",
"executionType":"limit",
"orderType":"buy_po",
"price":"0.000000000000001",
"triggerPrice":"0",
"quantity":"1000000000000000",
"filledQuantity":"1000000000000000",
"state":"filled",
"createdAt":"1668264339149",
"updatedAt":"1682667017745",
"direction":"buy",
"txHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"isActive":false,
"cid":""
},
{
"orderHash":"0x347de654c8484fe36473c3569382ff27d25e95c660fd055163b7193607867a8b",
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"subaccountId":"0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000",
"executionType":"limit",
"orderType":"buy_po",
"price":"0.000000000000001",
"triggerPrice":"0",
"quantity":"1000000000000000",
"filledQuantity":"1000000000000000",
"state":"filled",
"createdAt":"1668264339149",
"updatedAt":"1682667017745",
"direction":"buy",
"txHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"isActive":false,
"cid":""
},
{
"orderHash":"0x2141d52714f5c9328170cc674de8ecf876463b1999bea4124d1de595152b718f",
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"subaccountId":"0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000",
"executionType":"limit",
"orderType":"buy_po",
"price":"0.000000000000001",
"triggerPrice":"0",
"quantity":"1000000000000000",
"filledQuantity":"1000000000000000",
"state":"filled",
"createdAt":"1668264339149",
"updatedAt":"1682667017745",
"direction":"buy",
"txHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"isActive":false,
"cid":""
}
],
"paging":{
"total":"1000",
"from":0,
"to":0,
"countBySubaccount":"0",
"next":[
]
}
}
{
"orders": [
{
"order_hash": "0x47a3858df766691a6124255a959ac17c79588fa36e52bed6d8aea2d927bb6a60",
"market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"execution_type": "limit",
"order_type": "buy_po",
"price": "0.000000000007789",
"trigger_price": "0",
"quantity": "12000000000000000000",
"filled_quantity": "12000000000000000000",
"state": "filled",
"created_at": 1681812187591,
"updated_at": 1681886620984,
"direction": "buy"
},
{
"order_hash": "0x4a0f7bec21c2861ec390510f461ab94a6e4425453e113ba41d67c5e79a45538b",
"market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"execution_type": "limit",
"order_type": "buy_po",
"price": "0.000000000007692",
"trigger_price": "0",
"quantity": "14000000000000000000",
"filled_quantity": "14000000000000000000",
"state": "filled",
"created_at": 1681812187591,
"updated_at": 1681886620984,
"direction": "buy"
},
{
"order_hash": "0x447b593a3c1683b64bd6ac4e60aa6ff22078951312eb3bfacf0b8b163eb015e4",
"market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"execution_type": "limit",
"order_type": "buy_po",
"price": "0.000000000005787",
"trigger_price": "0",
"quantity": "18000000000000000000",
"filled_quantity": "18000000000000000000",
"state": "filled",
"created_at": 1681812187591,
"updated_at": 1681886620984,
"direction": "buy"
},
{
"order_hash": "0x77d1c86d0b04b3347ace0f4a7f708adbb160d54701891d0c212a8c28bb10f77f",
"market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"execution_type": "limit",
"order_type": "buy_po",
"price": "0.000000000005457",
"trigger_price": "0",
"quantity": "8000000000000000000",
"filled_quantity": "8000000000000000000",
"state": "filled",
"created_at": 1681812187591,
"updated_at": 1681886620984,
"direction": "buy"
},
{
"order_hash": "0x76899c13fa3e591b1e2cbadfc2c84db5a7f4f97e42cee2451a6a90d04b100642",
"market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"execution_type": "limit",
"order_type": "buy_po",
"price": "0.000000000007134",
"trigger_price": "0",
"quantity": "4000000000000000000",
"filled_quantity": "4000000000000000000",
"state": "filled",
"created_at": 1681812187591,
"updated_at": 1681886620984,
"direction": "buy"
},
{
"order_hash": "0xf353711353a98ac3aceee62a4d7fed30e0c65cf38adfa898c455be5e5c671445",
"market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"execution_type": "limit",
"order_type": "buy_po",
"price": "0.000000000006138",
"trigger_price": "0",
"quantity": "2000000000000000000",
"filled_quantity": "2000000000000000000",
"state": "filled",
"created_at": 1681812187591,
"updated_at": 1681886620984,
"direction": "buy"
},
{
"order_hash": "0xb599db2124630b350e0ca2ea3453ece84e7721334e1009b451fa21d072a6cf8f",
"market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"execution_type": "limit",
"order_type": "buy_po",
"price": "0.000000000005667",
"trigger_price": "0",
"quantity": "22000000000000000000",
"filled_quantity": "22000000000000000000",
"state": "filled",
"created_at": 1681812187591,
"updated_at": 1681886620984,
"direction": "buy"
},
{
"order_hash": "0x1c28300cfebfef73c26e32d396162e45089e34a5ba0c627cc8b6e3fb1d9861ad",
"market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"execution_type": "limit",
"order_type": "buy_po",
"price": "0.000000000006263",
"trigger_price": "0",
"quantity": "20000000000000000000",
"filled_quantity": "20000000000000000000",
"state": "filled",
"created_at": 1681812187591,
"updated_at": 1681886620984,
"direction": "buy"
},
{
"order_hash": "0x7a2b9753c94c67f5e79e2f9dcd8af8a619d55d2f9ba1a134a22c5ef154b76e7f",
"market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"execution_type": "limit",
"order_type": "buy_po",
"price": "0.000000000007683",
"trigger_price": "0",
"quantity": "16000000000000000000",
"filled_quantity": "16000000000000000000",
"state": "filled",
"created_at": 1681812187591,
"updated_at": 1681886620984,
"direction": "buy"
},
{
"order_hash": "0x4984a08abefd29ba6bc914b11182251e18c0235842916955a4ffdc8ff149d188",
"market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"execution_type": "limit",
"order_type": "buy_po",
"price": "0.000000000007668",
"trigger_price": "0",
"quantity": "6000000000000000000",
"filled_quantity": "6000000000000000000",
"state": "filled",
"created_at": 1681812187591,
"updated_at": 1681886620984,
"direction": "buy"
}
],
"paging": {
"total": 1000
}
}
Parameter | Type | Description |
---|---|---|
orders | SpotOrderHistory Array | List of prior spot orders |
paging | Paging | Pagination of results |
SpotOrderHistory
Parameter | Type | Description |
---|---|---|
order_hash | String | Hash of the order |
market_id | String | ID of the spot market |
is_active | Boolean | Indicates if the order is active |
subaccount_id | String | ID of the subaccount that the order belongs to |
execution_type | String | The type of the order (Should be one of: ["limit", "market"]) |
order_type | String | Order type (Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell", "buy_po", "sell_po"]) |
price | String | Price of the order |
trigger_price | String | Trigger price used by stop/take orders |
quantity | String | Quantity of the order |
filled_quantity | String | The amount of the quantity filled |
state | String | Order state (Should be one of: ["booked", "partial_filled", "filled", "canceled"]) |
created_at | Integer | Order created timestamp in UNIX millis |
updated_at | Integer | Order updated timestamp in UNIX millis |
direction | String | The direction of the order (Should be one of: ["buy", "sell"]) |
tx_hash | String | Transaction hash in which the order was created (not all orders have this value) |
cid | String | Identifier for the order specified by the user (up to 36 characters, like a UUID) |
Paging
Parameter | Type | Description |
---|---|---|
total | Integer | Total number of available records |
StreamOrdersHistory
Stream order updates for spot markets. If no parameters are given, updates to all subaccounts in all spot markets will be streamed.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from typing import Any, Dict
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def order_event_processor(event: Dict[str, Any]):
print(event)
def stream_error_processor(exception: RpcError):
print(f"There was an error listening to spot orders history updates ({exception})")
def stream_closed_processor():
print("The spot orders history updates stream has been closed")
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
order_direction = "buy"
task = asyncio.get_event_loop().create_task(
client.listen_spot_orders_history_updates(
callback=order_event_processor,
on_end_callback=stream_closed_processor,
on_status_callback=stream_error_processor,
market_id=market_id,
direction=order_direction,
)
)
await asyncio.sleep(delay=60)
task.cancel()
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
spotExchangePB "github.com/InjectiveLabs/sdk-go/exchange/spot_exchange_rpc/pb"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
subaccountId := "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"
direction := "buy"
req := spotExchangePB.StreamOrdersHistoryRequest{
MarketId: marketId,
SubaccountId: subaccountId,
Direction: direction,
}
stream, err := exchangeClient.StreamHistoricalSpotOrders(ctx, &req)
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
return
default:
res, err := stream.Recv()
if err != nil {
panic(err)
return
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
}
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | Filter by market ID | No |
subaccount_id | String | Filter by subaccount ID | No |
direction | String | Filter by direction (Should be one of: ["buy", "sell"]) | No |
state | String | Filter by state (Should be one of: ["booked", "partial_filled", "filled", "canceled"]) | No |
order_types | String Array | Filter by order type (Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell", "buy_po", "sell_po"]) | No |
execution_types | String Array | Filter by execution type (Should be one of: ["limit", "market"]) | No |
callback | Function | Function receiving one parameter (a stream event JSON dictionary) to process each new event | Yes |
on_end_callback | Function | Function with the logic to execute when the stream connection is interrupted | No |
on_status_callback | Function | Function receiving one parameter (the exception) with the logic to execute when an exception happens | No |
Response Parameters
Streaming Response Example:
{
"order":{
"orderHash":"0xff6a1ce6339911bb6f0765e17e70144ae62834e65e551e910018203d62bc6d12",
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"subaccountId":"0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000004",
"executionType":"limit",
"orderType":"buy_po",
"price":"0.000000000019028",
"triggerPrice":"0",
"quantity":"67129093000000000000000",
"filledQuantity":"0",
"state":"canceled",
"createdAt":"1702044186286",
"updatedAt":"1702044188683",
"direction":"buy",
"txHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"isActive":false,
"cid":""
},
"operationType":"update",
"timestamp":"1702044191000"
}
{
"order": {
"order_hash": "0xf8a90ee4cfb4c938035b791d3b3561e8991803793b4b5590164b2ecbfa247f3d",
"market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"subaccount_id": "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000004",
"execution_type": "limit",
"order_type": "buy_po",
"price": "0.000000000007438",
"trigger_price": "0",
"quantity": "76848283000000000000000",
"filled_quantity": "0",
"state": "canceled",
"created_at": 1696621893030,
"updated_at": 1696621895445,
"direction": "buy"
},
"operation_type": "update",
"timestamp": 1696621898000
}{
"order": {
"order_hash": "0xfd6bf489944cb181ee94057b80ffdfc113a17d48d0455c8d10e4deadf341bdfd",
"market_id": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"subaccount_id": "0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000004",
"execution_type": "limit",
"order_type": "buy_po",
"price": "0.000000000007478",
"trigger_price": "0",
"quantity": "76437220000000000000000",
"filled_quantity": "0",
"state": "canceled",
"created_at": 1696621893030,
"updated_at": 1696621895445,
"direction": "buy"
},
"operation_type": "update",
"timestamp": 1696621898000
}
Parameter | Type | Description |
---|---|---|
order | SpotOrderHistory | Updated Order |
operation_type | String | Order update type (Should be one of: ["insert", "replace", "update", "invalidate"]) |
timestamp | Integer | Operation timestamp in UNIX millis |
SpotOrderHistory
Parameter | Type | Description |
---|---|---|
order_hash | String | Hash of the order |
market_id | String | ID of the spot market |
is_active | Boolean | Indicates if the order is active |
subaccount_id | String | ID of the subaccount that the order belongs to |
execution_type | String | The type of the order (Should be one of: ["limit", "market"]) |
order_type | String | Order type (Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell", "buy_po", "sell_po"]) |
price | String | Price of the order |
trigger_price | String | Trigger price used by stop/take orders |
quantity | String | Quantity of the order |
filled_quantity | String | The amount of the quantity filled |
state | String | Order state (Should be one of: ["booked", "partial_filled", "filled", "canceled"]) |
created_at | Integer | Order created timestamp in UNIX millis |
updated_at | Integer | Order updated timestamp in UNIX millis |
direction | String | The direction of the order (Should be one of: ["buy", "sell"]) |
tx_hash | String | Transaction hash in which the order was created (not all orders have this value) |
cid | String | Identifier for the order specified by the user (up to 36 characters, like a UUID) |
TradesV2
Get trade history for a spot market. The default request returns all spot trades from all markets.
IP rate limit group: indexer
*Trade execution types
"market"
for market orders"limitFill"
for a resting limit order getting filled by a market order"limitMatchRestingOrder"
for a resting limit order getting matched with another new limit order"limitMatchNewOrder"
for a new limit order getting matched immediately
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
market_ids = ["0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"]
execution_side = "taker"
direction = "buy"
subaccount_ids = ["0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001"]
execution_types = ["limitMatchNewOrder", "market"]
orders = await client.fetch_spot_trades(
market_ids=market_ids,
subaccount_ids=subaccount_ids,
execution_side=execution_side,
direction=direction,
execution_types=execution_types,
)
print(orders)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
spotExchangePB "github.com/InjectiveLabs/sdk-go/exchange/spot_exchange_rpc/pb"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"
subaccountId := "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
req := spotExchangePB.TradesV2Request{
MarketId: marketId,
SubaccountId: subaccountId,
}
res, err := exchangeClient.GetSpotTradesV2(ctx, &req)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_ids | String Array | Filter by multiple market IDs | No |
subaccount_ids | String Array | Filter by multiple subaccount IDs | No |
execution_side | String | Filter by the execution side of the trade (Should be one of: ["maker", "taker"]) | No |
direction | String | Filter by the direction of the trade (Should be one of: ["buy", "sell"]) | No |
execution_types | String Array | Filter by the *trade execution type (Should be one of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"]) | No |
trade_id | String | Filter by the trade id of the trade | No |
account_address | String | Filter by the account address | No |
cid | String | Filter by the custom client order id of the trade's order | No |
pagination | PaginationOption | Pagination configuration | No |
Response Parameters
Response Example:
{
"trades":[
{
"orderHash":"0x952bb14a7a377697d724c60d6077ef3dfe894c98f854970fab187247be832b6f",
"subaccountId":"0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
"marketId":"0x01edfab47f124748dc89998eb33144af734484ba07099014594321729a0ca16b",
"tradeExecutionType":"limitMatchRestingOrder",
"tradeDirection":"buy",
"price":{
"price":"0.00000000001",
"quantity":"1000000000000000000",
"timestamp":"1701961116630"
},
"fee":"-600",
"executedAt":"1701961116630",
"feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"tradeId":"1321_0",
"executionSide":"maker",
"cid":"96866b8b-02dd-4288-97d3-e5254e4888b3"
},
{
"orderHash":"0x85a824c31f59cf68235b48666c4821334813f2b80db937f02d192f1e3fc74368",
"subaccountId":"0x3db1f84431dfe4df617f9eb2d04edf432beb9826000000000000000000000000",
"marketId":"0x01edfab47f124748dc89998eb33144af734484ba07099014594321729a0ca16b",
"tradeExecutionType":"limitMatchNewOrder",
"tradeDirection":"sell",
"price":{
"price":"0.00000000001",
"quantity":"1000000000000000000",
"timestamp":"1701961116630"
},
"fee":"10000",
"executedAt":"1701961116630",
"feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"tradeId":"1321_1",
"executionSide":"taker",
"cid":"spot_AAVE/USDT"
},
{
"orderHash":"0xffabb2d12a745d79eb12c7ef0eb59c729aaa4387a141f858153c8b8f58168b2e",
"subaccountId":"0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
"marketId":"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
"tradeExecutionType":"limitMatchRestingOrder",
"tradeDirection":"buy",
"price":{
"price":"0.00000000001",
"quantity":"2000000000000000000",
"timestamp":"1701960607140"
},
"fee":"-2400",
"executedAt":"1701960607140",
"feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"tradeId":"646_0",
"executionSide":"maker",
"cid":"ec581735-f801-4bf3-9101-282b301bf5cd"
},
{
"orderHash":"0xa19e24eef9877ec4980b8d259c1d21fa1dafcd50691e6f853e84af74fb23c05c",
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"marketId":"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
"tradeExecutionType":"limitMatchNewOrder",
"tradeDirection":"sell",
"price":{
"price":"0.00000000001",
"quantity":"2000000000000000000",
"timestamp":"1701960607140"
},
"fee":"40000",
"executedAt":"1701960607140",
"feeRecipient":"inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8",
"tradeId":"646_1",
"executionSide":"taker",
"cid":""
},
{
"orderHash":"0xffabb2d12a745d79eb12c7ef0eb59c729aaa4387a141f858153c8b8f58168b2e",
"subaccountId":"0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
"marketId":"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
"tradeExecutionType":"limitMatchRestingOrder",
"tradeDirection":"buy",
"price":{
"price":"0.00000000001",
"quantity":"8000000000000000000",
"timestamp":"1701960594997"
},
"fee":"-9600",
"executedAt":"1701960594997",
"feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"tradeId":"630_0",
"executionSide":"maker",
"cid":"ec581735-f801-4bf3-9101-282b301bf5cd"
},
{
"orderHash":"0x87b786072190a2f38e9057987be7bdcb4e2274a6c16fdb9670e5c2ded765140f",
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"marketId":"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
"tradeExecutionType":"limitMatchNewOrder",
"tradeDirection":"sell",
"price":{
"price":"0.00000000001",
"quantity":"8000000000000000000",
"timestamp":"1701960594997"
},
"fee":"160000",
"executedAt":"1701960594997",
"feeRecipient":"inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8",
"tradeId":"630_1",
"executionSide":"taker",
"cid":""
}
],
"paging":{
"total":"6",
"from":1,
"to":6,
"countBySubaccount":"0",
"next":[
]
}
}
{
"trades": [
{
"order_hash": "0xffabb2d12a745d79eb12c7ef0eb59c729aaa4387a141f858153c8b8f58168b2e",
"subaccount_id": "0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
"market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
"trade_execution_type": "limitMatchRestingOrder",
"trade_direction": "buy",
"price": {
"price": "0.00000000001",
"quantity": "2000000000000000000",
"timestamp": 1701960607140
},
"fee": "-2400",
"executed_at": 1701960607140,
"fee_recipient": "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"trade_id": "646_0",
"execution_side": "maker",
"cid": "ec581735-f801-4bf3-9101-282b301bf5cd"
},
{
"order_hash": "0xa19e24eef9877ec4980b8d259c1d21fa1dafcd50691e6f853e84af74fb23c05c",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
"trade_execution_type": "limitMatchNewOrder",
"trade_direction": "sell",
"price": {
"price": "0.00000000001",
"quantity": "2000000000000000000",
"timestamp": 1701960607140
},
"fee": "40000",
"executed_at": 1701960607140,
"fee_recipient": "inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8",
"trade_id": "646_1",
"execution_side": "taker"
},
{
"order_hash": "0xffabb2d12a745d79eb12c7ef0eb59c729aaa4387a141f858153c8b8f58168b2e",
"subaccount_id": "0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
"market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
"trade_execution_type": "limitMatchRestingOrder",
"trade_direction": "buy",
"price": {
"price": "0.00000000001",
"quantity": "8000000000000000000",
"timestamp": 1701960594997
},
"fee": "-9600",
"executed_at": 1701960594997,
"fee_recipient": "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"trade_id": "630_0",
"execution_side": "maker",
"cid": "ec581735-f801-4bf3-9101-282b301bf5cd"
},
{
"order_hash": "0x87b786072190a2f38e9057987be7bdcb4e2274a6c16fdb9670e5c2ded765140f",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
"trade_execution_type": "limitMatchNewOrder",
"trade_direction": "sell",
"price": {
"price": "0.00000000001",
"quantity": "8000000000000000000",
"timestamp": 1701960594997
},
"fee": "160000",
"executed_at": 1701960594997,
"fee_recipient": "inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8",
"trade_id": "630_1",
"execution_side": "taker"
}
],
"paging": {
"total": 4,
"from": 1,
"to": 4
}
}
Parameter | Type | Description |
---|---|---|
trades | SpotTrade Array | Trades of a particular spot market |
paging | Paging | Pagination of results |
SpotTrade
Parameter | Type | Description |
---|---|---|
order_hash | String | The order hash |
subaccount_id | String | The subaccountId that executed the trade |
market_id | String | The ID of the market that this trade is in |
trade_execution_type | String | Execution type of the trade (Should be one of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"]) |
trade_direction | String | Direction of the trade(Should be one of: ["buy", "sell"]) |
price | PriceLevel | Price level at which trade has been executed |
fee | String | The fee associated with the trade (quote asset denom) |
executed_at | Integer | Timestamp of trade execution (on chain) in UNIX millis |
fee_recipient | String | The address that received 40% of the fees |
trade_id | String | Unique identifier to differentiate between trades |
execution_side | String | Execution side of trade (Should be one of: ["maker", "taker"]) |
cid | String | Identifier for the order specified by the user (up to 36 characters, like a UUID) |
PriceLevel
Parameter | Type | Description |
---|---|---|
price | String | Price number of the price level |
quantity | String | Quantity of the price level |
timestamp | Integer | Price level last updated timestamp in UNIX millis |
Paging
Parameter | Type | Description |
---|---|---|
total | Integer | Total number of records available |
StreamTradesV2
Stream newly executed trades of spot markets. The default request streams trades from all spot markets.
IP rate limit group: indexer
*Trade execution types
"market"
for market orders"limitFill"
for a resting limit order getting filled by a market order"limitMatchRestingOrder"
for a resting limit order getting matched with another new limit order"limitMatchNewOrder"
for a new limit order getting matched immediately
Request Parameters
Request Example:
import asyncio
from typing import Any, Dict
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def trade_event_processor(event: Dict[str, Any]):
print(event)
def stream_error_processor(exception: RpcError):
print(f"There was an error listening to spot trades updates ({exception})")
def stream_closed_processor():
print("The spot trades updates stream has been closed")
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
market_ids = [
"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0",
]
execution_side = "maker"
direction = "sell"
subaccount_id = "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001"
execution_types = ["limitMatchRestingOrder"]
task = asyncio.get_event_loop().create_task(
client.listen_spot_trades_updates(
callback=trade_event_processor,
on_end_callback=stream_closed_processor,
on_status_callback=stream_error_processor,
market_ids=market_ids,
subaccount_ids=[subaccount_id],
execution_side=execution_side,
direction=direction,
execution_types=execution_types,
)
)
await asyncio.sleep(delay=60)
task.cancel()
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
spotExchangePB "github.com/InjectiveLabs/sdk-go/exchange/spot_exchange_rpc/pb"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"
subaccountId := "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"
req := spotExchangePB.StreamTradesV2Request{
MarketId: marketId,
SubaccountId: subaccountId,
}
stream, err := exchangeClient.StreamSpotTradesV2(ctx, &req)
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
return
default:
res, err := stream.Recv()
if err != nil {
fmt.Println(err)
return
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
}
}
Parameter | Type | Description | Required |
---|---|---|---|
market_ids | String Array | Filter by multiple market IDs | No |
subaccount_ids | String Array | Filter by multiple subaccount IDs | No |
execution_side | String | Filter by the execution side of the trade (Should be one of: ["maker", "taker"]) | No |
direction | String | Filter by the direction of the trade (Should be one of: ["buy", "sell"]) | No |
execution_types | String Array | Filter by the *trade execution type (Should be one of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"]) | No |
trade_id | String | Filter by the trade's trade id | No |
account_address | String | Filter by the account address | No |
cid | String | Filter by the custom client order id of the trade's order | No |
pagination | PaginationOption | Pagination configuration | No |
callback | Function | Function receiving one parameter (a stream event JSON dictionary) to process each new event | Yes |
on_end_callback | Function | Function with the logic to execute when the stream connection is interrupted | No |
on_status_callback | Function | Function receiving one parameter (the exception) with the logic to execute when an exception happens | No |
Response Parameters
Streaming Response Example:
{
"trade":{
"orderHash":"0xa7f4a7d85136d97108d271caadd93bf697ff965790e0e1558617b953cced4adc",
"subaccountId":"0x3db1f84431dfe4df617f9eb2d04edf432beb9826000000000000000000000000",
"marketId":"0x01edfab47f124748dc89998eb33144af734484ba07099014594321729a0ca16b",
"tradeExecutionType":"limitMatchNewOrder",
"tradeDirection":"sell",
"price":{
"price":"0.00000000001",
"quantity":"1000000000000000000",
"timestamp":"1701978102242"
},
"fee":"10000",
"executedAt":"1701978102242",
"feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"tradeId":"22868_1",
"executionSide":"taker",
"cid":"96866b8b-02dd-4288-97d3-e5254e4999d4"
},
"operationType":"insert",
"timestamp":"1701978103000"
}
{
"trade":{
"orderHash":"0x952bb14a7a377697d724c60d6077ef3dfe894c98f854970fab187247be832b6f",
"subaccountId":"0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
"marketId":"0x01edfab47f124748dc89998eb33144af734484ba07099014594321729a0ca16b",
"tradeExecutionType":"limitMatchRestingOrder",
"tradeDirection":"buy",
"price":{
"price":"0.00000000001",
"quantity":"1000000000000000000",
"timestamp":"1701978102242"
},
"fee":"-600",
"executedAt":"1701978102242",
"feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"tradeId":"22868_0",
"executionSide":"maker",
"cid":"96866b8b-02dd-4288-97d3-e5254e4888b3"
},
"operationType":"insert",
"timestamp":"1701978103000"
}
{
"trade": {
"order_hash": "0x88e34872af0147f57c8c5a093c3a6a8a97358615bccf975b4a06dfb5162daeaf",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
"trade_execution_type": "market",
"trade_direction": "sell",
"price": {
"price": "0.000000000001654",
"quantity": "1000000000000000000",
"timestamp": 1653042087046
},
"fee": "3308",
"executed_at": 1653042087046,
"fee_recipient": "inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8"
},
"operation_type": "insert",
"timestamp": 1653042089000
}{
"trade": {
"order_hash": "0xb5d651a01faa90ec53b0fa34f00f3ecdfe169f9fc35be8114ee113eea9257c30",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
"trade_execution_type": "market",
"trade_direction": "sell",
"price": {
"price": "0.000000000001654",
"quantity": "2000000000000000000",
"timestamp": 1653042093023
},
"fee": "6616",
"executed_at": 1653042093023,
"fee_recipient": "inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8"
},
"operation_type": "insert",
"timestamp": 1653042098000
}
Parameter | Type | Description |
---|---|---|
trade | SpotTrade | New spot market trade |
operation_type | String | Trade operation type (Should be one of: ["insert", "invalidate"]) |
timestamp | Integer | Timestamp the new trade is written into the database in UNIX millis |
SpotTrade
Parameter | Type | Description |
---|---|---|
order_hash | String | The order hash |
subaccount_id | String | The subaccountId that executed the trade |
market_id | String | The ID of the market that this trade is in |
trade_execution_type | String | Execution type of the trade (Should be one of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"]) |
trade_direction | String | Direction of the trade(Should be one of: ["buy", "sell"]) |
price | PriceLevel | Price level at which trade has been executed |
fee | String | The fee associated with the trade (quote asset denom) |
executed_at | Integer | Timestamp of trade execution (on chain) in UNIX millis |
fee_recipient | String | The address that received 40% of the fees |
trade_id | String | Unique identifier to differentiate between trades |
execution_side | String | Execution side of trade (Should be one of: ["maker", "taker"]) |
cid | String | Identifier for the order specified by the user (up to 36 characters, like a UUID) |
PriceLevel
Parameter | Type | Description |
---|---|---|
price | String | Price number of the price level |
quantity | String | Quantity of the price level |
timestamp | Integer | Price level last updated timestamp in UNIX millis |
OrderbooksV2
Get an orderbook snapshot for one or more spot markets.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
market_ids = [
"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0",
]
orderbooks = await client.fetch_spot_orderbooks_v2(market_ids=market_ids)
print(orderbooks)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketIds := []string{"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"}
res, err := exchangeClient.GetSpotOrderbooksV2(ctx, marketIds)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_ids | String Array | List of IDs of markets to get orderbook snapshots from | Yes |
Response Parameters
Response Example:
{
"orderbooks":[
{
"marketId":"0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0",
"orderbook":{
"sells":[
{
"price":"0.000000000005",
"quantity":"27767884000000000000000",
"timestamp":"1694702425539"
},
{
"price":"0.0000000000045",
"quantity":"3519999000000000000000000",
"timestamp":"1694424758707"
}
],
"timestamp":"-62135596800000",
"buys":[
],
"sequence":"0"
}
},
{
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"orderbook":{
"buys":[
{
"price":"0.000000000073489",
"quantity":"129000000000000000",
"timestamp":"1702042963690"
},
{
"price":"0.000000000064261",
"quantity":"1292000000000000000",
"timestamp":"1702039612697"
}
],
"sells":[
{
"price":"0.000000000085",
"quantity":"6693248000000000000000",
"timestamp":"1702044317059"
},
{
"price":"0.000000000085768",
"quantity":"581000000000000000",
"timestamp":"1701944786578"
}
],
"sequence":"6916386",
"timestamp":"1702044336800"
}
}
]
}
Parameter | Type | Description |
---|---|---|
orderbooks | SingleSpotLimitOrderbookV2 Array | List of spot market orderbooks with market IDs |
SingleSpotLimitOrderbookV2
Parameter | Type | Description |
---|---|---|
market_id | String | ID of spot market |
orderbook | SpotLimitOrderBookV2 | Orderbook of the market |
SpotLimitOrderbookV2
Parameter | Type | Description |
---|---|---|
buys | PriceLevel Array | List of price levels for buys |
sells | PriceLevel Array | List of price levels for sells |
sequence | Integer | Sequence number of the orderbook; increments by 1 each update |
PriceLevel
Parameter | Type | Description |
---|---|---|
price | String | Price number of the price level |
quantity | String | Quantity of the price level |
timestamp | Integer | Price level last updated timestamp in UNIX millis |
StreamOrderbooksV2
Stream orderbook snapshot updates for one or more spot markets.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from typing import Any, Dict
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def orderbook_event_processor(event: Dict[str, Any]):
print(event)
def stream_error_processor(exception: RpcError):
print(f"There was an error listening to spot orderbook snapshots ({exception})")
def stream_closed_processor():
print("The spot orderbook snapshots stream has been closed")
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
market_ids = [
"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0",
]
task = asyncio.get_event_loop().create_task(
client.listen_spot_orderbook_snapshots(
market_ids=market_ids,
callback=orderbook_event_processor,
on_end_callback=stream_closed_processor,
on_status_callback=stream_error_processor,
)
)
await asyncio.sleep(delay=60)
task.cancel()
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
network := common.LoadNetwork("devnet-1", "")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketIds := []string{"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"}
stream, err := exchangeClient.StreamSpotOrderbookV2(ctx, marketIds)
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
return
default:
res, err := stream.Recv()
if err != nil {
fmt.Println(err)
return
}
fmt.Println(res.MarketId, res.Orderbook, len(res.Orderbook.Sells), len(res.Orderbook.Buys))
}
}
}
Parameter | Type | Description | Required |
---|---|---|---|
market_ids | String Array | List of market IDs for orderbook streaming; empty means all spot markets | Yes |
callback | Function | Function receiving one parameter (a stream event JSON dictionary) to process each new event | Yes |
on_end_callback | Function | Function with the logic to execute when the stream connection is interrupted | No |
on_status_callback | Function | Function receiving one parameter (the exception) with the logic to execute when an exception happens | No |
Response Parameters
Streaming Response Example:
{
"orderbook":{
"buys":[
{
"price":"0.000000000073489",
"quantity":"129000000000000000",
"timestamp":"1702042963690"
},
{
"price":"0.000000000064261",
"quantity":"1292000000000000000",
"timestamp":"1702039612697"
}
],
"sells":[
{
"price":"0.000000000085",
"quantity":"6681507000000000000000",
"timestamp":"1702044411262"
},
{
"price":"0.000000000085768",
"quantity":"581000000000000000",
"timestamp":"1701944786578"
}
],
"sequence":"6916434",
"timestamp":"1702044439698"
},
"operationType":"update",
"timestamp":"1702044441000",
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
}
Parameter | Type | Description |
---|---|---|
orderbook | SpotLimitOrderbookV2 | Orderbook of a Spot Market |
operation_type | String | Order update type (Should be one of: ["insert", "replace", "update", "invalidate"]) |
timestamp | Integer | Operation timestamp in UNIX millis |
market_id | String | ID of the market the orderbook belongs to |
SpotLimitOrderbookV2
Parameter | Type | Description |
---|---|---|
buys | PriceLevel Array | List of price levels for buys |
sells | PriceLevel Array | List of price levels for sells |
sequence | Integer | Sequence number of the orderbook; increments by 1 each update |
PriceLevel
Parameter | Type | Description |
---|---|---|
price | String | Price number of the price level |
quantity | String | Quantity of the price level |
timestamp | Integer | Price level last updated timestamp in UNIX millis |
StreamOrderbookUpdate
Stream incremental orderbook updates for one or more spot markets. This stream should be started prior to obtaining orderbook snapshots so that no incremental updates are omitted between obtaining a snapshot and starting the update stream.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from decimal import Decimal
from typing import Any, Dict
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
def stream_error_processor(exception: RpcError):
print(f"There was an error listening to spot orderbook updates ({exception})")
def stream_closed_processor():
print("The spot orderbook updates stream has been closed")
class PriceLevel:
def __init__(self, price: Decimal, quantity: Decimal, timestamp: int):
self.price = price
self.quantity = quantity
self.timestamp = timestamp
def __str__(self) -> str:
return "price: {} | quantity: {} | timestamp: {}".format(self.price, self.quantity, self.timestamp)
class Orderbook:
def __init__(self, market_id: str):
self.market_id = market_id
self.sequence = -1
self.levels = {"buys": {}, "sells": {}}
async def load_orderbook_snapshot(async_client: AsyncClient, orderbook: Orderbook):
# load the snapshot
res = await async_client.fetch_spot_orderbooks_v2(market_ids=[orderbook.market_id])
for snapshot in res["orderbooks"]:
if snapshot["marketId"] != orderbook.market_id:
raise Exception("unexpected snapshot")
orderbook.sequence = int(snapshot["orderbook"]["sequence"])
for buy in snapshot["orderbook"]["buys"]:
orderbook.levels["buys"][buy["price"]] = PriceLevel(
price=Decimal(buy["price"]),
quantity=Decimal(buy["quantity"]),
timestamp=int(buy["timestamp"]),
)
for sell in snapshot["orderbook"]["sells"]:
orderbook.levels["sells"][sell["price"]] = PriceLevel(
price=Decimal(sell["price"]),
quantity=Decimal(sell["quantity"]),
timestamp=int(sell["timestamp"]),
)
break
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
async_client = AsyncClient(network)
market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
orderbook = Orderbook(market_id=market_id)
updates_queue = asyncio.Queue()
tasks = []
async def queue_event(event: Dict[str, Any]):
await updates_queue.put(event)
# start getting price levels updates
task = asyncio.get_event_loop().create_task(
async_client.listen_spot_orderbook_updates(
market_ids=[market_id],
callback=queue_event,
on_end_callback=stream_closed_processor,
on_status_callback=stream_error_processor,
)
)
tasks.append(task)
# load the snapshot once we are already receiving updates, so we don't miss any
await load_orderbook_snapshot(async_client=async_client, orderbook=orderbook)
task = asyncio.get_event_loop().create_task(
apply_orderbook_update(orderbook=orderbook, updates_queue=updates_queue)
)
tasks.append(task)
await asyncio.sleep(delay=60)
for task in tasks:
task.cancel()
async def apply_orderbook_update(orderbook: Orderbook, updates_queue: asyncio.Queue):
while True:
updates = await updates_queue.get()
update = updates["orderbookLevelUpdates"]
# discard updates older than the snapshot
if int(update["sequence"]) <= orderbook.sequence:
return
print(" * * * * * * * * * * * * * * * * * * *")
# ensure we have not missed any update
if int(update["sequence"]) > (orderbook.sequence + 1):
raise Exception(
"missing orderbook update events from stream, must restart: {} vs {}".format(
update["sequence"], (orderbook.sequence + 1)
)
)
print("updating orderbook with updates at sequence {}".format(update["sequence"]))
# update orderbook
orderbook.sequence = int(update["sequence"])
for direction, levels in {"buys": update["buys"], "sells": update["sells"]}.items():
for level in levels:
if level["isActive"]:
# upsert level
orderbook.levels[direction][level["price"]] = PriceLevel(
price=Decimal(level["price"]), quantity=Decimal(level["quantity"]), timestamp=level["timestamp"]
)
else:
if level["price"] in orderbook.levels[direction]:
del orderbook.levels[direction][level["price"]]
# sort the level numerically
buys = sorted(orderbook.levels["buys"].values(), key=lambda x: x.price, reverse=True)
sells = sorted(orderbook.levels["sells"].values(), key=lambda x: x.price, reverse=True)
# lowest sell price should be higher than the highest buy price
if len(buys) > 0 and len(sells) > 0:
highest_buy = buys[0].price
lowest_sell = sells[-1].price
print("Max buy: {} - Min sell: {}".format(highest_buy, lowest_sell))
if highest_buy >= lowest_sell:
raise Exception("crossed orderbook, must restart")
# for the example, print the list of buys and sells orders.
print("sells")
for k in sells:
print(k)
print("=========")
print("buys")
for k in buys:
print(k)
print("====================================")
if __name__ == "__main__":
asyncio.run(main())
package main
import (
"context"
"fmt"
"io"
"os"
"sort"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
spotExchangePB "github.com/InjectiveLabs/sdk-go/exchange/spot_exchange_rpc/pb"
"github.com/shopspring/decimal"
)
type MapOrderbook struct {
Sequence uint64
Levels map[bool]map[string]*spotExchangePB.PriceLevel
}
func main() {
network := common.LoadNetwork("devnet-1", "")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
fmt.Println(err)
panic(err)
}
ctx := context.Background()
marketIds := []string{"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"}
stream, err := exchangeClient.StreamSpotOrderbookUpdate(ctx, marketIds)
if err != nil {
fmt.Println(err)
panic(err)
}
updatesCh := make(chan *spotExchangePB.OrderbookLevelUpdates, 100000)
receiving := make(chan struct{})
var receivingClosed bool
// stream orderbook price levels
go func() {
for {
select {
case <-ctx.Done():
return
default:
res, err := stream.Recv()
if err == io.EOF {
fmt.Println("change stream needs to be restarted")
os.Exit(0)
}
if err != nil {
panic(err) // rester on errors
}
u := res.OrderbookLevelUpdates
if !receivingClosed {
fmt.Println("receiving updates from stream")
close(receiving)
receivingClosed = true
}
updatesCh <- u
}
}
}()
// ensure we are receiving updates before getting the orderbook snapshot,
// we will skip past updates later.
fmt.Println("waiting for streaming updates")
<-receiving
// prepare orderbooks map
orderbooks := map[string]*MapOrderbook{}
res, err := exchangeClient.GetSpotOrderbooksV2(ctx, marketIds)
if err != nil {
panic(err)
}
for _, ob := range res.Orderbooks {
// init inner maps not ready
_, ok := orderbooks[ob.MarketId]
if !ok {
orderbook := &MapOrderbook{
Sequence: ob.Orderbook.Sequence,
Levels: map[bool]map[string]*spotExchangePB.PriceLevel{},
}
orderbook.Levels[true] = map[string]*spotExchangePB.PriceLevel{}
orderbook.Levels[false] = map[string]*spotExchangePB.PriceLevel{}
orderbooks[ob.MarketId] = orderbook
}
for _, level := range ob.Orderbook.Buys {
orderbooks[ob.MarketId].Levels[true][level.Price] = level
}
for _, level := range ob.Orderbook.Sells {
orderbooks[ob.MarketId].Levels[false][level.Price] = level
}
}
// continuously consume level updates and maintain orderbook
skippedPastEvents := false
for {
updates := <-updatesCh
// validate orderbook
orderbook, ok := orderbooks[updates.MarketId]
if !ok {
fmt.Println("updates channel closed, must restart")
return // closed
}
// skip if update sequence <= orderbook sequence until it's ready to consume
if !skippedPastEvents {
if orderbook.Sequence >= updates.Sequence {
continue
}
skippedPastEvents = true
}
// panic if update sequence > orderbook sequence + 1
if updates.Sequence > orderbook.Sequence+1 {
fmt.Printf("skipping levels: update sequence %d vs orderbook sequence %d\n", updates.Sequence, orderbook.Sequence)
panic("missing orderbook update events from stream, must restart")
}
// update orderbook map
orderbook.Sequence = updates.Sequence
for isBuy, update := range map[bool][]*spotExchangePB.PriceLevelUpdate{
true: updates.Buys,
false: updates.Sells,
} {
for _, level := range update {
if level.IsActive {
// upsert
orderbook.Levels[isBuy][level.Price] = &spotExchangePB.PriceLevel{
Price: level.Price,
Quantity: level.Quantity,
Timestamp: level.Timestamp,
}
} else {
// remove inactive level
delete(orderbook.Levels[isBuy], level.Price)
}
}
}
// construct orderbook arrays
sells, buys := maintainOrderbook(orderbook.Levels)
fmt.Println("after", orderbook.Sequence, len(sells), len(buys))
if len(sells) > 0 && len(buys) > 0 {
// assert orderbook
topBuyPrice := decimal.RequireFromString(buys[0].Price)
lowestSellPrice := decimal.RequireFromString(sells[0].Price)
if topBuyPrice.GreaterThanOrEqual(lowestSellPrice) {
panic(fmt.Errorf("crossed orderbook, must restart: buy %s >= %s sell", topBuyPrice, lowestSellPrice))
}
}
res, _ = exchangeClient.GetSpotOrderbooksV2(ctx, marketIds)
fmt.Println("query", res.Orderbooks[0].Orderbook.Sequence, len(res.Orderbooks[0].Orderbook.Sells), len(res.Orderbooks[0].Orderbook.Buys))
// print orderbook
fmt.Println(" [SELLS] ========")
for _, s := range sells {
fmt.Println(s)
}
fmt.Println(" [BUYS] ========")
for _, b := range buys {
fmt.Println(b)
}
fmt.Println("=======================================================")
}
}
func maintainOrderbook(orderbook map[bool]map[string]*spotExchangePB.PriceLevel) (buys, sells []*spotExchangePB.PriceLevel) {
for _, v := range orderbook[false] {
sells = append(sells, v)
}
for _, v := range orderbook[true] {
buys = append(buys, v)
}
sort.Slice(sells, func(i, j int) bool {
return decimal.RequireFromString(sells[i].Price).LessThan(decimal.RequireFromString(sells[j].Price))
})
sort.Slice(buys, func(i, j int) bool {
return decimal.RequireFromString(buys[i].Price).GreaterThan(decimal.RequireFromString(buys[j].Price))
})
return sells, buys
}
Parameter | Type | Description | Required |
---|---|---|---|
market_ids | String Array | List of market IDs for orderbook streaming; empty means all spot markets | Yes |
callback | Function | Function receiving one parameter (a stream event JSON dictionary) to process each new event | Yes |
on_end_callback | Function | Function with the logic to execute when the stream connection is interrupted | No |
on_status_callback | Function | Function receiving one parameter (the exception) with the logic to execute when an exception happens | No |
Response Parameters
Streaming Response Example:
* * * * * * * * * * * * * * * * * * *
updating orderbook with updates at sequence 724
Max buy: 7.523E-12 - Min sell: 7.525E-12
sells
price: 8E-12 | quantity: 10000000000000000 | timestamp: 1675904636889
price: 7.526E-12 | quantity: 50000000000000000 | timestamp: 1676089482358
price: 7.525E-12 | quantity: 10000000000000000 | timestamp: 1676015247335
=========
buys
price: 7.523E-12 | quantity: 30000000000000000 | timestamp: 1676616192052
price: 7E-12 | quantity: 1000000000000000000 | timestamp: 1675904400063
price: 1E-12 | quantity: 10000000000000000 | timestamp: 1675882430039
price: 1E-15 | quantity: 17983000000000000000 | timestamp: 1675880932648
====================================
* * * * * * * * * * * * * * * * * * *
updating orderbook with updates at sequence 725
Max buy: 7.523E-12 - Min sell: 7.525E-12
sells
price: 8E-12 | quantity: 10000000000000000 | timestamp: 1675904636889
price: 7.526E-12 | quantity: 50000000000000000 | timestamp: 1676089482358
price: 7.525E-12 | quantity: 10000000000000000 | timestamp: 1676015247335
=========
buys
price: 7.523E-12 | quantity: 40000000000000000 | timestamp: 1676616222476
price: 7E-12 | quantity: 1000000000000000000 | timestamp: 1675904400063
price: 1E-12 | quantity: 10000000000000000 | timestamp: 1675882430039
price: 1E-15 | quantity: 17983000000000000000 | timestamp: 1675880932648
====================================
Parameter | Type | Description |
---|---|---|
orderbook_level_updates | OrderbookLevelUpdates | Orderbook level updates of a spot market |
operation_type | String | Order update type (Should be one of: ["insert", "replace", "update", "invalidate"]) |
timestamp | Integer | Operation timestamp in UNIX millis |
market_id | String | ID of the market the orderbook belongs to |
OrderbookLevelUpdates
Parameter | Type | Description |
---|---|---|
market_id | String | ID of the market the orderbook belongs to |
sequence | Integer | Orderbook update sequence number; increments by 1 each update |
buys | PriceLevelUpdate Array | List of buy level updates |
sells | PriceLevelUpdate Array | List of sell level updates |
updated_at | Integer | Timestamp of the updates in UNIX millis |
PriceLevelUpdate
Parameter | Type | Description |
---|---|---|
price | String | Price number of the price level |
quantity | String | Quantity of the price level |
is_active | Boolean | Price level status |
timestamp | Integer | Price level last updated timestamp in UNIX millis |
SubaccountOrdersList
Get orders of a subaccount.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
subaccount_id = "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001"
market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
skip = 10
limit = 10
pagination = PaginationOption(skip=skip, limit=limit)
orders = await client.fetch_spot_subaccount_orders_list(
subaccount_id=subaccount_id, market_id=market_id, pagination=pagination
)
print(orders)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
spotExchangePB "github.com/InjectiveLabs/sdk-go/exchange/spot_exchange_rpc/pb"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"
subaccountId := "0x0b46e339708ea4d87bd2fcc61614e109ac374bbe000000000000000000000000"
skip := uint64(0)
limit := int32(10)
req := spotExchangePB.SubaccountOrdersListRequest{
MarketId: marketId,
SubaccountId: subaccountId,
Skip: skip,
Limit: limit,
}
res, err := exchangeClient.GetSubaccountSpotOrdersList(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | Filter by subaccount ID | Yes |
market_id | String | Filter by market ID | No |
pagination | PaginationOption | Pagination configuration | No |
Response Parameters
Response Example:
{
"orders":[
{
"orderHash":"0x3414f6f1a37a864166b19930680eb62a99798b5e406c2d14ed1ee66ab9958503",
"orderSide":"buy",
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"subaccountId":"0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000",
"price":"0.000000000003",
"quantity":"55000000000000000000",
"unfilledQuantity":"55000000000000000000",
"triggerPrice":"0",
"feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"state":"booked",
"createdAt":"1701808096494",
"updatedAt":"1701808096494",
"txHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"cid":"670c52ec-f68f-456c-8aeb-e271071a43ac"
},
{
"orderHash":"0xb7b6d54d1e01e1eb0005e34e08a96b715b557eeee7c5f3a439636f98ddd66b91",
"orderSide":"buy",
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"subaccountId":"0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000",
"price":"0.000000000003",
"quantity":"55000000000000000000",
"unfilledQuantity":"55000000000000000000",
"triggerPrice":"0",
"feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"state":"booked",
"createdAt":"1701808058512",
"updatedAt":"1701808058512",
"txHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"cid":"bba97476-e7f4-4313-874b-7ef115daccb4"
}
],
"paging":{
"total":"53",
"from":1,
"to":2,
"countBySubaccount":"0",
"next":[
]
}
}
{
"orders": [
{
"order_hash": "0x5e970df47eb5a65a5f907e3a2912067dde416eca8609c838e08c0dbebfbefaa5",
"order_side": "sell",
"market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"price": "0.000000000005",
"quantity": "1000000000000000000",
"unfilled_quantity": "1000000000000000000",
"trigger_price": "0",
"fee_recipient": "inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8",
"state": "booked",
"created_at": 1652809317404,
"updated_at": 1652809317404
},
{
"order_hash": "0x318418b546563a75c11dc656ee0fb41608e2893b0de859cf2b9e2d65996b6f9c",
"order_side": "buy",
"market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"price": "0.000000000001",
"quantity": "1000000000000000000",
"unfilled_quantity": "1000000000000000000",
"trigger_price": "0",
"fee_recipient": "inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8",
"state": "booked",
"created_at": 1652809253308,
"updated_at": 1652809253308
}
]
}
Parameter | Type | Description |
---|---|---|
orders | SpotLimitOrder Array | List of spot market orders |
paging | Paging | Pagination of results |
SpotLimitOrder
Parameter | Type | Description |
---|---|---|
order_hash | String | Hash of the order |
order_side | String | The side of the order (Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell"]) |
market_id | String | ID of the market the order belongs to |
subaccount_id | String | The subaccount ID the order belongs to |
price | String | The price of the order |
quantity | String | The quantity of the order |
unfilled_quantity | String | The amount of the quantity remaining unfilled |
trigger_price | String | The price that triggers stop and take orders. If no price is set, the default is 0 |
fee_recipient | String | The address that receives fees if the order is executed |
state | String | State of the order (Should be one of: ["booked", "partial_filled", "filled", "canceled"]) |
created_at | Integer | Order committed timestamp in UNIX millis |
updated_at | Integer | Order updated timestamp in UNIX millis |
tx_hash | String | Transaction hash in which the order was created (not all orders have this value) |
cid | String | Identifier for the order specified by the user (up to 36 characters, like a UUID) |
Paging
Parameter | Type | Description |
---|---|---|
total | Integer | Total number of available records |
from | Integer | Lower bound of indices of records returned |
to | integer | Upper bound of indices of records returned |
SubaccountTradesList
Get trades of a subaccount.
IP rate limit group: indexer
*Trade execution types
"market"
for market orders"limitFill"
for a resting limit order getting filled by a market order"limitMatchRestingOrder"
for a resting limit order getting matched with another new limit order"limitMatchNewOrder"
for a new limit order getting matched immediately
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
subaccount_id = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
execution_type = "market"
direction = "buy"
skip = 2
limit = 3
pagination = PaginationOption(skip=skip, limit=limit)
trades = await client.fetch_spot_subaccount_trades_list(
subaccount_id=subaccount_id,
market_id=market_id,
execution_type=execution_type,
direction=direction,
pagination=pagination,
)
print(trades)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
spotExchangePB "github.com/InjectiveLabs/sdk-go/exchange/spot_exchange_rpc/pb"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"
subaccountId := "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"
skip := uint64(0)
limit := int32(10)
req := spotExchangePB.SubaccountTradesListRequest{
MarketId: marketId,
SubaccountId: subaccountId,
Skip: skip,
Limit: limit,
}
res, err := exchangeClient.GetSubaccountSpotTradesList(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | Filter by subaccount ID | Yes |
market_id | String | Filter by market ID | No |
execution_type | String | Filter by the *execution type of the trades (Should be one of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"]) | No |
direction | String | Filter by the direction of the trades (Should be one of: ["buy", "sell"]) | No |
pagination | PaginationOption | Pagination configuration | No |
Response Parameters
Response Example:
{
"trades":[
{
"orderHash":"0x6dfd01151a5b3cfb3a61777335f0d8d324a479b9006fd9642f52b402aec53d4f",
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"tradeExecutionType":"market",
"tradeDirection":"buy",
"price":{
"price":"0.000000000015589",
"quantity":"1000000000000000",
"timestamp":"1700675201676"
},
"fee":"10.9123",
"executedAt":"1700675201676",
"feeRecipient":"inj1zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3t5qxqh",
"tradeId":"18740619_240_0",
"executionSide":"taker",
"cid":""
},
{
"orderHash":"0x6a6cd0afb038322b67a88cd827e2800483e3571c5e82663df37a33770fa0a8d1",
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"tradeExecutionType":"market",
"tradeDirection":"buy",
"price":{
"price":"0.000000000015742",
"quantity":"1000000000000000",
"timestamp":"1700232025894"
},
"fee":"11.0194",
"executedAt":"1700232025894",
"feeRecipient":"inj1zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3t5qxqh",
"tradeId":"18529043_240_0",
"executionSide":"taker",
"cid":""
},
{
"orderHash":"0xa3049ebaa97ac3755c09bd53ea30e86b98aef40bf037cb9d91dedfc1fd4b7735",
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"tradeExecutionType":"limitMatchNewOrder",
"tradeDirection":"buy",
"price":{
"price":"0.000000000015874",
"quantity":"21000000000000000000",
"timestamp":"1700221121919"
},
"fee":"233347.8",
"executedAt":"1700221121919",
"feeRecipient":"inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8",
"tradeId":"18523837_243_0",
"executionSide":"taker",
"cid":""
}
]
}
{
"trades": [
{
"order_hash": "0xbf5cf18a5e73c61d465a60ca550c5fbe0ed37b9ca0a49f7bd1de012e983fe55e",
"subaccount_id": "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000",
"market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
"trade_execution_type": "limitFill",
"trade_direction": "sell",
"price": {
"price": "0.000000000002305",
"quantity": "1000000000000000000",
"timestamp": 1652809734211
},
"fee": "2305",
"executed_at": 1652809734211,
"fee_recipient": "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r"
},
{
"order_hash": "0xfd474dc696dc291bca8ca1b371653994fd846a303c08d26ccc17a7b60939d256",
"subaccount_id": "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000",
"market_id": "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
"trade_execution_type": "limitFill",
"trade_direction": "sell",
"price": {
"price": "0.000000000002318",
"quantity": "4000000000000000000",
"timestamp": 1652773190338
},
"fee": "9272",
"executed_at": 1652773190338,
"fee_recipient": "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r"
}
]
}
Parameter | Type | Description |
---|---|---|
trades | SpotTrade Array | List of spot market trades |
SpotTrade
Parameter | Type | Description |
---|---|---|
order_hash | String | The order hash |
subaccount_id | String | The subaccountId that executed the trade |
market_id | String | The ID of the market that this trade is in |
trade_execution_type | String | Execution type of the trade (Should be one of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"]) |
trade_direction | String | Direction of the trade(Should be one of: ["buy", "sell"]) |
price | PriceLevel | Price level at which trade has been executed |
fee | String | The fee associated with the trade (quote asset denom) |
executed_at | Integer | Timestamp of trade execution (on chain) in UNIX millis |
fee_recipient | String | The address that received 40% of the fees |
trade_id | String | Unique identifier to differentiate between trades |
execution_side | String | Execution side of trade (Should be one of: ["maker", "taker"]) |
cid | String | Identifier for the order specified by the user (up to 36 characters, like a UUID) |
PriceLevel
Parameter | Type | Description |
---|---|---|
price | String | Price number of the price level |
quantity | String | Quantity of the price level |
timestamp | Integer | Price level last updated timestamp in UNIX millis |
- InjectiveDerivativeExchangeRPC
InjectiveDerivativeExchangeRPC defines the gRPC API of the Derivative Exchange provider.
Market
Get details of a single derivative market.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
market = await client.fetch_derivative_market(market_id=market_id)
print(market)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"
res, err := exchangeClient.GetDerivativeMarket(ctx, marketId)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | ID of the market to fetch | Yes |
Response Parameters
Response Example:
{
"market":{
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"marketStatus":"active",
"ticker":"INJ/USDT PERP",
"oracleBase":"0x2d9315a88f3019f8efa88dfe9c0f0843712da0bac814461e27733f6b83eb51b3",
"oracleQuote":"0x1fc18861232290221461220bd4e2acd1dcdfbc89c84092c93c18bdc7756c1588",
"oracleType":"pyth",
"oracleScaleFactor":6,
"initialMarginRatio":"0.05",
"maintenanceMarginRatio":"0.02",
"quoteDenom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"quoteTokenMeta":{
"name":"Testnet Tether USDT",
"address":"0x0000000000000000000000000000000000000000",
"symbol":"USDT",
"logo":"https://static.alchemyapi.io/images/assets/825.png",
"decimals":6,
"updatedAt":"1698247516758"
},
"makerFeeRate":"-0.0001",
"takerFeeRate":"0.001",
"serviceProviderFee":"0.4",
"isPerpetual":true,
"minPriceTickSize":"100",
"minQuantityTickSize":"0.0001",
"perpetualMarketInfo":{
"hourlyFundingRateCap":"0.000625",
"hourlyInterestRate":"0.00000416666",
"nextFundingTimestamp":"1701990000",
"fundingInterval":"3600"
},
"perpetualMarketFunding":{
"cumulativeFunding":"-156010.283874921534910863",
"cumulativePrice":"566.477789213654772072",
"lastTimestamp":"1701906508"
},
"min_notional":"1000000"
}
}
{
"market": {
"market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
"market_status": "active",
"ticker": "BTC/USDT PERP",
"oracle_base": "BTC",
"oracle_quote": "USDT",
"oracle_type": "bandibc",
"oracle_scale_factor": 6,
"initial_margin_ratio": "0.095",
"maintenance_margin_ratio": "0.05",
"quote_denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
"quote_token_meta": {
"name": "Tether",
"address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"symbol": "USDT",
"logo": "https://static.alchemyapi.io/images/assets/825.png",
"decimals": 6,
"updated_at": 1650978923435
},
"maker_fee_rate": "0.0005",
"taker_fee_rate": "0.0012",
"service_provider_fee": "0.4",
"is_perpetual": true,
"min_price_tick_size": "100000",
"min_quantity_tick_size": "0.0001",
"perpetual_market_info": {
"hourly_funding_rate_cap": "0.000625",
"hourly_interest_rate": "0.00000416666",
"next_funding_timestamp": 1652864400,
"funding_interval": 3600
},
"perpetual_market_funding": {
"cumulative_funding": "7246105747.050586213851272386",
"cumulative_price": "31.114148427047982579",
"last_timestamp": 1652793510
},
"min_notional": "1000000"
}
}
Parameter | Type | Description |
---|---|---|
market | DerivativeMarketInfo | Info about a particular derivative market |
DerivativeMarketInfo
Parameter | Type | Description |
---|---|---|
oracle_quote | String | Oracle quote currency |
oracle_type | String | Oracle Type |
quote_denom | String | Coin denom used for the quote asset |
is_perpetual | Boolean | True if the market is a perpetual swap market |
maker_fee_rate | String | Defines the fee percentage makers pay (or receive, if negative) in quote asset when trading |
min_price_tick_size | String | Defines the minimum required tick size for the order's price |
min_quantity_tick_size | String | Defines the minimum required tick size for the order's quantity |
oracle_scale_factor | Integer | Scaling multiple to scale oracle prices to the correct number of decimals |
taker_fee_rate | String | Defines the fee percentage takers pay (in quote asset) when trading |
expiry_futures_market_info | ExpiryFuturesMarketInfo | Info about expiry futures market |
initial_margin_ratio | String | The initial margin ratio of the derivative market |
market_status | String | The status of the market (Should be one of: ["active", "paused", "suspended", "demolished", "expired"]) |
service_provider_fee | String | Percentage of the transaction fee shared with the service provider |
oracle_base | String | Oracle base currency |
perpetual_market_funding | PerpetualMarketFunding | PerpetualMarketFunding object |
perpetual_market_info | PerpetualMarketInfo | Information about the perpetual market |
ticker | String | The name of the pair in format AAA/BBB, where AAA is the base asset and BBB is the quote asset |
maintenance_margin_ratio | String | The maintenance margin ratio of the derivative market |
market_id | String | The market ID |
quoteTokenMeta | TokenMeta | Token metadata for quote asset, only for Ethereum-based assets |
min_notional | String | Defines the minimum required notional for an order to be accepted |
ExpiryFuturesMarketInfo
Parameter | Type | Description |
---|---|---|
expiration_timestamp | Integer | Defines the expiration time for a time expiry futures market in UNIX seconds |
settlement_price | String | Defines the settlement price for a time expiry futures market |
PerpetualMarketFunding
Parameter | Type | Description |
---|---|---|
cumulative_funding | String | Defines the cumulative funding of a perpetual market |
cumulative_price | String | Defines the cumulative price for the current hour up to the last timestamp |
last_timestamp | Integer | Defines the last funding timestamp in UNIX seconds |
PerpetualMarketInfo
Parameter | Type | Description |
---|---|---|
hourly_funding_rate_cap | String | Defines the default maximum absolute value of the hourly funding rate |
hourly_interest_rate | String | Defines the hourly interest rate of the perpetual market |
next_funding_timestamp | Integer | Defines the next funding timestamp in UNIX seconds |
funding_interval | Integer | Defines the funding interval in seconds |
TokenMeta
Parameter | Type | Description |
---|---|---|
address | String | Token's Ethereum contract address |
decimals | Integer | Token decimals |
logo | String | URL to the logo image |
name | String | Token full name |
symbol | String | Token symbol short name |
updatedAt | Integer | Token metadata fetched timestamp in UNIX millis |
Markets
Get a list of one or more derivative markets.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
market_statuses = ["active"]
quote_denom = "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"
market = await client.fetch_derivative_markets(market_statuses=market_statuses, quote_denom=quote_denom)
print(market)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("mainnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketStatus := "active"
quoteDenom := "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7"
req := derivativeExchangePB.MarketsRequest{
MarketStatus: marketStatus,
QuoteDenom: quoteDenom,
}
res, err := exchangeClient.GetDerivativeMarkets(ctx, &req)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_statuses | String Array | Filter by market status (Should be any of: ["active", "paused", "suspended", "demolished", "expired"]) | No |
quote_denom | String | Filter by the Coin denomination of the quote currency | No |
Response Parameters
Response Example:
[
{
"marketId": "0x1c79dac019f73e4060494ab1b4fcba734350656d6fc4d474f6a238c13c6f9ced",
"marketStatus": "active",
"ticker": "BNB/USDT PERP",
"oracleBase": "BNB",
"oracleQuote": "USDT",
"oracleType": "bandibc",
"oracleScaleFactor": 6,
"initialMarginRatio": "0.095",
"maintenanceMarginRatio": "0.05",
"quoteDenom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
"quoteTokenMeta": {
"name": "Tether",
"address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"symbol": "USDT",
"logo": "https://static.alchemyapi.io/images/assets/825.png",
"decimals": 6,
"updatedAt": 1650978923353
},
"makerFeeRate": "0.0005",
"takerFeeRate": "0.0012",
"serviceProviderFee": "0.4",
"isPerpetual": true,
"minPriceTickSize": "10000",
"minQuantityTickSize": "0.01",
"perpetualMarketInfo": {
"hourlyFundingRateCap": "0.000625",
"hourlyInterestRate": "0.00000416666",
"nextFundingTimestamp": 1654246800,
"fundingInterval": 3600
},
"perpetualMarketFunding": {
"cumulativeFunding": "56890491.178246679699729639",
"cumulativePrice": "7.082760891515203314",
"lastTimestamp": 1654245985
},
"min_notional": "1000000",
},
{
"marketId": "0x00030df39180df04a873cb4aadc50d4135640af5c858ab637dbd4d31b147478c",
"marketStatus": "active",
"ticker": "Frontrunner Futures: Expires 5.21.2023",
"oracleBase": "FRNT",
"oracleQuote": "USDT",
"oracleType": "pricefeed",
"oracleScaleFactor": 6,
"initialMarginRatio": "0.999999999999999999",
"maintenanceMarginRatio": "0.1",
"quoteDenom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
"quoteTokenMeta": {
"name": "Tether",
"address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"symbol": "USDT",
"logo": "https://static.alchemyapi.io/images/assets/825.png",
"decimals": 6,
"updatedAt": 1653064108501
},
"makerFeeRate": "0.005",
"takerFeeRate": "0.012",
"serviceProviderFee": "0.4",
"isPerpetual": false,
"minPriceTickSize": "0.000000000000001",
"minQuantityTickSize": "0.0001",
"expiryFuturesMarketInfo": {
"expirationTimestamp": 1684600043,
"settlementPrice": "0"
},
"min_notional": "0"
}
]
{
"markets": [
{
"market_id": "0x1c79dac019f73e4060494ab1b4fcba734350656d6fc4d474f6a238c13c6f9ced",
"market_status": "active",
"ticker": "BNB/USDT PERP",
"oracle_base": "BNB",
"oracle_quote": "USDT",
"oracle_type": "bandibc",
"oracle_scale_factor": 6,
"initial_margin_ratio": "0.095",
"maintenance_margin_ratio": "0.05",
"quote_denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
"quote_token_meta": {
"name": "Tether",
"address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"symbol": "USDT",
"logo": "https://static.alchemyapi.io/images/assets/825.png",
"decimals": 6,
"updated_at": 1650978923353
},
"maker_fee_rate": "0.0005",
"taker_fee_rate": "0.0012",
"service_provider_fee": "0.4",
"is_perpetual": true,
"min_price_tick_size": "10000",
"min_quantity_tick_size": "0.01",
"perpetual_market_info": {
"hourly_funding_rate_cap": "0.000625",
"hourly_interest_rate": "0.00000416666",
"next_funding_timestamp": 1652864400,
"funding_interval": 3600
},
"perpetual_market_funding": {
"cumulative_funding": "48248742.484852568471323698",
"cumulative_price": "5.691379282523162906",
"last_timestamp": 1652775374
},
"min_notional": "1000000"
},
{
"market_id": "0xfb5f14852bd01af901291dd2aa65e997b3a831f957124a7fe7aa40d218ff71ae",
"market_status": "active",
"ticker": "XAG/USDT PERP",
"oracle_base": "XAG",
"oracle_quote": "USDT",
"oracle_type": "bandibc",
"oracle_scale_factor": 6,
"initial_margin_ratio": "0.8",
"maintenance_margin_ratio": "0.4",
"quote_denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
"quote_token_meta": {
"name": "Tether",
"address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"symbol": "USDT",
"logo": "https://static.alchemyapi.io/images/assets/825.png",
"decimals": 6,
"updated_at": 1650978923534
},
"maker_fee_rate": "0.003",
"taker_fee_rate": "0.005",
"service_provider_fee": "0.4",
"is_perpetual": true,
"min_price_tick_size": "10000",
"min_quantity_tick_size": "0.01",
"perpetual_market_info": {
"hourly_funding_rate_cap": "0.000625",
"hourly_interest_rate": "0.00000416666",
"next_funding_timestamp": 1652864400,
"funding_interval": 3600
},
"perpetual_market_funding": {
"cumulative_funding": "1099659.417190990913058692",
"cumulative_price": "-4.427475055338306767",
"last_timestamp": 1652775322
},
"min_notional": "0",
}
]
}
Parameter | Type | Description |
---|---|---|
markets | DerivativeMarketInfo Array | List of derivative markets and associated info |
DerivativeMarketInfo
Parameter | Type | Description |
---|---|---|
oracle_quote | String | Oracle quote currency |
oracle_type | String | Oracle Type |
quote_denom | String | Coin denom used for the quote asset |
is_perpetual | Boolean | True if the market is a perpetual swap market |
maker_fee_rate | String | Defines the fee percentage makers pay (or receive, if negative) in quote asset when trading |
min_price_tick_size | String | Defines the minimum required tick size for the order's price |
min_quantity_tick_size | String | Defines the minimum required tick size for the order's quantity |
oracle_scale_factor | Integer | Scaling multiple to scale oracle prices to the correct number of decimals |
taker_fee_rate | String | Defines the fee percentage takers pay (in quote asset) when trading |
expiry_futures_market_info | ExpiryFuturesMarketInfo | Info about expiry futures market |
initial_margin_ratio | String | The initial margin ratio of the derivative market |
market_status | String | The status of the market (Should be one of: ["active", "paused", "suspended", "demolished", "expired"]) |
service_provider_fee | String | Percentage of the transaction fee shared with the service provider |
oracle_base | String | Oracle base currency |
perpetual_market_funding | PerpetualMarketFunding | PerpetualMarketFunding object |
perpetual_market_info | PerpetualMarketInfo | Information about the perpetual market |
ticker | String | The name of the pair in format AAA/BBB, where AAA is the base asset and BBB is the quote asset |
maintenance_margin_ratio | String | The maintenance margin ratio of the derivative market |
market_id | String | The market ID |
quoteTokenMeta | TokenMeta | Token metadata for quote asset, only for Ethereum-based assets |
min_notional | String | Defines the minimum required notional for an order to be accepted |
ExpiryFuturesMarketInfo
Parameter | Type | Description |
---|---|---|
expiration_timestamp | Integer | Defines the expiration time for a time expiry futures market in UNIX seconds |
settlement_price | String | Defines the settlement price for a time expiry futures market |
PerpetualMarketFunding
Parameter | Type | Description |
---|---|---|
cumulative_funding | String | Defines the cumulative funding of a perpetual market |
cumulative_price | String | Defines the cumulative price for the current hour up to the last timestamp |
last_timestamp | Integer | Defines the last funding timestamp in UNIX seconds |
PerpetualMarketInfo
Parameter | Type | Description |
---|---|---|
hourly_funding_rate_cap | String | Defines the default maximum absolute value of the hourly funding rate |
hourly_interest_rate | String | Defines the hourly interest rate of the perpetual market |
next_funding_timestamp | Integer | Defines the next funding timestamp in UNIX seconds |
funding_interval | Integer | Defines the funding interval in seconds |
TokenMeta
Parameter | Type | Description |
---|---|---|
address | String | Token's Ethereum contract address |
decimals | Integer | Token decimals |
logo | String | URL to the logo image |
name | String | Token full name |
symbol | String | Token symbol short name |
updatedAt | Integer | Token metadata fetched timestamp in UNIX millis |
StreamMarkets
Stream live updates of derivative markets.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from typing import Any, Dict
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def market_event_processor(event: Dict[str, Any]):
print(event)
def stream_error_processor(exception: RpcError):
print(f"There was an error listening to derivative markets updates ({exception})")
def stream_closed_processor():
print("The derivative markets updates stream has been closed")
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
task = asyncio.get_event_loop().create_task(
client.listen_derivative_market_updates(
callback=market_event_processor,
on_end_callback=stream_closed_processor,
on_status_callback=stream_error_processor,
)
)
await asyncio.sleep(delay=60)
task.cancel()
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketIds := []string{"0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"}
stream, err := exchangeClient.StreamDerivativeMarket(ctx, marketIds)
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
return
default:
res, err := stream.Recv()
if err != nil {
panic(err)
return
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
}
}
Parameter | Type | Description | Required |
---|---|---|---|
market_ids | String Array | List of market IDs for updates streaming, empty means 'ALL' derivative markets | No |
callback | Function | Function receiving one parameter (a stream event JSON dictionary) to process each new event | Yes |
on_end_callback | Function | Function with the logic to execute when the stream connection is interrupted | No |
on_status_callback | Function | Function receiving one parameter (the exception) with the logic to execute when an exception happens | No |
Response Parameters
Streaming Response Example:
{
"market": {
"marketId": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
"marketStatus": "active",
"ticker": "BTC/USDT PERP",
"oracleBase": "BTC",
"oracleQuote": "USDT",
"oracleType": "bandibc",
"oracleScaleFactor": 6,
"initialMarginRatio": "0.095",
"maintenanceMarginRatio": "0.05",
"quoteDenom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
"quoteTokenMeta": {
"name": "Tether",
"address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"symbol": "USDT",
"logo": "https://static.alchemyapi.io/images/assets/825.png",
"decimals": 6,
"updatedAt": 1650978923435
},
"makerFeeRate": "0.0005",
"takerFeeRate": "0.0012",
"serviceProviderFee": "0.4",
"isPerpetual": true,
"minPriceTickSize": "100000",
"minQuantityTickSize": "0.0001",
"perpetualMarketInfo": {
"hourlyFundingRateCap": "0.000625",
"hourlyInterestRate": "0.00000416666",
"nextFundingTimestamp": 1654246800,
"fundingInterval": 3600
},
"perpetualMarketFunding": {
"cumulativeFunding": "8239865636.851083559033030036",
"cumulativePrice": "7.15770685160786651",
"lastTimestamp": 1654246073
},
"min_notional": "1000000"
},
"operationType": "update",
"timestamp": 1654246076000
}
{
"market": {
"market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
"market_status": "active",
"ticker": "BTC/USDT PERP",
"oracle_base": "BTC",
"oracle_quote": "USDT",
"oracle_type": "bandibc",
"oracle_scale_factor": 6,
"initial_margin_ratio": "0.095",
"maintenance_margin_ratio": "0.05",
"quote_denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
"quote_token_meta": {
"name": "Tether",
"address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"symbol": "USDT",
"logo": "https://static.alchemyapi.io/images/assets/825.png",
"decimals": 6,
"updated_at": 1650978923435
},
"maker_fee_rate": "0.0005",
"taker_fee_rate": "0.0012",
"service_provider_fee": "0.4",
"is_perpetual": true,
"min_price_tick_size": "100000",
"min_quantity_tick_size": "0.0001",
"perpetual_market_info": {
"hourly_funding_rate_cap": "0.000625",
"hourly_interest_rate": "0.00000416666",
"next_funding_timestamp": 1653040800,
"funding_interval": 3600
},
"perpetual_market_funding": {
"cumulative_funding": "7356035675.459202347630388315",
"cumulative_price": "3.723976370878870887",
"last_timestamp": 1653038971
},
"min_notional": "0"
},
"operation_type": "update",
"timestamp": 1653038974000
}
Parameter | Type | Description |
---|---|---|
market | DerivativeMarketInfo | Info about a particular derivative market |
operation_type | String | Update type (Should be one of: ["insert", "delete", "replace", "update", "invalidate"]) |
timestamp | Integer | Operation timestamp in UNIX millis |
DerivativeMarketInfo
Parameter | Type | Description |
---|---|---|
oracle_quote | String | Oracle quote currency |
oracle_type | String | Oracle Type |
quote_denom | String | Coin denom used for the quote asset |
is_perpetual | Boolean | True if the market is a perpetual swap market |
maker_fee_rate | String | Defines the fee percentage makers pay (or receive, if negative) in quote asset when trading |
min_price_tick_size | String | Defines the minimum required tick size for the order's price |
min_quantity_tick_size | String | Defines the minimum required tick size for the order's quantity |
oracle_scale_factor | Integer | Scaling multiple to scale oracle prices to the correct number of decimals |
taker_fee_rate | String | Defines the fee percentage takers pay (in quote asset) when trading |
expiry_futures_market_info | ExpiryFuturesMarketInfo | Info about expiry futures market |
initial_margin_ratio | String | The initial margin ratio of the derivative market |
market_status | String | The status of the market (Should be one of: ["active", "paused", "suspended", "demolished", "expired"]) |
service_provider_fee | String | Percentage of the transaction fee shared with the service provider |
oracle_base | String | Oracle base currency |
perpetual_market_funding | PerpetualMarketFunding | PerpetualMarketFunding object |
perpetual_market_info | PerpetualMarketInfo | Information about the perpetual market |
ticker | String | The name of the pair in format AAA/BBB, where AAA is the base asset and BBB is the quote asset |
maintenance_margin_ratio | String | The maintenance margin ratio of the derivative market |
market_id | String | The market ID |
quoteTokenMeta | TokenMeta | Token metadata for quote asset, only for Ethereum-based assets |
min_notional | String | Defines the minimum required notional for an order to be accepted |
ExpiryFuturesMarketInfo
Parameter | Type | Description |
---|---|---|
expiration_timestamp | Integer | Defines the expiration time for a time expiry futures market in UNIX seconds |
settlement_price | String | Defines the settlement price for a time expiry futures market |
PerpetualMarketFunding
Parameter | Type | Description |
---|---|---|
cumulative_funding | String | Defines the cumulative funding of a perpetual market |
cumulative_price | String | Defines the cumulative price for the current hour up to the last timestamp |
last_timestamp | Integer | Defines the last funding timestamp in UNIX seconds |
PerpetualMarketInfo
Parameter | Type | Description |
---|---|---|
hourly_funding_rate_cap | String | Defines the default maximum absolute value of the hourly funding rate |
hourly_interest_rate | String | Defines the hourly interest rate of the perpetual market |
next_funding_timestamp | Integer | Defines the next funding timestamp in UNIX seconds |
funding_interval | Integer | Defines the funding interval in seconds |
TokenMeta
Parameter | Type | Description |
---|---|---|
address | String | Token's Ethereum contract address |
decimals | Integer | Token decimals |
logo | String | URL to the logo image |
name | String | Token full name |
symbol | String | Token symbol short name |
updatedAt | Integer | Token metadata fetched timestamp in UNIX millis |
OrdersHistory
Lists historical orders posted from a subaccount
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
market_ids = ["0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"]
subaccount_id = "0x295639d56c987f0e24d21bb167872b3542a6e05a000000000000000000000000"
is_conditional = "false"
skip = 10
limit = 3
pagination = PaginationOption(skip=skip, limit=limit)
orders = await client.fetch_derivative_orders_history(
subaccount_id=subaccount_id,
market_ids=market_ids,
is_conditional=is_conditional,
pagination=pagination,
)
print(orders)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
subaccountId := "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
skip := uint64(0)
limit := int32(10)
isConditional := "false"
req := derivativeExchangePB.OrdersHistoryRequest{
SubaccountId: subaccountId,
MarketId: marketId,
Skip: skip,
Limit: limit,
IsConditional: isConditional,
}
res, err := exchangeClient.GetHistoricalDerivativeOrders(ctx, &req)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | Filter by subaccount ID | No |
market_ids | String Array | Filter by multiple market IDs | No |
order_types | String Array | The order types to be included (Should be any of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell", "buy_po", "sell_po"]) | No |
direction | String | Filter by order direction (Should be one of: ["buy", "sell"]) | No |
is_conditional | String | Search for conditional/non-conditional orders(Should be one of: ["true", "false"]) | No |
state | String | The order state (Should be one of: ["booked", "partial_filled", "filled", "canceled"]) | No |
execution_types | String Array | The execution of the order (Should be one of: ["limit", "market"]) | No |
trade_id | String | Filter by the trade's trade id | No |
active_markets_only | Bool | Return only orders for active markets | No |
cid | String | Filter by the custom client order id of the trade's order | No |
pagination | PaginationOption | Pagination configuration | No |
Response Parameters
Response Example:
{
"orders":[
{
"orderHash":"0x3c98f1e38781ce8780f8f5ffe3a78cf3dbfa4d96f54d774a4847f46e9e89d6dc",
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccountId":"0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000005",
"executionType":"limit",
"orderType":"buy_po",
"price":"13097700",
"triggerPrice":"0",
"quantity":"110660.5284",
"filledQuantity":"0",
"state":"canceled",
"createdAt":"1701995288222",
"updatedAt":"1702002966962",
"direction":"buy",
"margin":"724699201412.34",
"txHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"isActive":false,
"isReduceOnly":false,
"isConditional":false,
"triggerAt":"0",
"placedOrderHash":"",
"cid":""
},
{
"orderHash":"0xc7c34746158b1e21bbdfa8edce0876fa00810f7b6f2236c302945c8e6b9eeb38",
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccountId":"0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000005",
"executionType":"limit",
"orderType":"buy_po",
"price":"13064100",
"triggerPrice":"0",
"quantity":"110945.1399",
"filledQuantity":"0",
"state":"canceled",
"createdAt":"1701995288222",
"updatedAt":"1702002966962",
"direction":"buy",
"margin":"724699201083.795",
"txHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"isActive":false,
"isReduceOnly":false,
"isConditional":false,
"triggerAt":"0",
"placedOrderHash":"",
"cid":""
},
{
"orderHash":"0x4478897d21c94df929c7d12c33d71973027ced1899ff253199b6e46124e680c1",
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccountId":"0x5e249f0e8cb406f41de16e1bd6f6b55e7bc75add000000000000000000000005",
"executionType":"limit",
"orderType":"buy_po",
"price":"13030500",
"triggerPrice":"0",
"quantity":"111231.2193",
"filledQuantity":"0",
"state":"canceled",
"createdAt":"1701995288222",
"updatedAt":"1702002966962",
"direction":"buy",
"margin":"724699201544.325",
"txHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"isActive":false,
"isReduceOnly":false,
"isConditional":false,
"triggerAt":"0",
"placedOrderHash":"",
"cid":""
}
],
"paging":{
"total":"1000",
"from":0,
"to":0,
"countBySubaccount":"0",
"next":[
]
}
}
{
"orders": [
{
"order_hash": "0x17da6aa0ba9c192da6c9d5a043b4c36a91af5117636cb1f6e69654fc6cfc1bee",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"execution_type": "market",
"order_type": "sell",
"price": "6494113.703056872037914692",
"trigger_price": "0",
"quantity": "2110",
"filled_quantity": "2110",
"state": "filled",
"created_at": 1692857306725,
"updated_at": 1692857306725,
"direction": "sell",
"margin": "0"
},
{
"order_hash": "0xeac94983c5e1a47885e5959af073c475e4ec6ec343c1e1d441af1ba65f8aa5ee",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"execution_type": "limit",
"order_type": "buy",
"price": "8111100",
"trigger_price": "0",
"quantity": "10",
"filled_quantity": "10",
"state": "filled",
"created_at": 1688738648747,
"updated_at": 1688738648747,
"direction": "buy",
"margin": "82614000"
},
{
"order_hash": "0x41a5c6f8c8c8ff3f37e443617dda589f46f1678ef1a22e2ab2b6ca54e0788210",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"execution_type": "market",
"order_type": "buy",
"price": "8261400",
"trigger_price": "0",
"quantity": "100",
"filled_quantity": "100",
"state": "filled",
"created_at": 1688591280030,
"updated_at": 1688591280030,
"direction": "buy",
"margin": "274917218.543"
},
{
"order_hash": "0x2f667629cd06ac9fd6e54aa2544ad63cd43efc29418d0e1e12df9ba783c9a7ab",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"execution_type": "market",
"order_type": "buy",
"price": "7166668.98546",
"trigger_price": "0",
"quantity": "2000",
"filled_quantity": "2000",
"state": "filled",
"created_at": 1687507605674,
"updated_at": 1687507605674,
"direction": "buy",
"margin": "4814400000"
},
{
"order_hash": "0x4c42bca7b65f18bf96e75be03a53f73854da15e8030c38e63d1531307f8cd40c",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"execution_type": "market",
"order_type": "sell",
"price": "7123287.02926",
"trigger_price": "0",
"quantity": "1000",
"filled_quantity": "1000",
"state": "filled",
"created_at": 1687507547684,
"updated_at": 1687507547684,
"direction": "sell",
"margin": "0"
},
{
"order_hash": "0x70c66ce3e92aa616d3dbdbcd565c37a3d42b2b5a0951a8bebe9ddaca9852d547",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"execution_type": "market",
"order_type": "buy",
"price": "7162504.91532",
"trigger_price": "0",
"quantity": "1000",
"filled_quantity": "1000",
"state": "filled",
"created_at": 1687507348068,
"updated_at": 1687507348068,
"direction": "buy",
"margin": "7212200000"
}
],
"paging": {
"total": 6
}
}
Parameter | Type | Description |
---|---|---|
orders | DerivativeOrderHistory Array | list of historical derivative orders |
paging | Paging | Pagination of results |
DerivativeOrderHistory
Parameter | Type | Description |
---|---|---|
order_hash | String | Hash of the order |
market_id | String | Derivative market ID |
is_active | Boolean | Indicates if the order is active |
subaccount_id | String | The subaccountId that this order belongs to |
execution_type | String | The type of the order (Should be one of: ["limit", "market"]) |
order_type | String | Order type (Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell", "buy_po", "sell_po"]) |
price | String | Price of the order |
trigger_price | String | The price that triggers stop/take orders |
quantity | String | Quantity of the order |
filled_quantity | String | The amount of the quantity filled |
state | String | Order state (Should be one of: ["booked", "partial_filled", "filled", "canceled"]) |
created_at | Integer | Order created timestamp in UNIX millis |
updated_at | Integer | Order updated timestamp in UNIX millis |
is_reduce_only | Boolean | Indicates if the order is reduce-only |
direction | String | The direction of the order (Should be one of: ["buy", "sell"]) |
is_conditional | Boolean | Indicates if the order is conditional |
trigger_at | Integer | Trigger timestamp in UNIX millis |
placed_order_hash | String | Hash of order placed upon conditional order trigger |
margin | String | The margin of the order |
tx_hash | String | Transaction hash in which the order was created (not all orders have this value) |
cid | String | Identifier for the order specified by the user (up to 36 characters, like a UUID) |
Paging
Parameter | Type | Description |
---|---|---|
total | Integer | Total number of available records |
StreamOrdersHistory
Stream order updates of a derivative market.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from typing import Any, Dict
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def order_event_processor(event: Dict[str, Any]):
print(event)
def stream_error_processor(exception: RpcError):
print(f"There was an error listening to derivative orders history updates ({exception})")
def stream_closed_processor():
print("The derivative orders history updates stream has been closed")
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
task = asyncio.get_event_loop().create_task(
client.listen_derivative_orders_history_updates(
callback=order_event_processor,
on_end_callback=stream_closed_processor,
on_status_callback=stream_error_processor,
market_id=market_id,
)
)
await asyncio.sleep(delay=60)
task.cancel()
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
subaccountId := "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"
direction := "buy"
req := derivativeExchangePB.StreamOrdersHistoryRequest{
MarketId: marketId,
SubaccountId: subaccountId,
Direction: direction,
}
stream, err := exchangeClient.StreamHistoricalDerivativeOrders(ctx, &req)
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
return
default:
res, err := stream.Recv()
if err != nil {
panic(err)
return
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
}
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | Filter by subaccount ID | No |
market_id | String | Filter by market ID | No |
order_types | String Array | Filter by order type (Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell", "buy_po", "sell_po"]) | No |
direction | String | Filter by direction (Should be one of: ["buy", "sell"]) | No |
state | String | Filter by state (Should be one of: ["booked", "partial_filled", "filled", "canceled"]) | No |
execution_types | String Array | Filter by execution type (Should be one of: ["limit", "market"]) | No |
callback | Function | Function receiving one parameter (a stream event JSON dictionary) to process each new event | Yes |
on_end_callback | Function | Function with the logic to execute when the stream connection is interrupted | No |
on_status_callback | Function | Function receiving one parameter (the exception) with the logic to execute when an exception happens | No |
Response Parameters
Streaming Response Example:
{
"order":{
"order_hash":"0x4aeb72ac2ae5811126a0c384e05ce68745316add0e705c39e73f68c76431515e",
"market_id":"0x141e3c92ed55107067ceb60ee412b86256cedef67b1227d6367b4cdf30c55a74",
"is_active":true,
"subaccount_id":"0x7619f89a2172c6705aac7482f3adbf0601ea140e000000000000000000000000",
"execution_type":"limit",
"order_type":"sell_po",
"price":"27953000000",
"trigger_price":"0",
"quantity":"0.0344",
"filled_quantity":"0",
"state":"booked",
"created_at":1696617269292,
"updated_at":1696617269292,
"direction":"sell",
"margin":"320527734"
},
"operation_type":"insert",
"timestamp":1696617272000
}
{
"order":{
"order_hash":"0x24d82da3530ce5d2d392c9563d29b79c3a25e058dd6d79e0d8f651703256eb78",
"market_id":"0x141e3c92ed55107067ceb60ee412b86256cedef67b1227d6367b4cdf30c55a74",
"subaccount_id":"0x6590d14d9e9c1d964f8c83bddc8a092f4a2d1284000000000000000000000000",
"execution_type":"limit",
"order_type":"buy_po",
"price":"27912000000",
"trigger_price":"0",
"quantity":"0.0344",
"filled_quantity":"0",
"state":"canceled",
"created_at":1696617207873,
"updated_at":1696617269292,
"direction":"buy",
"margin":"320057600"
},
"operation_type":"update",
"timestamp":1696617272000
}
{
"order":{
"order_hash":"0x4aeb72ac2ae5811126a0c384e05ce68745316add0e705c39e73f68c76431515e",
"market_id":"0x141e3c92ed55107067ceb60ee412b86256cedef67b1227d6367b4cdf30c55a74",
"is_active":true,
"subaccount_id":"0x7619f89a2172c6705aac7482f3adbf0601ea140e000000000000000000000000",
"execution_type":"limit",
"order_type":"sell_po",
"price":"27953000000",
"trigger_price":"0",
"quantity":"0.0344",
"filled_quantity":"0",
"state":"booked",
"created_at":1696617269292,
"updated_at":1696617269292,
"direction":"sell",
"margin":"320527734"
},
"operation_type":"insert",
"timestamp":1696617272000
}
{
"order":{
"order_hash":"0x24d82da3530ce5d2d392c9563d29b79c3a25e058dd6d79e0d8f651703256eb78",
"market_id":"0x141e3c92ed55107067ceb60ee412b86256cedef67b1227d6367b4cdf30c55a74",
"subaccount_id":"0x6590d14d9e9c1d964f8c83bddc8a092f4a2d1284000000000000000000000000",
"execution_type":"limit",
"order_type":"buy_po",
"price":"27912000000",
"trigger_price":"0",
"quantity":"0.0344",
"filled_quantity":"0",
"state":"canceled",
"created_at":1696617207873,
"updated_at":1696617269292,
"direction":"buy",
"margin":"320057600"
},
"operation_type":"update",
"timestamp":1696617272000
}
Parameter | Type | Description |
---|---|---|
order | DerivativeOrderHistory | Updated order |
operation_type | String | Order update type (Should be one of: ["insert", "replace", "update", "invalidate"]) |
timestamp | Integer | Operation timestamp in UNIX millis |
DerivativeOrderHistory
Parameter | Type | Description |
---|---|---|
order_hash | String | Hash of the order |
market_id | String | Derivative market ID |
is_active | Boolean | Indicates if the order is active |
subaccount_id | String | The subaccountId that this order belongs to |
execution_type | String | The type of the order (Should be one of: ["limit", "market"]) |
order_type | String | Order type (Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell", "buy_po", "sell_po"]) |
price | String | Price of the order |
trigger_price | String | The price that triggers stop/take orders |
quantity | String | Quantity of the order |
filled_quantity | String | The amount of the quantity filled |
state | String | Order state (Should be one of: ["booked", "partial_filled", "filled", "canceled"]) |
created_at | Integer | Order created timestamp in UNIX millis |
updated_at | Integer | Order updated timestamp in UNIX millis |
is_reduce_only | Boolean | Indicates if the order is reduce-only |
direction | String | The direction of the order (Should be one of: ["buy", "sell"]) |
is_conditional | Boolean | Indicates if the order is conditional |
trigger_at | Integer | Trigger timestamp in UNIX millis |
placed_order_hash | String | Hash of order placed upon conditional order trigger |
margin | String | The margin of the order |
tx_hash | String | Transaction hash in which the order was created (not all orders have this value) |
cid | String | Identifier for the order specified by the user (up to 36 characters, like a UUID) |
TradesV2
Get trades of a derivative market.
The difference between Trades
and TradesV2
is that the latter returns a trade_id
compatible witht the one used for trade events in chain stream.
IP rate limit group: indexer
*Trade execution types
"market"
for market orders"limitFill"
for a resting limit order getting filled by a market order"limitMatchRestingOrder"
for a resting limit order getting matched with another new limit order"limitMatchNewOrder"
for a new limit order getting matched immediately
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
market_ids = ["0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"]
subaccount_ids = ["0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"]
skip = 0
limit = 4
pagination = PaginationOption(skip=skip, limit=limit)
trades = await client.fetch_derivative_trades(
market_ids=market_ids, subaccount_ids=subaccount_ids, pagination=pagination
)
print(trades)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"
subaccountId := "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"
req := derivativeExchangePB.TradesV2Request{
MarketId: marketId,
SubaccountId: subaccountId,
}
res, err := exchangeClient.GetDerivativeTradesV2(ctx, &req)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_ids | String Array | Filter by multiple market IDs | No |
subaccount_ids | String Array | Filter by multiple subaccount IDs | No |
execution_side | String | Filter by the execution side of the trade (Should be one of: ["maker", "taker"]) | No |
direction | String | Filter by the direction of the trade (Should be one of: ["buy", "sell"]) | No |
execution_types | String Array | Filter by the *trade execution type (Should be any of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"]) | No |
trade_id | String | Filter by the trade id of the trade | No |
account_address | String | Filter by the account address | No |
cid | String | Filter by the custom client order id of the trade's order | No |
pagination | PaginationOption | Pagination configuration | No |
Response Parameters
Response Example:
{
"trades":[
{
"orderHash":"0xc246b6a43d826667047f752a76e508511d0aa4f73aba1c3b95527037ccbcb50c",
"subaccountId":"0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
"marketId":"0x56d0c0293c4415e2d48fc2c8503a56a0c7389247396a2ef9b0a48c01f0646705",
"tradeExecutionType":"limitMatchRestingOrder",
"positionDelta":{
"tradeDirection":"buy",
"executionPrice":"10000000",
"executionQuantity":"1",
"executionMargin":"10000000"
},
"payout":"0",
"fee":"-60000",
"executedAt":"1701978102242",
"feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"tradeId":"22868_2",
"executionSide":"maker",
"cid":"49fb387d-aad3-4f03-85c5-e6c06c5ea685",
"isLiquidation":false
},
{
"orderHash":"0x836e778ae11cee6cd31619ca7329121419471be7ea1bd2fafbae3a8d411a04c7",
"subaccountId":"0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
"marketId":"0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4",
"tradeExecutionType":"limitMatchRestingOrder",
"positionDelta":{
"tradeDirection":"buy",
"executionPrice":"10000000",
"executionQuantity":"1",
"executionMargin":"10000000"
},
"payout":"0",
"fee":"-600",
"executedAt":"1701978102242",
"feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"tradeId":"22868_4",
"executionSide":"maker",
"cid":"9a74f3ce-ea31-491e-9e64-e48541a8f7fd",
"isLiquidation":false
},
{
"orderHash":"0x404577bc40896028733f7740d4efc6f6695fb9194f43dd545fb8923cbb01efd6",
"subaccountId":"0x3db1f84431dfe4df617f9eb2d04edf432beb9826000000000000000000000000",
"marketId":"0x56d0c0293c4415e2d48fc2c8503a56a0c7389247396a2ef9b0a48c01f0646705",
"tradeExecutionType":"limitMatchNewOrder",
"positionDelta":{
"tradeDirection":"sell",
"executionPrice":"10000000",
"executionQuantity":"1",
"executionMargin":"10000000"
},
"payout":"0",
"fee":"5000000",
"executedAt":"1701978102242",
"feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"tradeId":"22868_3",
"executionSide":"taker",
"cid":"derivative_ATOM/USDT",
"isLiquidation":false
},
{
"orderHash":"0x3fde93ceabc67a13372c237f5271784c0bbe97801ef12e883cfbde4c13e16300",
"subaccountId":"0x3db1f84431dfe4df617f9eb2d04edf432beb9826000000000000000000000000",
"marketId":"0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4",
"tradeExecutionType":"limitMatchNewOrder",
"positionDelta":{
"tradeDirection":"sell",
"executionPrice":"10000000",
"executionQuantity":"1",
"executionMargin":"9000000"
},
"payout":"0",
"fee":"10000",
"executedAt":"1701978102242",
"feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"tradeId":"22868_5",
"executionSide":"taker",
"cid":"derivative_INJ/USDT",
"isLiquidation":false
},
{
"orderHash":"0xc246b6a43d826667047f752a76e508511d0aa4f73aba1c3b95527037ccbcb50c",
"subaccountId":"0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
"marketId":"0x56d0c0293c4415e2d48fc2c8503a56a0c7389247396a2ef9b0a48c01f0646705",
"tradeExecutionType":"limitMatchRestingOrder",
"positionDelta":{
"tradeDirection":"buy",
"executionPrice":"10000000",
"executionQuantity":"1",
"executionMargin":"10000000"
},
"payout":"0",
"fee":"-60000",
"executedAt":"1701961116630",
"feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"tradeId":"1321_2",
"executionSide":"maker",
"cid":"49fb387d-aad3-4f03-85c5-e6c06c5ea685",
"isLiquidation":false
},
{
"orderHash":"0x836e778ae11cee6cd31619ca7329121419471be7ea1bd2fafbae3a8d411a04c7",
"subaccountId":"0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
"marketId":"0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4",
"tradeExecutionType":"limitMatchRestingOrder",
"positionDelta":{
"tradeDirection":"buy",
"executionPrice":"10000000",
"executionQuantity":"1",
"executionMargin":"10000000"
},
"payout":"0",
"fee":"-600",
"executedAt":"1701961116630",
"feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"tradeId":"1321_4",
"executionSide":"maker",
"cid":"9a74f3ce-ea31-491e-9e64-e48541a8f7fd",
"isLiquidation":false
},
{
"orderHash":"0xf6ae77b0a1e267b7f0b8618f3f226c39ba702a09fb3bdb650b0c28197d36d91d",
"subaccountId":"0x3db1f84431dfe4df617f9eb2d04edf432beb9826000000000000000000000000",
"marketId":"0x56d0c0293c4415e2d48fc2c8503a56a0c7389247396a2ef9b0a48c01f0646705",
"tradeExecutionType":"limitMatchNewOrder",
"positionDelta":{
"tradeDirection":"sell",
"executionPrice":"10000000",
"executionQuantity":"1",
"executionMargin":"10000000"
},
"payout":"0",
"fee":"5000000",
"executedAt":"1701961116630",
"feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"tradeId":"1321_3",
"executionSide":"taker",
"cid":"49fb387d-aad3-4f03-85c5-e6c06c5ea685",
"isLiquidation":false
},
{
"orderHash":"0x01ba4dd3b30bc946a31f5fe1aba9918e95d3dc8cf31a6c4b2d793068eae529e8",
"subaccountId":"0x3db1f84431dfe4df617f9eb2d04edf432beb9826000000000000000000000000",
"marketId":"0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4",
"tradeExecutionType":"limitMatchNewOrder",
"positionDelta":{
"tradeDirection":"sell",
"executionPrice":"10000000",
"executionQuantity":"1",
"executionMargin":"9000000"
},
"payout":"0",
"fee":"10000",
"executedAt":"1701961116630",
"feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"tradeId":"1321_5",
"executionSide":"taker",
"cid":"9a74f3ce-ea31-491e-9e64-e48541a8f7fd",
"isLiquidation":false
}
],
"paging":{
"total":"8",
"from":1,
"to":8,
"countBySubaccount":"0",
"next":[
]
}
}
{
"trades": [
{
"order_hash": "0x836e778ae11cee6cd31619ca7329121419471be7ea1bd2fafbae3a8d411a04c7",
"subaccount_id": "0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
"market_id": "0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4",
"trade_execution_type": "limitMatchRestingOrder",
"position_delta": {
"trade_direction": "buy",
"execution_price": "10000000",
"execution_quantity": "1",
"execution_margin": "10000000"
},
"payout": "0",
"fee": "-600",
"executed_at": 1701978102242,
"fee_recipient": "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"trade_id": "22868_4",
"execution_side": "maker",
"cid": "9a74f3ce-ea31-491e-9e64-e48541a8f7fd"
},
{
"order_hash": "0x3fde93ceabc67a13372c237f5271784c0bbe97801ef12e883cfbde4c13e16300",
"subaccount_id": "0x3db1f84431dfe4df617f9eb2d04edf432beb9826000000000000000000000000",
"market_id": "0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4",
"trade_execution_type": "limitMatchNewOrder",
"position_delta": {
"trade_direction": "sell",
"execution_price": "10000000",
"execution_quantity": "1",
"execution_margin": "9000000"
},
"payout": "0",
"fee": "10000",
"executed_at": 1701978102242,
"fee_recipient": "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"trade_id": "22868_5",
"execution_side": "taker",
"cid": "9a74f3ce-ea31-491e-9e64-e48541a8f7fd"
},
{
"order_hash": "0x836e778ae11cee6cd31619ca7329121419471be7ea1bd2fafbae3a8d411a04c7",
"subaccount_id": "0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
"market_id": "0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4",
"trade_execution_type": "limitMatchRestingOrder",
"position_delta": {
"trade_direction": "buy",
"execution_price": "10000000",
"execution_quantity": "1",
"execution_margin": "10000000"
},
"payout": "0",
"fee": "-600",
"executed_at": 1701961116630,
"fee_recipient": "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"trade_id": "1321_4",
"execution_side": "maker",
"cid": "9a74f3ce-ea31-491e-9e64-e48541a8f7fd"
},
{
"order_hash": "0x01ba4dd3b30bc946a31f5fe1aba9918e95d3dc8cf31a6c4b2d793068eae529e8",
"subaccount_id": "0x3db1f84431dfe4df617f9eb2d04edf432beb9826000000000000000000000000",
"market_id": "0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4",
"trade_execution_type": "limitMatchNewOrder",
"position_delta": {
"trade_direction": "sell",
"execution_price": "10000000",
"execution_quantity": "1",
"execution_margin": "9000000"
},
"payout": "0",
"fee": "10000",
"executed_at": 1701961116630,
"fee_recipient": "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"trade_id": "1321_5",
"execution_side": "taker",
"cid": "9a74f3ce-ea31-491e-9e64-e48541a8f7fd"
}
],
"paging": {
"total": 4,
"from": 1,
"to": 4
}
}
Parameter | Type | Description |
---|---|---|
trades | DerivativeTrade Array | List of trades of derivative markets |
paging | Paging | Pagination of results |
DerivativeTrade
Parameter | Type | Description |
---|---|---|
order_hash | String | The order hash |
subaccount_id | String | ID of subaccount that executed the trade |
market_id | String | The market ID |
trade_execution_type | String | *Execution type of the trade (Should be one of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"]) |
is_liquidation | Boolean | True if the trade is a liquidation |
position_delta | PositionDelta | Position delta from the trade |
payout | String | The payout associated with the trade |
fee | String | The fee associated with the trade |
executed_at | Integer | Timestamp of trade execution (on chain) in UNIX millis |
fee_recipient | String | The address that received 40% of the fees |
trade_id | String | Unique identifier to differentiate between trades |
execution_side | String | Execution side of trade (Should be one of: ["maker", "taker"]) |
cid | String | Custom client order id |
PositionDelta
Parameter | Type | Description |
---|---|---|
execution_price | String | Execution price of the trade |
execution_quantity | String | Execution quantity of the trade |
trade_direction | String | The direction the trade (Should be one of: ["buy", "sell"]) |
execution_margin | String | Execution margin of the trade |
Paging
Parameter | Type | Description |
---|---|---|
total | Integer | Total number of records available |
StreamTradesV2
Stream newly executed trades of a derivative market. The default request streams trades from all derivative markets.
The difference between StreamTrades
and StreamTradesV2
is that the latter returns a trade_id
compatible witht the one used for trade events in chain stream.
IP rate limit group: indexer
*Trade execution types
"market"
for market orders"limitFill"
for a resting limit order getting filled by a market order"limitMatchRestingOrder"
for a resting limit order getting matched with another new limit order"limitMatchNewOrder"
for a new limit order getting matched immediately
Request Parameters
Request Example:
import asyncio
from typing import Any, Dict
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def market_event_processor(event: Dict[str, Any]):
print(event)
def stream_error_processor(exception: RpcError):
print(f"There was an error listening to derivative trades updates ({exception})")
def stream_closed_processor():
print("The derivative trades updates stream has been closed")
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
market_ids = [
"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"0x70bc8d7feab38b23d5fdfb12b9c3726e400c265edbcbf449b6c80c31d63d3a02",
]
subaccount_ids = ["0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"]
task = asyncio.get_event_loop().create_task(
client.listen_derivative_trades_updates(
callback=market_event_processor,
on_end_callback=stream_closed_processor,
on_status_callback=stream_error_processor,
market_ids=market_ids,
subaccount_ids=subaccount_ids,
)
)
await asyncio.sleep(delay=60)
task.cancel()
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"
subaccountId := "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"
req := derivativeExchangePB.StreamTradesV2Request{
MarketId: marketId,
SubaccountId: subaccountId,
}
stream, err := exchangeClient.StreamDerivativeV2Trades(ctx, &req)
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
return
default:
res, err := stream.Recv()
if err != nil {
panic(err)
return
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
}
}
Parameter | Type | Description | Required |
---|---|---|---|
market_ids | String Array | Filter by multiple market IDs | No |
execution_side | String | Filter by the execution side of the trade (Should be one of: ["maker", "taker"]) | No |
direction | String | Filter by the direction of the trade (Should be one of: ["buy", "sell"]) | No |
subaccount_ids | String Array | Filter by multiple subaccount IDs | No |
execution_types | String Array | Filter by the *trade execution type (Should be one of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"]) | No |
trade_id | String | Filter by the trade's trade id | No |
account_address | String | Filter by the account address | No |
cid | String | Filter by the custom client order id of the trade's order | No |
pagination | PaginationOption | Pagination configuration | No |
callback | Function | Function receiving one parameter (a stream event JSON dictionary) to process each new event | Yes |
on_end_callback | Function | Function with the logic to execute when the stream connection is interrupted | No |
on_status_callback | Function | Function receiving one parameter (the exception) with the logic to execute when an exception happens | No |
Response Parameters
Streaming Response Example:
{
"trade":{
"orderHash":"0x01e6b3df831734c88c84522f9834b3656b3afde6891ac671742dd269be776510",
"subaccountId":"0x3db1f84431dfe4df617f9eb2d04edf432beb9826000000000000000000000000",
"marketId":"0x56d0c0293c4415e2d48fc2c8503a56a0c7389247396a2ef9b0a48c01f0646705",
"tradeExecutionType":"limitMatchNewOrder",
"positionDelta":{
"tradeDirection":"sell",
"executionPrice":"10000000",
"executionQuantity":"1",
"executionMargin":"10000000"
},
"payout":"0",
"fee":"5000000",
"executedAt":"1701979920875",
"feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"tradeId":"25116_3",
"executionSide":"taker",
"cid":"derivative_ATOM/USDT",
"isLiquidation":false
},
"operationType":"insert",
"timestamp":"1701979922000"
}
{
"trade":{
"orderHash":"0xc246b6a43d826667047f752a76e508511d0aa4f73aba1c3b95527037ccbcb50c",
"subaccountId":"0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
"marketId":"0x56d0c0293c4415e2d48fc2c8503a56a0c7389247396a2ef9b0a48c01f0646705",
"tradeExecutionType":"limitMatchRestingOrder",
"positionDelta":{
"tradeDirection":"buy",
"executionPrice":"10000000",
"executionQuantity":"1",
"executionMargin":"10000000"
},
"payout":"0",
"fee":"-60000",
"executedAt":"1701979920875",
"feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"tradeId":"25116_2",
"executionSide":"maker",
"cid":"49fb387d-aad3-4f03-85c5-e6c06c5ea685",
"isLiquidation":false
},
"operationType":"insert",
"timestamp":"1701979922000"
}
{
"trade":{
"orderHash":"0xa0446c80b66dd6ab75b32e51e4e04929ae92df9fa7a64fe2d21ed9be536bb6d5",
"subaccountId":"0x3db1f84431dfe4df617f9eb2d04edf432beb9826000000000000000000000000",
"marketId":"0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4",
"tradeExecutionType":"limitMatchNewOrder",
"positionDelta":{
"tradeDirection":"sell",
"executionPrice":"10000000",
"executionQuantity":"1",
"executionMargin":"9000000"
},
"payout":"0",
"fee":"10000",
"executedAt":"1701979920875",
"feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"tradeId":"25116_5",
"executionSide":"taker",
"cid":"derivative_INJ/USDT",
"isLiquidation":false
},
"operationType":"insert",
"timestamp":"1701979922000"
}
{
"trade":{
"orderHash":"0x836e778ae11cee6cd31619ca7329121419471be7ea1bd2fafbae3a8d411a04c7",
"subaccountId":"0x101411266c6e2b610b4a0324d2bfb2ef0ca6e1dd000000000000000000000000",
"marketId":"0x7cc8b10d7deb61e744ef83bdec2bbcf4a056867e89b062c6a453020ca82bd4e4",
"tradeExecutionType":"limitMatchRestingOrder",
"positionDelta":{
"tradeDirection":"buy",
"executionPrice":"10000000",
"executionQuantity":"1",
"executionMargin":"10000000"
},
"payout":"0",
"fee":"-600",
"executedAt":"1701979920875",
"feeRecipient":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"tradeId":"25116_4",
"executionSide":"maker",
"cid":"9a74f3ce-ea31-491e-9e64-e48541a8f7fd",
"isLiquidation":false
},
"operationType":"insert",
"timestamp":"1701979922000"
}
{
"trade": {
"order_hash": "0x0403d2e51d73aa1cb46004b16d76279afece9ad14e3784eb93aa6370de466f81",
"subaccount_id": "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000",
"market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
"trade_execution_type": "limitMatchRestingOrder",
"position_delta": {
"trade_direction": "sell",
"execution_price": "40249100000",
"execution_quantity": "0.06",
"execution_margin": "2388462000"
},
"payout": "0",
"fee": "1207473",
"executed_at": 1653040243183,
"fee_recipient": "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r"
},
"operation_type": "insert",
"timestamp": 1653040246000
}{
"trade": {
"order_hash": "0x728d69975e4057d1801f1a7031d0ccf7242abacbf73320da55abab677efc2a7e",
"subaccount_id": "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000",
"market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
"trade_execution_type": "limitMatchRestingOrder",
"position_delta": {
"trade_direction": "sell",
"execution_price": "40249100000",
"execution_quantity": "0.02",
"execution_margin": "779300000"
},
"payout": "0",
"fee": "402491",
"executed_at": 1653040243183,
"fee_recipient": "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r"
},
"operation_type": "insert",
"timestamp": 1653040246000
}
Parameter | Type | Description |
---|---|---|
trade | DerivativeTrade | New derivative market trade |
operation_type | String | Trade operation type (Should be one of: ["insert", "invalidate"]) |
timestamp | Integer | Timestamp the new trade is written into the database in UNIX millis |
DerivativeTrade
Parameter | Type | Description |
---|---|---|
order_hash | String | The order hash |
subaccount_id | String | ID of subaccount that executed the trade |
market_id | String | The market ID |
trade_execution_type | String | *Execution type of the trade (Should be one of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"]) |
is_liquidation | Boolean | True if the trade is a liquidation |
position_delta | PositionDelta | Position delta from the trade |
payout | String | The payout associated with the trade |
fee | String | The fee associated with the trade |
executed_at | Integer | Timestamp of trade execution (on chain) in UNIX millis |
fee_recipient | String | The address that received 40% of the fees |
trade_id | String | Unique identifier to differentiate between trades |
execution_side | String | Execution side of trade (Should be one of: ["maker", "taker"]) |
cid | String | Custom client order id |
PositionDelta
Parameter | Type | Description |
---|---|---|
execution_price | String | Execution price of the trade |
execution_quantity | String | Execution quantity of the trade |
trade_direction | String | The direction the trade (Should be one of: ["buy", "sell"]) |
execution_margin | String | Execution margin of the trade |
Positions
Get the positions of a market.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
market_ids = [
"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"0xd97d0da6f6c11710ef06315971250e4e9aed4b7d4cd02059c9477ec8cf243782",
]
subaccount_id = "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"
direction = "short"
subaccount_total_positions = False
skip = 4
limit = 4
pagination = PaginationOption(skip=skip, limit=limit)
positions = await client.fetch_derivative_positions_v2(
market_ids=market_ids,
subaccount_id=subaccount_id,
direction=direction,
subaccount_total_positions=subaccount_total_positions,
pagination=pagination,
)
print(positions)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
subaccountId := "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"
skip := uint64(0)
limit := int32(10)
req := derivativeExchangePB.PositionsV2Request{
MarketId: marketId,
SubaccountId: subaccountId,
Skip: skip,
Limit: limit,
}
res, err := exchangeClient.GetDerivativePositionsV2(ctx, &req)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_ids | String Array | Filter by multiple market IDs | No |
subaccount_id | String | Filter by subaccount ID | No |
direction | String | Filter by direction of position (Should be one of: ["long", "short"]) | No |
subaccount_total_positions | Boolean | Choose to return subaccount total positions (Should be one of: [True, False]) | No |
pagination | PaginationOption | Pagination configuration | No |
Response Parameters
Response Example:
{
"positions":[
{
"ticker":"INJ/USDT PERP",
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccountId":"0x0000007c60fab7a70c2ae0ebe437f3726b05e7eb000000000000000000000000",
"direction":"short",
"quantity":"0.087829315829932072",
"entryPrice":"26453271.813315285838444221",
"margin":"1156906.224974",
"liquidationPrice":"38848511.946759",
"markPrice":"35561999.99",
"updatedAt":"1703793600379"
},
{
"ticker":"INJ/USDT PERP",
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccountId":"0x0000040f1111c5c3d2037940658ee770bb37e0a2000000000000000000000000",
"direction":"long",
"quantity":"0.000068500966722584",
"entryPrice":"12293600",
"margin":"440.389918",
"liquidationPrice":"5984327.380009",
"markPrice":"35561999.99",
"updatedAt":"1703793600379"
},
{
"ticker":"INJ/USDT PERP",
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccountId":"0x00509ed903475672121d6a1fb2c646eef4da6c44000000000000000000000000",
"direction":"short",
"quantity":"0.022151816236313182",
"entryPrice":"15980281.340438795311756833",
"margin":"172782.601001",
"liquidationPrice":"23313932.022168",
"markPrice":"35561999.99",
"updatedAt":"1703793600379"
},
],
"paging":{
"total":"1166",
"from":0,
"to":0,
"countBySubaccount":"0",
"next":[
]
}
}
{
"positions": [
{
"ticker": "INJ/USDT PERP",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0x0000007c60fab7a70c2ae0ebe437f3726b05e7eb000000000000000000000000",
"direction": "short",
"quantity": "0.087829315829932072",
"entry_price": "26453271.813315285838444221",
"margin": "1156893.718782",
"liquidation_price": "38848372.346758",
"mark_price": "35294291.44",
"updated_at": 1703790001819
},
{
"ticker": "INJ/USDT PERP",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0x0000040f1111c5c3d2037940658ee770bb37e0a2000000000000000000000000",
"direction": "long",
"quantity": "0.000068500966722584",
"entry_price": "12293600",
"margin": "440.399672",
"liquidation_price": "5984182.081895",
"mark_price": "35294291.44",
"updated_at": 1703790001819
},
{
"ticker": "INJ/USDT PERP",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0x00509ed903475672121d6a1fb2c646eef4da6c44000000000000000000000000",
"direction": "short",
"quantity": "0.022151816236313182",
"entry_price": "15980281.340438795311756833",
"margin": "172779.44676",
"liquidation_price": "23313792.422186",
"mark_price": "35294291.44",
"updated_at": 1703790001819
},
{
"ticker": "INJ/USDT PERP",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0x00606da8ef76ca9c36616fa576d1c053bb0f7eb2000000000000000000000000",
"direction": "short",
"quantity": "0.041121486263975195",
"entry_price": "15980281.340438795311756842",
"margin": "320624.783065",
"liquidation_price": "23311073.361647",
"mark_price": "35294291.44",
"updated_at": 1703790001819
},
{
"ticker": "INJ/USDT PERP",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0x00cd2929594559000670af009e2f5ef15fefa6cf000000000000000000000000",
"direction": "long",
"quantity": "0.000050211853307914",
"entry_price": "12293600",
"margin": "322.774915",
"liquidation_price": "5985039.457698",
"mark_price": "35294291.44",
"updated_at": 1703790001819
},
{
"ticker": "INJ/USDT PERP",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0x00cf63fab44e827a4fb12142d6e0d8e82099701a000000000000000000000000",
"direction": "long",
"quantity": "0.000058171926973086",
"entry_price": "12293600",
"margin": "374.127106",
"liquidation_price": "5981833.667338",
"mark_price": "35294291.44",
"updated_at": 1703790001819
},
{
"ticker": "INJ/USDT PERP",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0x010d36443f440708892e79dcbb6c1350c4c76662000000000000000000000000",
"direction": "long",
"quantity": "0.00008708028566368",
"entry_price": "12293600",
"margin": "559.983294",
"liquidation_price": "5982596.709155",
"mark_price": "35294291.44",
"updated_at": 1703790001819
},
{
"ticker": "INJ/USDT PERP",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0x0154fc01caf0e4c82b7ea6c9be719c260e940ef3000000000000000000000000",
"direction": "short",
"quantity": "0.005684726095134712",
"entry_price": "19468749.344033524349659551",
"margin": "54688.034814",
"liquidation_price": "28518548.958621",
"mark_price": "35294291.44",
"updated_at": 1703790001819
},
{
"ticker": "INJ/USDT PERP",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0x0198b3d3691bcc1718dcda4277bb27c68fd19a6f000000000000000000000000",
"direction": "short",
"quantity": "1.950155851194068459",
"entry_price": "34111005.753742189227540816",
"margin": "33194528.351493",
"liquidation_price": "50129882.732098",
"mark_price": "35294291.44",
"updated_at": 1703790001819
},
{
"ticker": "INJ/USDT PERP",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0x021a86b9858f6e4150a724d444e94d10cb75c1b1000000000000000000000000",
"direction": "short",
"quantity": "0.077749303393590607",
"entry_price": "15980281.340438795311756851",
"margin": "605813.214778",
"liquidation_price": "23306040.184987",
"mark_price": "35294291.44",
"updated_at": 1703790001819
}
],
"paging": {
"total": 1153
}
}
Parameter | Type | Description |
---|---|---|
positions | DerivativePosition Array | List of derivative positions |
paging | Paging | Pagination of results |
DerivativePosition
Parameter | Type | Description |
---|---|---|
ticker | String | Ticker of the derivative market |
market_id | String | ID of the market the position is in |
subaccount_id | String | The subaccount ID the position belongs to |
direction | String | Direction of the position (Should be one of: ["long", "short"]) |
quantity | String | Quantity of the position |
entry_price | String | Entry price of the position |
margin | String | Margin of the position |
liquidation_price | String | Liquidation price of the position |
mark_price | String | Oracle price of the base asset |
updated_at | Integer | Position updated timestamp in UNIX millis |
Paging
Parameter | Type | Description |
---|---|---|
total | Integer | Total number of available records |
StreamPositions
Stream position updates for a specific market.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from typing import Any, Dict
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def positions_event_processor(event: Dict[str, Any]):
print(event)
def stream_error_processor(exception: RpcError):
print(f"There was an error listening to derivative positions updates ({exception})")
def stream_closed_processor():
print("The derivative positions updates stream has been closed")
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
market_ids = ["0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"]
subaccount_ids = ["0xea98e3aa091a6676194df40ac089e40ab4604bf9000000000000000000000000"]
task = asyncio.get_event_loop().create_task(
client.listen_derivative_positions_updates(
callback=positions_event_processor,
on_end_callback=stream_closed_processor,
on_status_callback=stream_error_processor,
market_ids=market_ids,
subaccount_ids=subaccount_ids,
)
)
await asyncio.sleep(delay=60)
task.cancel()
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"
subaccountId := "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"
req := derivativeExchangePB.StreamPositionsRequest{
MarketId: marketId,
SubaccountId: subaccountId,
}
stream, err := exchangeClient.StreamDerivativePositions(ctx, &req)
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
return
default:
res, err := stream.Recv()
if err != nil {
panic(err)
return
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
}
}
Parameter | Type | Description | Required |
---|---|---|---|
market_ids | String Array | IDs of the markets to stream position data from | No |
subaccount_ids | String Array | Subaccount IDs of the traders to stream positions from | No |
callback | Function | Function receiving one parameter (a stream event JSON dictionary) to process each new event | Yes |
on_end_callback | Function | Function with the logic to execute when the stream connection is interrupted | No |
on_status_callback | Function | Function receiving one parameter (the exception) with the logic to execute when an exception happens | No |
Response Parameters
Streaming Response Example:
{
"position": {
"ticker": "BTC/USDT PERP",
"marketId": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
"subaccountId": "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000",
"direction": "short",
"quantity": "1.6321",
"entryPrice": "40555935751.758890674529114982",
"margin": "65283896141.678537523412631302",
"liquidationPrice": "76719878206.648298",
"markPrice": "40128736026.4094317665",
"aggregateReduceOnlyQuantity": "0"
},
"timestamp": 1654246646000
}
{
"position": {
"ticker": "BTC/USDT PERP",
"marketId": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
"subaccountId": "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000",
"direction": "short",
"quantity": "1.6321",
"entryPrice": "40489113688.030524225816723708",
"margin": "65069810777.851918748331744252",
"liquidationPrice": "76531312698.56045",
"markPrice": "40128736026.4094317665",
"aggregateReduceOnlyQuantity": "0"
},
"timestamp": 1654246687000
}
{
"position": {
"ticker": "BTC/USDT PERP",
"market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
"subaccount_id": "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000",
"direction": "short",
"quantity": "0.4499",
"entry_price": "40187334829.308997167725462798",
"margin": "17648170480.844939276952101173",
"liquidation_price": "75632579558.528471",
"mark_price": "40128736026.4094317665",
"aggregate_reduce_only_quantity": "0"
},
"timestamp": 1653039418000
}{
"position": {
"ticker": "BTC/USDT PERP",
"market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
"subaccount_id": "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000",
"direction": "short",
"quantity": "0.4499",
"entry_price": "40415133266.89312760388339505",
"margin": "17780087110.130349528796488556",
"liquidation_price": "76128781140.582706",
"mark_price": "40128736026.4094317665",
"aggregate_reduce_only_quantity": "0"
},
"timestamp": 1653039464000
}{
"position": {
"ticker": "BTC/USDT PERP",
"market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
"subaccount_id": "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000",
"direction": "short",
"quantity": "0.4499",
"entry_price": "40306914705.252255649316986606",
"margin": "17654816331.908168110936068341",
"liquidation_price": "75760533574.235878",
"mark_price": "40128736026.4094317665",
"aggregate_reduce_only_quantity": "0"
},
"timestamp": 1653039501000
}
Parameter | Type | Description |
---|---|---|
position | DerivativePosition | Updated derivative position |
timestamp | Integer | Timestamp of update in UNIX millis |
DerivativePosition
Parameter | Type | Description |
---|---|---|
direction | String | Direction of the position (Should be one of: ["long", "short"]) |
market_id | String | ID of the market the position is in |
subaccount_id | String | The subaccount ID the position belongs to |
ticker | String | Ticker of the derivative market |
aggregate_reduce_only_quantity | String | Aggregate quantity of the reduce-only orders associated with the position |
entry_price | String | Entry price of the position |
liquidation_price | String | Liquidation price of the position |
margin | String | Margin of the position |
mark_price | String | Oracle price of the base asset |
quantity | String | Quantity of the position |
updated_at | Integer | Position updated timestamp in UNIX millis |
created_at | Integer | Position created timestamp in UNIX millis. Currently not supported (value will be inaccurate). |
LiquidablePositions
Gets all the liquidable positions
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
skip = 10
limit = 3
pagination = PaginationOption(skip=skip, limit=limit)
positions = await client.fetch_derivative_liquidable_positions(
market_id=market_id,
pagination=pagination,
)
print(positions)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
//marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
skip := uint64(0)
limit := int32(10)
req := derivativeExchangePB.LiquidablePositionsRequest{
//MarketId: marketId,
Skip: skip,
Limit: limit,
}
res, err := exchangeClient.GetDerivativeLiquidablePositions(ctx, &req)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | ID of the market to query liquidable positions for | Yes |
skip | Integer | Skip the first n cosmwasm contracts. This can be used to fetch all results since the API caps at 100 | No |
limit | Integer | Max number of items to be returned, defaults to 100 | No |
Response Parameters
Streaming Response Example:
{
"positions":[
{
"ticker":"INJ/USDT PERP",
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccountId":"0x0a5d67f3616a9e7b53c301b508e9384c6321be47000000000000000000000000",
"direction":"short",
"quantity":"0.00966730135521481",
"entryPrice":"15980281.340438795311756819",
"margin":"75611.273514",
"liquidationPrice":"23334925.188149",
"markPrice":"39291123.99",
"aggregateReduceOnlyQuantity":"0",
"updatedAt":"1705525203015",
"createdAt":"-62135596800000"
},
{
"ticker":"INJ/USDT PERP",
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccountId":"0x0c812012cf492aa422fb888e172fbd6e19df517b000000000000000000000000",
"direction":"short",
"quantity":"0.066327809378915175",
"entryPrice":"16031762.538045163086357667",
"margin":"520412.029703",
"liquidationPrice":"23409630.791347",
"markPrice":"39291123.99",
"aggregateReduceOnlyQuantity":"0",
"updatedAt":"1705525203015",
"createdAt":"-62135596800000"
},
{
"ticker":"INJ/USDT PERP",
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccountId":"0x0d750ad3404b6f23579706e44111e8dd774fd1fa000000000000000000000000",
"direction":"short",
"quantity":"0.000080602003464734",
"entryPrice":"16031762.53804516308635803",
"margin":"632.408209",
"liquidationPrice":"23409630.592378",
"markPrice":"39291123.99",
"aggregateReduceOnlyQuantity":"0",
"updatedAt":"1705525203015",
"createdAt":"-62135596800000"
}
]
}
{
"positions": [
{
"ticker": "SOL/USDT PERP",
"market_id": "0x95698a9d8ba11660f44d7001d8c6fb191552ece5d9141a05c5d9128711cdc2e0",
"subaccount_id": "0x0ddbe7ea40134ae14ed6a5d104d8783c80663edb000000000000000000000000",
"direction": "short",
"quantity": "135965",
"entry_price": "24074541.242231456624866694",
"margin": "922840147876.471312471775929175",
"liquidation_price": "29392264.1007154944460271",
"mark_price": "102769181.99",
"aggregate_reduce_only_quantity": "0",
"updated_at": 1703361600801,
"created_at": -62135596800000
},
{
"ticker": "SOL/USDT PERP",
"market_id": "0x95698a9d8ba11660f44d7001d8c6fb191552ece5d9141a05c5d9128711cdc2e0",
"subaccount_id": "0x16aef18dbaa341952f1af1795cb49960f68dfee3000000000000000000000000",
"direction": "short",
"quantity": "34.99",
"entry_price": "25000000",
"margin": "963925977.452838924992513061",
"liquidation_price": "50046298.3288514793340278",
"mark_price": "102769181.99",
"aggregate_reduce_only_quantity": "0",
"updated_at": 1703361600801,
"created_at": -62135596800000
},
{
"ticker": "SOL/USDT PERP",
"market_id": "0x95698a9d8ba11660f44d7001d8c6fb191552ece5d9141a05c5d9128711cdc2e0",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"direction": "short",
"quantity": "160",
"entry_price": "24375243.283322806982741737",
"margin": "3774845657.765183864053125849",
"liquidation_price": "45683836.8041478153648322",
"mark_price": "102769181.99",
"aggregate_reduce_only_quantity": "0",
"updated_at": 1703361600801,
"created_at": -62135596800000
},
{
"ticker": "SOL/USDT PERP",
"market_id": "0x95698a9d8ba11660f44d7001d8c6fb191552ece5d9141a05c5d9128711cdc2e0",
"subaccount_id": "0xce4c01573f2a5f4db5d184b666ecfccb9313cc65000000000000000000000000",
"direction": "short",
"quantity": "8",
"entry_price": "17700000",
"margin": "141673770.450618846533455704",
"liquidation_price": "33723067.9107879579206495",
"mark_price": "102769181.99",
"aggregate_reduce_only_quantity": "0",
"updated_at": 1703361600801,
"created_at": -62135596800000
},
{
"ticker": "INJ/USDT PERP",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0x0000007c60fab7a70c2ae0ebe437f3726b05e7eb000000000000000000000000",
"direction": "short",
"quantity": "0.087829315829932072",
"entry_price": "26453271.813315285838444221",
"margin": "1154483.475338511428917818",
"liquidation_price": "38821468.0751518485185464",
"mark_price": "40421744.55",
"aggregate_reduce_only_quantity": "0",
"updated_at": 1703361600801,
"created_at": -62135596800000
},
{
"ticker": "INJ/USDT PERP",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0x00509ed903475672121d6a1fb2c646eef4da6c44000000000000000000000000",
"direction": "short",
"quantity": "0.022151816236313182",
"entry_price": "15980281.340438795311756833",
"margin": "172410.019375666543049786",
"liquidation_price": "23297442.3538099336017081",
"mark_price": "40421744.55",
"aggregate_reduce_only_quantity": "0",
"updated_at": 1703361600801,
"created_at": -62135596800000
},
{
"ticker": "INJ/USDT PERP",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0x00606da8ef76ca9c36616fa576d1c053bb0f7eb2000000000000000000000000",
"direction": "short",
"quantity": "0.041121486263975195",
"entry_price": "15980281.340438795311756842",
"margin": "320053.045217395063737578",
"liquidation_price": "23297442.3538099336017082",
"mark_price": "40421744.55",
"aggregate_reduce_only_quantity": "0",
"updated_at": 1703361600801,
"created_at": -62135596800000
},
{
"ticker": "INJ/USDT PERP",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0x0154fc01caf0e4c82b7ea6c9be719c260e940ef3000000000000000000000000",
"direction": "short",
"quantity": "0.005684726095134712",
"entry_price": "19468749.344033524349659551",
"margin": "54563.593706555517738922",
"liquidation_price": "28497087.7512237107551938",
"mark_price": "40421744.55",
"aggregate_reduce_only_quantity": "0",
"updated_at": 1703361600801,
"created_at": -62135596800000
},
{
"ticker": "INJ/USDT PERP",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0x021a86b9858f6e4150a724d444e94d10cb75c1b1000000000000000000000000",
"direction": "short",
"quantity": "0.077749303393590607",
"entry_price": "15980281.340438795311756851",
"margin": "605131.369885566651321656",
"liquidation_price": "23297442.3538099336017081",
"mark_price": "40421744.55",
"aggregate_reduce_only_quantity": "0",
"updated_at": 1703361600801,
"created_at": -62135596800000
},
{
"ticker": "INJ/USDT PERP",
"market_id": "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccount_id": "0x03ca8d57285836857dddf42cbb896448015246e7000000000000000000000000",
"direction": "short",
"quantity": "3.933956815705317214",
"entry_price": "20294270.597312410912417203",
"margin": "39442957.950528509629919537",
"liquidation_price": "29726031.3451969744796065",
"mark_price": "40421744.55",
"aggregate_reduce_only_quantity": "0",
"updated_at": 1703361600801,
"created_at": -62135596800000
}
]
}
Parameter | Type | Description |
---|---|---|
positions | DerivativePosition Array | List of liquidable lpositions |
DerivativePosition
Parameter | Type | Description |
---|---|---|
direction | String | Direction of the position (Should be one of: ["long", "short"]) |
market_id | String | ID of the market the position is in |
subaccount_id | String | The subaccount ID the position belongs to |
ticker | String | Ticker of the derivative market |
aggregate_reduce_only_quantity | String | Aggregate quantity of the reduce-only orders associated with the position |
entry_price | String | Entry price of the position |
liquidation_price | String | Liquidation price of the position |
margin | String | Margin of the position |
mark_price | String | Oracle price of the base asset |
quantity | String | Quantity of the position |
updated_at | Integer | Position updated timestamp in UNIX millis |
created_at | Integer | Position created timestamp in UNIX millis. Currently not supported (value will be inaccurate). |
OrderbooksV2
Get an orderbook snapshot for one or more derivative markets.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
market_ids = [
"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"0xd5e4b12b19ecf176e4e14b42944731c27677819d2ed93be4104ad7025529c7ff",
]
orderbooks = await client.fetch_derivative_orderbooks_v2(market_ids=market_ids)
print(orderbooks)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketIds := []string{"0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"}
res, err := exchangeClient.GetDerivativeOrderbooksV2(ctx, marketIds)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_ids | String Array | List of IDs of markets to get orderbook snapshots from | Yes |
Response Parameters
Response Example:
{
"orderbooks":[
{
"marketId":"0xd5e4b12b19ecf176e4e14b42944731c27677819d2ed93be4104ad7025529c7ff",
"orderbook":{
"sequence":"4099",
"timestamp":"1681978300931",
"buys":[
],
"sells":[
]
}
},
{
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"orderbook":{
"buys":[
{
"price":"13400000",
"quantity":"683.3032",
"timestamp":"1702002966962"
},
{
"price":"13366500",
"quantity":"108438.1403",
"timestamp":"1702002966962"
}
],
"sells":[
{
"price":"18390200",
"quantity":"78815.8042",
"timestamp":"1702002966962"
}
],
"sequence":"1919116",
"timestamp":"1702003451726"
}
}
]
}
{
"orderbooks": [
{
"market_id": "0x2e94326a421c3f66c15a3b663c7b1ab7fb6a5298b3a57759ecf07f0036793fc9",
"orderbook": {
"buys": [
{
"price": "25100000000",
"quantity": "0.46",
"timestamp": 1701558751779
},
{
"price": "25000000000",
"quantity": "99.51",
"timestamp": 1702216325243
},
{
"price": "24192180000",
"quantity": "0.05",
"timestamp": 1681812143213
},
{
"price": "24000180000",
"quantity": "3",
"timestamp": 1681811751044
},
{
"price": "21295940000",
"quantity": "1",
"timestamp": 1681811119316
},
{
"price": "20160150000",
"quantity": "1",
"timestamp": 1681812143213
},
{
"price": "20000000000",
"quantity": "200",
"timestamp": 1699699685300
},
{
"price": "19894890000",
"quantity": "1",
"timestamp": 1681811751044
},
{
"price": "19764860000",
"quantity": "4",
"timestamp": 1681810803871
},
{
"price": "18900140000",
"quantity": "3",
"timestamp": 1681812143213
},
{
"price": "18439160000",
"quantity": "10",
"timestamp": 1681812143213
},
{
"price": "15000000000",
"quantity": "400",
"timestamp": 1699699705568
},
{
"price": "10000000000",
"quantity": "1000",
"timestamp": 1699699744160
}
],
"sells": [
{
"price": "50501180000",
"quantity": "4",
"timestamp": 1681811955314
},
{
"price": "50198770000",
"quantity": "2.48",
"timestamp": 1681811955314
}
],
"timestamp": -62135596800000
}
}
]
}
Parameter | Type | Description |
---|---|---|
orderbooks | SingleDerivativeLimitOrderbookV2 Array | List of derivative market orderbooks |
SingleDerivativeLimitOrderbookV2
Parameter | Type | Description |
---|---|---|
market_id | String | ID of the market that the orderbook belongs to |
orderbook | DerivativeLimitOrderbookV2 | Orderbook of the market |
DerivativeLimitOrderbookV2
Parameter | Type | Description |
---|---|---|
buys | PriceLevel Array | List of price levels for buys |
sells | PriceLevel Array | List of price levels for sells |
sequence | Integer | Sequence number of the orderbook; increments by 1 each update |
PriceLevel
Parameter | Type | Description |
---|---|---|
quantity | String | Quantity of the price level |
timestamp | Integer | Price level last updated timestamp in UNIX millis |
price | String | Price number of the price level |
StreamOrderbooksV2
Stream orderbook snapshot updates for one or more derivative markets
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from typing import Any, Dict
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def orderbook_event_processor(event: Dict[str, Any]):
print(event)
def stream_error_processor(exception: RpcError):
print(f"There was an error listening to derivative orderbook snapshots ({exception})")
def stream_closed_processor():
print("The derivative orderbook snapshots stream has been closed")
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
market_ids = ["0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"]
task = asyncio.get_event_loop().create_task(
client.listen_derivative_orderbook_snapshots(
market_ids=market_ids,
callback=orderbook_event_processor,
on_end_callback=stream_closed_processor,
on_status_callback=stream_error_processor,
)
)
await asyncio.sleep(delay=60)
task.cancel()
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
network := common.LoadNetwork("devnet-1", "")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketIds := []string{"0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"}
stream, err := exchangeClient.StreamDerivativeOrderbookV2(ctx, marketIds)
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
return
default:
res, err := stream.Recv()
if err != nil {
fmt.Println(err)
return
}
fmt.Println(res.MarketId, len(res.Orderbook.Sells), len(res.Orderbook.Buys))
}
}
}
Parameter | Type | Description | Required |
---|---|---|---|
market_ids | String Array | List of market IDs for orderbook streaming; empty means all spot markets | Yes |
callback | Function | Function receiving one parameter (a stream event JSON dictionary) to process each new event | Yes |
on_end_callback | Function | Function with the logic to execute when the stream connection is interrupted | No |
on_status_callback | Function | Function receiving one parameter (the exception) with the logic to execute when an exception happens | No |
Response Parameters
Streaming Response Example:
{
"orderbook":{
"buys":[
{
"price":"13400000",
"quantity":"683.3032",
"timestamp":"1702002966962"
},
...
],
"sells":[
{
"price":"18390200",
"quantity":"78815.8042",
"timestamp":"1702002966962"
},
...
],
"sequence":"1919121",
"timestamp":"1702003627697"
},
"operationType":"update",
"timestamp":"1702003629000",
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
}
Parameter | Type | Description |
---|---|---|
orderbook | DerivativeLimitOrderbookV2 | Orderbook of a Derivative Market |
operation_type | String | Order update type (Should be one of: ["insert", "replace", "update", "invalidate"]) |
timestamp | Integer | Operation timestamp in UNIX millis |
market_id | String | ID of the market the orderbook belongs to |
DerivativeLimitOrderbookV2
Parameter | Type | Description |
---|---|---|
buys | PriceLevel Array | List of price levels for buys |
sells | PriceLevel Array | List of price levels for sells |
sequence | Integer | Sequence number of the orderbook; increments by 1 each update |
PriceLevel
Parameter | Type | Description |
---|---|---|
price | String | Price number of the price level |
quantity | String | Quantity of the price level |
timestamp | Integer | Price level last updated timestamp in UNIX millis |
StreamOrderbookUpdate
Stream incremental orderbook updates for one or more derivative markets. This stream should be started prior to obtaining orderbook snapshots so that no incremental updates are omitted between obtaining a snapshot and starting the update stream.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from decimal import Decimal
from typing import Any, Dict
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
def stream_error_processor(exception: RpcError):
print(f"There was an error listening to derivative orderbook updates ({exception})")
def stream_closed_processor():
print("The derivative orderbook updates stream has been closed")
class PriceLevel:
def __init__(self, price: Decimal, quantity: Decimal, timestamp: int):
self.price = price
self.quantity = quantity
self.timestamp = timestamp
def __str__(self) -> str:
return "price: {} | quantity: {} | timestamp: {}".format(self.price, self.quantity, self.timestamp)
class Orderbook:
def __init__(self, market_id: str):
self.market_id = market_id
self.sequence = -1
self.levels = {"buys": {}, "sells": {}}
async def load_orderbook_snapshot(async_client: AsyncClient, orderbook: Orderbook):
# load the snapshot
res = await async_client.fetch_derivative_orderbooks_v2(market_ids=[orderbook.market_id])
for snapshot in res["orderbooks"]:
if snapshot["marketId"] != orderbook.market_id:
raise Exception("unexpected snapshot")
orderbook.sequence = int(snapshot["orderbook"]["sequence"])
for buy in snapshot["orderbook"]["buys"]:
orderbook.levels["buys"][buy["price"]] = PriceLevel(
price=Decimal(buy["price"]),
quantity=Decimal(buy["quantity"]),
timestamp=int(buy["timestamp"]),
)
for sell in snapshot["orderbook"]["sells"]:
orderbook.levels["sells"][sell["price"]] = PriceLevel(
price=Decimal(sell["price"]),
quantity=Decimal(sell["quantity"]),
timestamp=int(sell["timestamp"]),
)
break
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
async_client = AsyncClient(network)
market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
orderbook = Orderbook(market_id=market_id)
updates_queue = asyncio.Queue()
tasks = []
async def queue_event(event: Dict[str, Any]):
await updates_queue.put(event)
# start getting price levels updates
task = asyncio.get_event_loop().create_task(
async_client.listen_derivative_orderbook_updates(
market_ids=[market_id],
callback=queue_event,
on_end_callback=stream_closed_processor,
on_status_callback=stream_error_processor,
)
)
tasks.append(task)
# load the snapshot once we are already receiving updates, so we don't miss any
await load_orderbook_snapshot(async_client=async_client, orderbook=orderbook)
task = asyncio.get_event_loop().create_task(
apply_orderbook_update(orderbook=orderbook, updates_queue=updates_queue)
)
tasks.append(task)
await asyncio.sleep(delay=60)
for task in tasks:
task.cancel()
async def apply_orderbook_update(orderbook: Orderbook, updates_queue: asyncio.Queue):
while True:
updates = await updates_queue.get()
update = updates["orderbookLevelUpdates"]
# discard updates older than the snapshot
if int(update["sequence"]) <= orderbook.sequence:
return
print(" * * * * * * * * * * * * * * * * * * *")
# ensure we have not missed any update
if int(update["sequence"]) > (orderbook.sequence + 1):
raise Exception(
"missing orderbook update events from stream, must restart: {} vs {}".format(
update["sequence"], (orderbook.sequence + 1)
)
)
print("updating orderbook with updates at sequence {}".format(update["sequence"]))
# update orderbook
orderbook.sequence = int(update["sequence"])
for direction, levels in {"buys": update["buys"], "sells": update["sells"]}.items():
for level in levels:
if level["isActive"]:
# upsert level
orderbook.levels[direction][level["price"]] = PriceLevel(
price=Decimal(level["price"]), quantity=Decimal(level["quantity"]), timestamp=level["timestamp"]
)
else:
if level["price"] in orderbook.levels[direction]:
del orderbook.levels[direction][level["price"]]
# sort the level numerically
buys = sorted(orderbook.levels["buys"].values(), key=lambda x: x.price, reverse=True)
sells = sorted(orderbook.levels["sells"].values(), key=lambda x: x.price, reverse=True)
# lowest sell price should be higher than the highest buy price
if len(buys) > 0 and len(sells) > 0:
highest_buy = buys[0].price
lowest_sell = sells[-1].price
print("Max buy: {} - Min sell: {}".format(highest_buy, lowest_sell))
if highest_buy >= lowest_sell:
raise Exception("crossed orderbook, must restart")
# for the example, print the list of buys and sells orders.
print("sells")
for k in sells:
print(k)
print("=========")
print("buys")
for k in buys:
print(k)
print("====================================")
if __name__ == "__main__":
asyncio.run(main())
package main
import (
"context"
"fmt"
"sort"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
"github.com/shopspring/decimal"
)
type MapOrderbook struct {
Sequence uint64
Levels map[bool]map[string]*derivativeExchangePB.PriceLevel
}
func main() {
network := common.LoadNetwork("devnet-1", "")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
fmt.Println(err)
panic(err)
}
ctx := context.Background()
marketIds := []string{"0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"}
stream, err := exchangeClient.StreamDerivativeOrderbookUpdate(ctx, marketIds)
if err != nil {
fmt.Println(err)
panic(err)
}
updatesCh := make(chan *derivativeExchangePB.OrderbookLevelUpdates, 100000)
receiving := make(chan struct{})
var receivingClosed bool
// stream orderbook price levels
go func() {
defer close(updatesCh)
for {
select {
case <-ctx.Done():
return
default:
res, err := stream.Recv()
if err != nil {
fmt.Println(err)
return
}
u := res.OrderbookLevelUpdates
if !receivingClosed {
fmt.Println("receiving updates from stream")
close(receiving)
receivingClosed = true
}
updatesCh <- u
}
}
}()
// ensure we are receiving updates before getting orderbook
fmt.Println("waiting for streaming updates")
<-receiving
// prepare orderbooks map
orderbooks := map[string]*MapOrderbook{}
res, err := exchangeClient.GetDerivativeOrderbooksV2(ctx, marketIds)
if err != nil {
panic(err)
}
for _, ob := range res.Orderbooks {
// init inner maps not ready
_, ok := orderbooks[ob.MarketId]
if !ok {
orderbook := &MapOrderbook{
Sequence: ob.Orderbook.Sequence,
Levels: make(map[bool]map[string]*derivativeExchangePB.PriceLevel),
}
orderbook.Levels[true] = make(map[string]*derivativeExchangePB.PriceLevel)
orderbook.Levels[false] = make(map[string]*derivativeExchangePB.PriceLevel)
orderbooks[ob.MarketId] = orderbook
}
for _, level := range ob.Orderbook.Buys {
orderbooks[ob.MarketId].Levels[true][level.Price] = level
}
for _, level := range ob.Orderbook.Sells {
orderbooks[ob.MarketId].Levels[false][level.Price] = level
}
}
// continuously consume level updates and maintain orderbook
skippedPastEvents := false
for {
updates, ok := <-updatesCh
if !ok {
fmt.Println("updates channel closed, must restart")
return // closed
}
// validate orderbook
orderbook, ok := orderbooks[updates.MarketId]
if !ok {
panic("level update doesn't belong to any orderbooks")
}
// skip if update sequence <= orderbook sequence until it's ready to consume
if !skippedPastEvents {
if orderbook.Sequence >= updates.Sequence {
continue
}
skippedPastEvents = true
}
// panic if update sequence > orderbook sequence + 1
if updates.Sequence > orderbook.Sequence+1 {
fmt.Printf("skipping levels: update sequence %d vs orderbook sequence %d\n", updates.Sequence, orderbook.Sequence)
panic("missing orderbook update events from stream, must restart")
}
// update orderbook map
orderbook.Sequence = updates.Sequence
for isBuy, update := range map[bool][]*derivativeExchangePB.PriceLevelUpdate{
true: updates.Buys,
false: updates.Sells,
} {
for _, level := range update {
if level.IsActive {
// upsert
orderbook.Levels[isBuy][level.Price] = &derivativeExchangePB.PriceLevel{
Price: level.Price,
Quantity: level.Quantity,
Timestamp: level.Timestamp,
}
} else {
// remove inactive level
delete(orderbook.Levels[isBuy], level.Price)
}
}
}
// construct orderbook arrays
sells, buys := maintainOrderbook(orderbook.Levels)
fmt.Println("after", orderbook.Sequence, len(sells), len(buys))
if len(sells) > 0 && len(buys) > 0 {
// assert orderbook
topBuyPrice := decimal.RequireFromString(buys[0].Price)
lowestSellPrice := decimal.RequireFromString(sells[0].Price)
if topBuyPrice.GreaterThanOrEqual(lowestSellPrice) {
panic(fmt.Errorf("crossed orderbook, must restart: buy %s >= %s sell", topBuyPrice, lowestSellPrice))
}
}
res, _ = exchangeClient.GetDerivativeOrderbooksV2(ctx, marketIds)
fmt.Println("query", res.Orderbooks[0].Orderbook.Sequence, len(res.Orderbooks[0].Orderbook.Sells), len(res.Orderbooks[0].Orderbook.Buys))
// print orderbook
fmt.Println(" [SELLS] ========")
for _, s := range sells {
fmt.Println(s)
}
fmt.Println(" [BUYS] ========")
for _, b := range buys {
fmt.Println(b)
}
fmt.Println("=======================================================")
}
}
func maintainOrderbook(orderbook map[bool]map[string]*derivativeExchangePB.PriceLevel) (buys, sells []*derivativeExchangePB.PriceLevel) {
for _, v := range orderbook[false] {
sells = append(sells, v)
}
for _, v := range orderbook[true] {
buys = append(buys, v)
}
sort.Slice(sells, func(i, j int) bool {
return decimal.RequireFromString(sells[i].Price).LessThan(decimal.RequireFromString(sells[j].Price))
})
sort.Slice(buys, func(i, j int) bool {
return decimal.RequireFromString(buys[i].Price).GreaterThan(decimal.RequireFromString(buys[j].Price))
})
return sells, buys
}
Parameter | Type | Description | Required |
---|---|---|---|
market_ids | String Array | List of market IDs for orderbook streaming; empty means all derivative markets | Yes |
callback | Function | Function receiving one parameter (a stream event JSON dictionary) to process each new event | Yes |
on_end_callback | Function | Function with the logic to execute when the stream connection is interrupted | No |
on_status_callback | Function | Function receiving one parameter (the exception) with the logic to execute when an exception happens | No |
Response Parameters
Streaming Response Example:
* * * * * * * * * * * * * * * * * * *
updating orderbook with updates at sequence 589
Max buy: 10000000000 - Min sell: 50000000000
sells
price: 101000000000 | quantity: 0.0007 | timestamp: 1675291761230
price: 100000000000 | quantity: 0.0037 | timestamp: 1675291786816
price: 70000000000 | quantity: 0.0001 | timestamp: 1671787246665
price: 65111000000 | quantity: 0.0449 | timestamp: 1675291786816
price: 50000000000 | quantity: 0.1 | timestamp: 1676326399734
=========
buys
price: 10000000000 | quantity: 0.0004 | timestamp: 1676622014694
price: 5000000000 | quantity: 0.0097 | timestamp: 1676383776468
price: 1000000000 | quantity: 0.0013 | timestamp: 1676622213616
====================================
* * * * * * * * * * * * * * * * * * *
updating orderbook with updates at sequence 590
Max buy: 10000000000 - Min sell: 50000000000
sells
price: 101000000000 | quantity: 0.0007 | timestamp: 1675291761230
price: 100000000000 | quantity: 0.0037 | timestamp: 1675291786816
price: 70000000000 | quantity: 0.0001 | timestamp: 1671787246665
price: 65111000000 | quantity: 0.0449 | timestamp: 1675291786816
price: 50000000000 | quantity: 0.1 | timestamp: 1676326399734
=========
buys
price: 10000000000 | quantity: 0.0004 | timestamp: 1676622014694
price: 5000000000 | quantity: 0.0097 | timestamp: 1676383776468
price: 1000000000 | quantity: 0.0014 | timestamp: 1676622220695
====================================
Parameter | Type | Description |
---|---|---|
orderbook_level_updates | OrderbookLevelUpdates | Orderbook level updates of a derivative market |
operation_type | String | Order update type (Should be one of: ["insert", "replace", "update", "invalidate"]) |
timestamp | Integer | Operation timestamp in UNIX millis |
market_id | String | ID of the market the orderbook belongs to |
OrderbookLevelUpdates
Parameter | Type | Description |
---|---|---|
market_id | String | ID of the market the orderbook belongs to |
sequence | Integer | Orderbook update sequence number; increments by 1 each update |
buys | PriceLevelUpdate Array | List of buy level updates |
sells | PriceLevelUpdate Array | List of sell level updates |
updated_at | Integer | Timestamp of the updates in UNIX millis |
PriceLevelUpdate
Parameter | Type | Description |
---|---|---|
price | String | Price number of the price level |
quantity | String | Quantity of the price level |
is_active | Boolean | Price level status |
timestamp | Integer | Price level last updated timestamp in UNIX millis |
SubaccountOrdersList
Get the derivative orders of a specific subaccount.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
subaccount_id = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
skip = 1
limit = 2
pagination = PaginationOption(skip=skip, limit=limit)
orders = await client.fetch_subaccount_orders_list(
subaccount_id=subaccount_id, market_id=market_id, pagination=pagination
)
print(orders)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"
subaccountId := "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
skip := uint64(0)
limit := int32(10)
req := derivativeExchangePB.SubaccountOrdersListRequest{
MarketId: marketId,
SubaccountId: subaccountId,
Skip: skip,
Limit: limit,
}
res, err := exchangeClient.GetSubaccountDerivativeOrdersList(ctx, &req)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | Filter by subaccount ID | Yes |
market_id | String | Filter by market ID | No |
pagination | PaginationOption | Pagination configuration | No |
Response Parameters
Response Example:
{
"orders":[
{
"orderHash":"0x0a3db65baf5d253b10e6f42e606a95503f72e920176b94e31ee802acde53ec84",
"orderSide":"buy",
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"margin":"10107500",
"price":"10107500",
"quantity":"1",
"unfilledQuantity":"1",
"triggerPrice":"0",
"feeRecipient":"inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8",
"state":"booked",
"createdAt":"1699794939298",
"updatedAt":"1699794939298",
"orderType":"buy",
"txHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"isReduceOnly":false,
"orderNumber":"0",
"isConditional":false,
"triggerAt":"0",
"placedOrderHash":"",
"executionType":"",
"cid":""
}
],
"paging":{
"total":"2",
"from":2,
"to":2,
"countBySubaccount":"0",
"next":[
]
}
}
{
"orders": [
{
"order_hash": "0x8af0b619d31acda68d04b8a14e1488eee3c28792ded6fbb7393a489a4a8dbb58",
"order_side": "buy",
"market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"margin": "36000000000",
"price": "36000000000",
"quantity": "1",
"unfilled_quantity": "1",
"trigger_price": "0",
"fee_recipient": "inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8",
"state": "booked",
"created_at": 1652792829016,
"updated_at": 1652792829016
},
{
"order_hash": "0x457aadf92c40e5b2c4c7e6c3176872e72f36e11e7d4e718222b94a08a35ab071",
"order_side": "buy",
"market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"margin": "155000000",
"price": "31000000000",
"quantity": "0.01",
"unfilled_quantity": "0.01",
"trigger_price": "0",
"fee_recipient": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"state": "booked",
"created_at": 1652701438661,
"updated_at": 1652701438661
}
]
}
Parameter | Type | Description |
---|---|---|
orders | DerivativeLimitOrder Array | List of derivative orders |
paging | Paging | Pagination of results |
DerivativeLimitOrder
Parameter | Type | Description |
---|---|---|
order_hash | String | Hash of the order |
order_side | String | The side of the order (Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell"]) |
market_id | String | The market ID |
subaccount_id | String | The subaccount ID this order belongs to |
is_reduce_only | Boolean | True if the order is a reduce-only order |
margin | String | Margin of the order |
price | String | Price of the order |
quantity | String | Quantity of the order |
unfilled_quantity | String | The amount of the quantity remaining unfilled |
trigger_price | String | The price that triggers stop/take orders |
fee_recipient | String | Fee recipient address |
state | String | Order state (Should be one of: ["booked", "partial_filled", "filled", "canceled"]) |
created_at | Integer | Order created timestamp in UNIX millis |
updated_at | Integer | Order updated timestamp in UNIX millis |
order_number | Integer | Order number of subaccount |
order_type | String | Order type (Should be one of: ["buy", "sell", "stop_buy", "stop_sell", "take_buy", "take_sell", "buy_po", "sell_po"]) |
is_conditional | Boolean | If the order is conditional |
trigger_at | Integer | Trigger timestamp, only exists for conditional orders |
placed_order_hash | String | OrderHash of order that is triggered by this conditional order |
execution_type | String | Execution type of conditional order |
tx_hash | String | Transaction hash in which the order was created (not all orders have this value) |
cid | String | Identifier for the order specified by the user (up to 36 characters, like a UUID) |
SubaccountTradesList
Get the derivative trades for a specific subaccount.
IP rate limit group: indexer
*Trade execution types
"market"
for market orders"limitFill"
for a resting limit order getting filled by a market order"limitMatchRestingOrder"
for a resting limit order getting matched with another new limit order"limitMatchNewOrder"
for a new limit order getting matched immediately
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
subaccount_id = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
execution_type = "market"
direction = "sell"
skip = 10
limit = 2
pagination = PaginationOption(skip=skip, limit=limit)
trades = await client.fetch_derivative_subaccount_trades_list(
subaccount_id=subaccount_id,
market_id=market_id,
execution_type=execution_type,
direction=direction,
pagination=pagination,
)
print(trades)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"
subaccountId := "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
skip := uint64(0)
limit := int32(10)
req := derivativeExchangePB.SubaccountTradesListRequest{
MarketId: marketId,
SubaccountId: subaccountId,
Skip: skip,
Limit: limit,
}
res, err := exchangeClient.GetSubaccountDerivativeTradesList(ctx, &req)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | Subaccount ID of trader to get trades from | Yes |
market_id | String | Filter by Market ID | No |
execution_type | String | Filter by the *execution type of the trades (Should be one of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"]) | No |
direction | String | Filter by the direction of the trades (Should be one of: ["buy", "sell"]) | No |
pagination | PaginationOption | Pagination configuration | No |
Response Parameters
Response Example:
{
"trades":[
{
"orderHash":"0x19da3923ce9141a9cfdb644d4ac72e0650e0e938c244ca9a55d100011fedc25e",
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"tradeExecutionType":"market",
"positionDelta":{
"tradeDirection":"sell",
"executionPrice":"16945600",
"executionQuantity":"4",
"executionMargin":"67443600"
},
"payout":"0",
"fee":"47447.68",
"executedAt":"1699795360671",
"feeRecipient":"inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8",
"tradeId":"18321280_201_0",
"executionSide":"taker",
"isLiquidation":false,
"cid":""
},
{
"orderHash":"0xe9c8a307d353d09f11f616c9b3ee7be890512ceca9da7d8e3a62411607afc9af",
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"tradeExecutionType":"limitFill",
"positionDelta":{
"tradeDirection":"buy",
"executionPrice":"16945600",
"executionQuantity":"4",
"executionMargin":"67782400"
},
"payout":"68143885.714285714285714287",
"fee":"-4066.944",
"executedAt":"1699795360671",
"feeRecipient":"inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8",
"tradeId":"18321280_202_0",
"executionSide":"maker",
"isLiquidation":false,
"cid":""
}
]
}
{
"trades": [
{
"order_hash": "0xb131b0a095a8e72ad2fe0897001dbf6277f7ee9b8da868a9eedf9814e181da82",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
"trade_execution_type": "market",
"position_delta": {
"trade_direction": "buy",
"execution_price": "42710340000",
"execution_quantity": "0.15",
"execution_margin": "0"
},
"payout": "1105814219.16406340684465003",
"fee": "7687861.2",
"executed_at": 1652793510591,
"fee_recipient": "inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8"
},
{
"order_hash": "0xa049d9b5950b5a4a3a1560503ab22e191ad3f03d211629359cbdc844e8a05d91",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
"trade_execution_type": "market",
"position_delta": {
"trade_direction": "sell",
"execution_price": "38221371000",
"execution_quantity": "1",
"execution_margin": "37732000000"
},
"payout": "0",
"fee": "45865645.2",
"executed_at": 1651491831613,
"fee_recipient": "inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8"
}
]
}
Parameter | Type | Description |
---|---|---|
trades | DerivativeTrade Array | List of derivative market trades |
DerivativeTrade
Parameter | Type | Description |
---|---|---|
order_hash | String | The order hash |
subaccount_id | String | ID of subaccount that executed the trade |
market_id | String | The market ID |
trade_execution_type | String | *Execution type of the trade (Should be one of: ["market", "limitFill", "limitMatchRestingOrder", "limitMatchNewOrder"]) |
is_liquidation | Boolean | True if the trade is a liquidation |
position_delta | PositionDelta | Position delta from the trade |
payout | String | The payout associated with the trade |
fee | String | The fee associated with the trade |
executed_at | Integer | Timestamp of trade execution (on chain) in UNIX millis |
fee_recipient | String | The address that received 40% of the fees |
trade_id | String | Unique identifier to differentiate between trades |
execution_side | String | Execution side of trade (Should be one of: ["maker", "taker"]) |
cid | String | Custom client order id |
PositionDelta
Parameter | Type | Description |
---|---|---|
execution_price | String | Execution price of the trade |
execution_quantity | String | Execution quantity of the trade |
trade_direction | String | The direction the trade (Should be one of: ["buy", "sell"]) |
execution_margin | String | Execution margin of the trade |
FundingPayments
Get the funding payments for a subaccount.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
market_ids = ["0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"]
subaccount_id = "0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000"
skip = 0
limit = 3
end_time = 1676426400125
pagination = PaginationOption(skip=skip, limit=limit, end_time=end_time)
funding_payments = await client.fetch_funding_payments(
market_ids=market_ids, subaccount_id=subaccount_id, pagination=pagination
)
print(funding_payments)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"
subaccountId := "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
req := derivativeExchangePB.FundingPaymentsRequest{
MarketId: marketId,
SubaccountId: subaccountId,
}
res, err := exchangeClient.GetDerivativeFundingPayments(ctx, &req)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_ids | String Array | Filter by multiple market IDs | No |
subaccount_id | String | Subaccount ID of the trader we want to get the positions from | No |
pagination | PaginationOption | Pagination configuration | No |
Response Parameters
Response Example:
{
"payments":[
{
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccountId":"0x00509ed903475672121d6a1fb2c646eef4da6c44000000000000000000000000",
"amount":"1.628605",
"timestamp":"1702000801389"
},
{
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccountId":"0x0000040f1111c5c3d2037940658ee770bb37e0a2000000000000000000000000",
"amount":"-0.005036",
"timestamp":"1702000801389"
},
{
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"subaccountId":"0x0000007c60fab7a70c2ae0ebe437f3726b05e7eb000000000000000000000000",
"amount":"-0.006378",
"timestamp":"1702000801389"
}
],
"paging":{
"total":"1000",
"from":0,
"to":0,
"countBySubaccount":"0",
"next":[
]
}
}
{
"payments": [
{
"market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"amount": "9904406.085347",
"timestamp": 1652511601035
},
{
"market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"amount": "5811676.298013",
"timestamp": 1652508000824
},
{
"market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
"subaccount_id": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"amount": "6834858.744846",
"timestamp": 1652504401219
}
]
}
Parameter | Type | Description |
---|---|---|
payments | FundingPayment Array | List of funding payments |
paging | Paging | Pagination of results |
FundingPayment
Parameter | Type | Description |
---|---|---|
market_id | String | The market ID |
subaccount_id | String | The subaccount ID |
amount | String | The amount of the funding payment |
timestamp | Integer | Operation timestamp in UNIX millis |
Paging
Parameter | Type | Description |
---|---|---|
total | Integer | Total number of records available |
FundingRates
Get the historical funding rates for a specific market.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
skip = 0
limit = 3
end_time = 1675717201465
pagination = PaginationOption(skip=skip, limit=limit, end_time=end_time)
funding_rates = await client.fetch_funding_rates(market_id=market_id, pagination=pagination)
print(funding_rates)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
derivativeExchangePB "github.com/InjectiveLabs/sdk-go/exchange/derivative_exchange_rpc/pb"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"
req := derivativeExchangePB.FundingRatesRequest{
MarketId: marketId,
}
res, err := exchangeClient.GetDerivativeFundingRates(ctx, &req)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | ID of the market to get funding rates for | Yes |
pagination | PaginationOption | Pagination configuration | No |
Response Parameters
Response Example:
{
"fundingRates":[
{
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"rate":"0.000004",
"timestamp":"1702000801389"
},
{
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"rate":"0.000004",
"timestamp":"1701997200816"
},
{
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"rate":"0.000004",
"timestamp":"1701993600737"
}
],
"paging":{
"total":"5571",
"from":0,
"to":0,
"countBySubaccount":"0",
"next":[
]
}
}
{
"funding_rates": [
{
"market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
"rate": "0.000142",
"timestamp": 1652508000824
},
{
"market_id": "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
"rate": "0.000167",
"timestamp": 1652504401219
}
]
}
Parameter | Type | Description |
---|---|---|
funding_rates | FundingRate Array | List of funding rates |
paging | Paging | Pagination of results |
FundingRate
Parameter | Type | Description |
---|---|---|
market_id | String | The derivative market ID |
rate | String | Value of the funding rate |
timestamp | Integer | Timestamp of funding rate in UNIX millis |
Paging
Parameter | Type | Description |
---|---|---|
total | Integer | Total number of records available |
BinaryOptionsMarket
Get details of a single binary options market.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
market_id = "0x175513943b8677368d138e57bcd6bef53170a0da192e7eaa8c2cd4509b54f8db"
market = await client.fetch_binary_options_market(market_id=market_id)
print(market)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | ID of the binary options market to fetch | Yes |
Response Parameters
Response Example:
{
"market": {
"marketId": "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"marketStatus": "active",
"ticker": "INJ/USDT BO",
"oracleSymbol": "inj",
"oracleProvider": "BANDIBC",
"oracleType": "provider",
"oracleScaleFactor": 6,
"expirationTimestamp": "2343242423",
"settlementTimestamp": "2342342323",
"quoteDenom": "USDT",
"quoteTokenMeta": {
"name": "Tether",
"address": '0xdAC17F958D2ee523a2206206994597C13D831ec7',
"symbol": "USDT",
"logo": "https://static.alchemyapi.io/images/assets/7278.png",
"decimals": 18;
"updatedAt": "1650978921846"
},
"makerFeeRate": "0.001",
"takerFeeRate": "0.002",
"serviceProviderFee": "0.4",
"minPriceTickSize": "0.000000000000001",
"minQuantityTickSize": "1000000000000000",
"settlementPrice": "1",
"min_notional": "0"
}
}
Parameter | Type | Description |
---|---|---|
market | BinaryOptionsMarketInfo | Info about a particular binary options market |
BinaryOptionsMarketInfo
Parameter | Type | Description |
---|---|---|
market_id | String | The market ID |
market_status | String | The status of the market (Should be one of: ["active", "paused", "suspended", "demolished", "expired"]) |
ticker | String | The name of the binary options market |
oracle_symbol | String | Oracle symbol |
oracle_provider | String | Oracle provider |
oracle_type | String | Oracle Type |
oracle_scale_factor | Integer | Scaling multiple to scale oracle prices to the correct number of decimals |
expiration_timestamp | Integer | Defines the expiration time for the market in UNIX seconds |
settlement_timestamp | Integer | Defines the settlement time for the market in UNIX seconds |
quote_denom | String | Coin denom used for the quote asset |
quoteTokenMeta | TokenMeta | Token metadata for quote asset, only for Ethereum-based assets |
maker_fee_rate | String | Defines the fee percentage makers pay (or receive, if negative) in quote asset when trading |
taker_fee_rate | String | Defines the fee percentage takers pay (in quote asset) when trading |
service_provider_fee | String | Percentage of the transaction fee shared with the service provider |
min_price_tick_size | String | Defines the minimum required tick size for the order's price |
min_quantity_tick_size | String | Defines the minimum required tick size for the order's quantity |
settlement_price | String | Defines the settlement price of the market |
min_notional | String | Defines the minimum required notional for an order to be accepted |
TokenMeta
Parameter | Type | Description |
---|---|---|
address | String | Token's Ethereum contract address |
decimals | Integer | Token decimals |
logo | String | URL to the logo image |
name | String | Token full name |
symbol | String | Token symbol short name |
updatedAt | Integer | Token metadata fetched timestamp in UNIX millis |
BinaryOptionsMarkets
Get a list of binary options markets.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
market_status = "active"
quote_denom = "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7"
market = await client.fetch_binary_options_markets(market_status=market_status, quote_denom=quote_denom)
print(market)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
Parameter | Type | Description | Required |
---|---|---|---|
market_status | String | Filter by the status of the market (Should be one of: ["active", "paused", "suspended", "demolished", "expired"]) | No |
quote_denom | String | Filter by the Coin denomination of the quote currency | No |
pagination | PaginationOption | Pagination configuration | No |
Response Parameters
Response Example:
{
"markets":[
{
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"marketStatus":"active",
"ticker":"INJ/USDT BO",
"oracleSymbol":"inj",
"oracleProvider":"BANDIBC",
"oracleType":"provider",
"oracleScaleFactor":6,
"expirationTimestamp":"2343242423",
"settlementTimestamp":"2342342323",
"quoteDenom":"USDT",
"quoteTokenMeta":{
"name":"Tether",
"address":"0xdAC17F958D2ee523a2206206994597C13D831ec7",
"symbol":"USDT",
"logo":"https://static.alchemyapi.io/images/assets/7278.png",
"decimals":18;"updatedAt":"1650978921846"
},
"makerFeeRate":"0.001",
"takerFeeRate":"0.002",
"serviceProviderFee":"0.4",
"minPriceTickSize":"0.000000000000001",
"minQuantityTickSize":"1000000000000000",
"settlementPrice":"1",
"min_notional":"0",
}
],
"paging":{
"total":"5"
"from":"1"
"to":"3"
"countBySubaccount":"4"
}
}
Parameter | Type | Description |
---|---|---|
market | BinaryOptionsMarketInfo Array | List of binary options markets and associated info |
paging | Paging | Pagination of results |
BinaryOptionsMarketInfo
Parameter | Type | Description |
---|---|---|
market_id | String | The market ID |
market_status | String | The status of the market (Should be one of: ["active", "paused", "suspended", "demolished", "expired"]) |
ticker | String | The name of the binary options market |
oracle_symbol | String | Oracle symbol |
oracle_provider | String | Oracle provider |
oracle_type | String | Oracle Type |
oracle_scale_factor | Integer | Scaling multiple to scale oracle prices to the correct number of decimals |
expiration_timestamp | Integer | Defines the expiration time for the market in UNIX seconds |
settlement_timestamp | Integer | Defines the settlement time for the market in UNIX seconds |
quote_denom | String | Coin denom used for the quote asset |
quoteTokenMeta | TokenMeta | Token metadata for quote asset, only for Ethereum-based assets |
maker_fee_rate | String | Defines the fee percentage makers pay (or receive, if negative) in quote asset when trading |
taker_fee_rate | String | Defines the fee percentage takers pay (in quote asset) when trading |
service_provider_fee | String | Percentage of the transaction fee shared with the service provider |
min_price_tick_size | String | Defines the minimum required tick size for the order's price |
min_quantity_tick_size | String | Defines the minimum required tick size for the order's quantity |
settlement_price | String | Defines the settlement price of the market |
min_notional | String | Defines the minimum required notional for an order to be accepted |
TokenMeta
Parameter | Type | Description |
---|---|---|
address | String | Token's Ethereum contract address |
decimals | Integer | Token decimals |
logo | String | URL to the logo image |
name | String | Token full name |
symbol | String | Token symbol short name |
updatedAt | Integer | Token metadata fetched timestamp in UNIX millis |
Paging
Parameter | Type | Description |
---|---|---|
total | Integer | Total number of available records |
- InjectiveOracleRPC
InjectiveOracleRPC defines the gRPC API of the Exchange Oracle provider.
OracleList
Get a list of all oracles.
IP rate limit group: indexer
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
oracle_list = await client.fetch_oracle_list()
print(oracle_list)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
network := common.LoadNetwork("mainnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := exchangeClient.GetOracleList(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Response Parameters
Response Example:
{
"oracles":[
{
"symbol":"BTC",
"oracleType":"bandibc",
"price":"16835.93",
"baseSymbol":"",
"quoteSymbol":""
},
{
"symbol":"ETH",
"oracleType":"bandibc",
"price":"1251.335",
"baseSymbol":"",
"quoteSymbol":""
},
{
"symbol":"INJ",
"oracleType":"bandibc",
"price":"1.368087992",
"baseSymbol":"",
"quoteSymbol":""
},
{
"symbol":"USDT",
"oracleType":"bandibc",
"price":"0.999785552",
"baseSymbol":"",
"quoteSymbol":""
},
{
"symbol":"FRNT/USDT",
"baseSymbol":"FRNT",
"quoteSymbol":"USDT",
"oracleType":"pricefeed",
"price":"0.5"
},
{
"symbol":"0xb327d9cf0ecd793a175fa70ac8d2dc109d4462758e556962c4a87b02ec4f3f15",
"baseSymbol":"0xb327d9cf0ecd793a175fa70ac8d2dc109d4462758e556962c4a87b02ec4f3f15",
"quoteSymbol":"0xb327d9cf0ecd793a175fa70ac8d2dc109d4462758e556962c4a87b02ec4f3f15",
"oracleType":"pyth",
"price":"7.33638432"
},
{
"symbol":"0xecf553770d9b10965f8fb64771e93f5690a182edc32be4a3236e0caaa6e0581a",
"baseSymbol":"0xecf553770d9b10965f8fb64771e93f5690a182edc32be4a3236e0caaa6e0581a",
"quoteSymbol":"0xecf553770d9b10965f8fb64771e93f5690a182edc32be4a3236e0caaa6e0581a",
"oracleType":"pyth",
"price":"225.28704062"
}
]
}
{
"oracles": [
{
"symbol": "ANC",
"oracle_type": "bandibc",
"price": "2.212642692"
},
{
"symbol": "ATOM",
"oracle_type": "bandibc",
"price": "24.706861402"
},
{
"symbol": "ZRX",
"oracle_type": "coinbase",
"price": "0.9797"
}
]
}
Parameter | Type | Description |
---|---|---|
oracles | Oracle Array | List of oracles |
Oracle
Parameter | Type | Description |
---|---|---|
symbol | String | The symbol of the oracle asset |
base_symbol | String | Oracle base currency |
quote_symbol | String | Oracle quote currency. If no quote symbol is returned, USD is the default. |
oracle_base | String | Oracle base currency |
price | String | The price of the asset |
Price
Get the oracle price of an asset.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
market = (await client.all_derivative_markets())[
"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
]
base_symbol = market.oracle_base
quote_symbol = market.oracle_quote
oracle_type = market.oracle_type
oracle_prices = await client.fetch_oracle_price(
base_symbol=base_symbol,
quote_symbol=quote_symbol,
oracle_type=oracle_type,
)
print(oracle_prices)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := chainclient.NewMarketsAssistantInitializedFromChain(ctx, exchangeClient)
market := marketsAssistant.AllDerivativeMarkets()["0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"]
baseSymbol := market.OracleBase
quoteSymbol := market.OracleQuote
oracleType := market.OracleType
oracleScaleFactor := uint32(0)
res, err := exchangeClient.GetPrice(ctx, baseSymbol, quoteSymbol, oracleType, oracleScaleFactor)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
base_symbol | String | Oracle base currency | Yes |
quote_symbol | String | Oracle quote currency | Yes |
oracle_type | String | The oracle provider | Yes |
oracle_scale_factor | Integer | Oracle scale factor for the quote asset | Yes |
Response Parameters
Response Example:
{ "price": '1.368087992' }
{
"price": "40128736026.4094317665"
}
Parameter | Type | Description |
---|---|---|
price | String | The price of the oracle asset |
StreamPrices
Stream new price changes for a specified oracle. If no oracles are provided, all price changes are streamed.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from typing import Any, Dict
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def price_event_processor(event: Dict[str, Any]):
print(event)
def stream_error_processor(exception: RpcError):
print(f"There was an error listening to oracle prices updates ({exception})")
def stream_closed_processor():
print("The oracle prices updates stream has been closed")
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
market = (await client.all_derivative_markets())[
"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
]
base_symbol = market.oracle_base
quote_symbol = market.oracle_quote
oracle_type = market.oracle_type
task = asyncio.get_event_loop().create_task(
client.listen_oracle_prices_updates(
callback=price_event_processor,
on_end_callback=stream_closed_processor,
on_status_callback=stream_error_processor,
base_symbol=base_symbol,
quote_symbol=quote_symbol,
oracle_type=oracle_type,
)
)
await asyncio.sleep(delay=60)
task.cancel()
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := chainclient.NewMarketsAssistantInitializedFromChain(ctx, exchangeClient)
market := marketsAssistant.AllDerivativeMarkets()["0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"]
baseSymbol := market.OracleBase
quoteSymbol := market.OracleQuote
oracleType := market.OracleType
stream, err := exchangeClient.StreamPrices(ctx, baseSymbol, quoteSymbol, oracleType)
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
return
default:
res, err := stream.Recv()
if err != nil {
fmt.Println(err)
return
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
}
}
Parameter | Type | Description | Required |
---|---|---|---|
base_symbol | String | Oracle base currency | No |
quote_symbol | String | Oracle quote currency | No |
oracle_type | String | The oracle provider | No |
callback | Function | Function receiving one parameter (a stream event JSON dictionary) to process each new event | Yes |
on_end_callback | Function | Function with the logic to execute when the stream connection is interrupted | No |
on_status_callback | Function | Function receiving one parameter (the exception) with the logic to execute when an exception happens | No |
Response Parameters
Streaming Response Example:
{
"price":"1.3683814386627584",
"timestamp":"1702043286264"
}
{
"price": "40128.7360264094317665",
"timestamp": 1653038843915
}
Parameter | Type | Description |
---|---|---|
price | String | The price of the oracle asset |
timestamp | Integer | Operation timestamp in UNIX millis. |
- InjectiveInsuranceRPC
InjectiveInsuranceRPC defines the gRPC API of the Insurance Exchange provider.
InsuranceFunds
List all the insurance funds.
IP rate limit group: indexer
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
insurance_funds = await client.fetch_insurance_funds()
print(insurance_funds)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
insurancePB "github.com/InjectiveLabs/sdk-go/exchange/insurance_rpc/pb"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
req := insurancePB.FundsRequest{}
res, err := exchangeClient.GetInsuranceFunds(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Response Parameters
Response Example:
{
"funds":[
{
"marketTicker":"BTC/USDT PERP",
"marketId":"0x90e662193fa29a3a7e6c07be4407c94833e762d9ee82136a2cc712d6b87d7de3",
"depositDenom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"poolTokenDenom":"share1",
"redemptionNoticePeriodDuration":"1209600",
"balance":"3825059708",
"totalShare":"1000000000000000000",
"oracleBase":"BTC",
"oracleQuote":"USDT",
"oracleType":"bandibc",
"expiry":"0"
},
{
"marketTicker":"ETH/USDT PERP",
"marketId":"0xd5e4b12b19ecf176e4e14b42944731c27677819d2ed93be4104ad7025529c7ff",
"depositDenom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"poolTokenDenom":"share2",
"redemptionNoticePeriodDuration":"1209600",
"balance":"723501080000",
"totalShare":"7235010800000000000",
"oracleBase":"ETH",
"oracleQuote":"USDT",
"oracleType":"bandibc",
"expiry":"0"
}
]
}
{
"funds": [
{
"market_ticker": "OSMO/UST PERP",
"market_id": "0x8c7fd5e6a7f49d840512a43d95389a78e60ebaf0cde1af86b26a785eb23b3be5",
"deposit_denom": "ibc/B448C0CA358B958301D328CCDC5D5AD642FC30A6D3AE106FF721DB315F3DDE5C",
"pool_token_denom": "share19",
"redemption_notice_period_duration": 1209600,
"balance": "1000000",
"total_share": "1000000000000000000",
"oracle_base": "OSMO",
"oracle_quote": "UST",
"oracle_type": "bandibc"
}
]
}
Parameter | Type | Description |
---|---|---|
funds | InsuranceFund Array | List of all insurance funds, including default and all funded accounts |
InsuranceFund
Parameter | Type | Description |
---|---|---|
oracle_type | String | The oracle provider |
pool_token_denom | String | Denom of the pool token for the given fund |
total_share | String | Total number of shares in the fund |
balance | String | The total balance of the fund |
oracle_base | String | Oracle base currency |
market_id | String | ID of the derivative market |
market_ticker | String | Ticker of the derivative market |
oracle_quote | String | Oracle quote currency |
redemption_notice_period_duration | Integer | The minimum notice period duration that must pass after an underwriter sends a redemption request before underwriter can claim tokens |
deposit_denom | String | Denom of the coin used to underwrite the insurance fund |
expiry | Integer | Insurance fund expiry time, if any (usually 0 for perp markets) |
deposit_token_meta | TokenMeta | Token metadata for the deposit asset, only for Ethereum-based assets |
TokenMeta
Parameter | Type | Description |
---|---|---|
address | String | Token's Ethereum contract address |
decimals | Integer | Token decimals |
logo | String | URL to the logo image |
name | String | Token full name |
symbol | String | Token symbol short name |
updatedAt | Integer | Token metadata fetched timestamp in UNIX millis |
Redemptions
Get a list of redemptions. If no parameters are provided, redemptions for all pools and addresses will be returned.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
redeemer = "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku"
redemption_denom = "share4"
status = "disbursed"
insurance_redemptions = await client.fetch_redemptions(address=redeemer, denom=redemption_denom, status=status)
print(insurance_redemptions)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
insurancePB "github.com/InjectiveLabs/sdk-go/exchange/insurance_rpc/pb"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
req := insurancePB.RedemptionsRequest{}
res, err := exchangeClient.GetRedemptions(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
address | String | Filter by address of the redeemer | No |
denom | String | Filter by denom of the insurance pool token | No |
status | String | Filter by redemption status (Should be one of: ["disbursed", "pending"]) | No |
Response Parameters
Response Example:
{
"redemptionSchedules":[
{
"redemptionId":"1",
"status":"disbursed",
"redeemer":"inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"claimableRedemptionTime":"1674798129093000",
"redemptionAmount":"500000000000000000",
"redemptionDenom":"share4",
"requestedAt":"1673588529093000",
"disbursedAmount":"5000000",
"disbursedDenom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"disbursedAt":"1674798130965000"
},
{
"redemptionId":"2",
"status":"disbursed",
"redeemer":"inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"claimableRedemptionTime":"1674798342397000",
"redemptionAmount":"2000000000000000000",
"redemptionDenom":"share4",
"requestedAt":"1673588742397000",
"disbursedAmount":"20000000",
"disbursedDenom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"disbursedAt":"1674798343097000"
}
]
}
{
"redemption_schedules": [
{
"redemption_id": 1,
"status": "pending",
"redeemer": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"claimable_redemption_time": 1654247935923000,
"redemption_amount": "1000000000000000000",
"redemption_denom": "share19",
"requested_at": 1653038335923000
}
]
}
Parameter | Type | Description |
---|---|---|
redemption_schedules | RedemptionSchedule Array | List of redemption schedules |
RedemptionSchedule
Parameter | Type | Description |
---|---|---|
claimable_redemption_time | Integer | Claimable redemption time in seconds |
redeemer | String | Account address of the redeemer |
redemption_denom | String | Pool token denom being redeemed |
requested_at | Integer | Redemption request time in unix milliseconds |
status | String | Status of the redemption (Should be one of: ["disbursed", "pending"]) |
redemption_amount | String | Amount of pool tokens being redeemed |
redemption_id | Integer | ID of the redemption |
disbursed_amount | String | Amount of quote tokens disbursed |
disbursed_at | Integer | Redemption disbursement time in unix milliseconds |
disbursed_denom | String | Denom of the quote tokens disbursed |
- InjectiveAuctionRPC
InjectiveAuctionRPC defines the gRPC API of the Auction provider.
Auction
Get the details of a specific auction.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
bid_round = 31
auction = await client.fetch_auction(round=bid_round)
print(auction)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
round := int64(35)
res, err := exchangeClient.GetAuction(ctx, round)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
round | Integer | The auction round number, -1 for latest | Yes |
Response Parameters
Response Example:
{
"auction":{
"winner":"inj1uyk56r3xdcf60jwrmn7p9rgla9dc4gam56ajrq",
"basket":[
{
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"amount":"2322098"
}
],
"winningBidAmount":"2000000000000000000",
"round":"31",
"endTimestamp":"1676013187000",
"updatedAt":"1677075140258"
},
"bids":[
{
"bidder":"inj1pdxq82m20fzkjn2th2mm5jp7t5ex6j6klf9cs5",
"amount":"1000000000000000000",
"timestamp":"1675426622603"
},
{
"bidder":"inj1tu9xwxms5dvz3782tjal0fy5rput78p3k5sfv6",
"amount":"1010000000000000000",
"timestamp":"1675427580363"
},
{
"bidder":"inj1sdkt803zwq2tpej0k2a0z58hwyrnerzfsxj356",
"amount":"1030000000000000000",
"timestamp":"1675482275821"
},
{
"bidder":"inj1uyk56r3xdcf60jwrmn7p9rgla9dc4gam56ajrq",
"amount":"2000000000000000000",
"timestamp":"1675595586380"
}
]
}
{
"auction": {
"basket": [
{
"denom": "ibc/B448C0CA358B958301D328CCDC5D5AD642FC30A6D3AE106FF721DB315F3DDE5C",
"amount": "20541163349"
},
{
"denom": "peggy0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"amount": "3736040925000000"
},
{
"denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
"amount": "383119139180"
}
],
"round": 13534,
"end_timestamp": 1650635285000,
"updated_at": 1650978958302
}
}
Parameter | Type | Description |
---|---|---|
auction | Auction | Auction details |
bids | Bid Array | Auction's bids |
Auction
Parameter | Type | Description |
---|---|---|
winner | String | Account Injective address |
basket | Coin Array | Coins in the basket |
winning_bid_amount | String | Amount of the highest bid (in INJ) |
round | Integer | The auction round number |
end_timestamp | Integer | Auction end timestamp in UNIX milliseconds |
updated_at | Integer | The timestamp of the last update in UNIX milliseconds |
Bid
Parameter | Type | Description |
---|---|---|
bidder | String | Bidder account Injective address |
amount | String | The bid amount |
timestamp | Integer | Bid timestamp in UNIX millis |
Coin
Parameter | Type | Description |
---|---|---|
denom | String | Token denom |
amount | String | Token amount |
Auctions
Get the details of previous auctions.
IP rate limit group: indexer
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
auctions = await client.fetch_auctions()
print(auctions)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := exchangeClient.GetAuctions(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
No parameters
Response Parameters
Response Example:
{
"auctions":[
{
"basket":[
{
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"amount":"188940000"
}
],
"round":"1",
"endTimestamp":"1657869187000",
"updatedAt":"1658131202118",
"winner":"",
"winningBidAmount":""
},
{
"basket":[
{
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"amount":"219025410"
}
],
"round":"2",
"endTimestamp":"1658473987000",
"updatedAt":"1658134858904",
"winner":"",
"winningBidAmount":""
},
...
{
"winner":"inj1rk9fguz9zjwtqm3t6e9fzp7n9dd7jfhaw9dcc4",
"basket":[
{
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"amount":"1066722260002"
}
],
"winningBidAmount":"3007530000000000000000",
"round":"73",
"endTimestamp":"1701414787000",
"updatedAt":"1700809987278"
},
{
"basket":[
{
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"amount":"1137356301548"
},
{
"denom":"peggy0xf9152067989BDc8783fF586624124C05A529A5D1",
"amount":"128519416"
}
],
"round":"74",
"endTimestamp":"1702019587000",
"updatedAt":"1701414788278",
"winner":"",
"winningBidAmount":""
}
]
}
{
"auctions": [
{
"basket": [
{
"denom": "ibc/B448C0CA358B958301D328CCDC5D5AD642FC30A6D3AE106FF721DB315F3DDE5C",
"amount": "20541163349"
},
{
"denom": "peggy0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"amount": "3736040925000000"
},
{
"denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
"amount": "383119139180"
}
],
"round": 13435,
"end_timestamp": 1650575885000,
"updated_at": 1650978931464
},
{
"basket": [
{
"denom": "ibc/B448C0CA358B958301D328CCDC5D5AD642FC30A6D3AE106FF721DB315F3DDE5C",
"amount": "20541163349"
},
{
"denom": "peggy0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"amount": "3736040925000000"
},
{
"denom": "peggy0xdAC17F958D2ee523a2206206994597C13D831ec7",
"amount": "383119139180"
}
],
"round": 13436,
"end_timestamp": 1650576485000,
"updated_at": 1650978931847
}
]
}
Parameter | Type | Description |
---|---|---|
auctions | Auction Array | List of auctions |
Parameter | Type | Description |
---|---|---|
winner | String | Account Injective address |
basket | Coin Array | Coins in the basket |
winning_bid_amount | String | Amount of the highest bid (in INJ) |
round | Integer | The auction round number |
end_timestamp | Integer | Auction end timestamp in UNIX milliseconds |
updated_at | Integer | The timestamp of the last update in UNIX milliseconds |
Coin
Parameter | Type | Description |
---|---|---|
denom | String | Token denom |
amount | String | Token amount |
StreamBids
Stream live updates for auction bids.
IP rate limit group: indexer
Request Example:
import asyncio
from typing import Any, Dict
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def bid_event_processor(event: Dict[str, Any]):
print(event)
def stream_error_processor(exception: RpcError):
print(f"There was an error listening to bids updates ({exception})")
def stream_closed_processor():
print("The bids updates stream has been closed")
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
task = asyncio.get_event_loop().create_task(
client.listen_bids_updates(
callback=bid_event_processor,
on_end_callback=stream_closed_processor,
on_status_callback=stream_error_processor,
)
)
await asyncio.sleep(delay=60)
task.cancel()
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
stream, err := exchangeClient.StreamBids(ctx)
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
return
default:
res, err := stream.Recv()
if err != nil {
fmt.Println(err)
return
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
}
}
No parameters
Response Parameters
Response Example:
{
"bidder": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"bidAmount": "1000000000000000000",
"round": 19532,
"timestamp": 1654233511715
}
{
"bidder": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"bidAmount": "3000000000000000000",
"round": 19532,
"timestamp": 1654233530633
}
{
"bidder": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"bid_amount": "1000000000000000000",
"round": 17539,
"timestamp": 1653038036697
}{
"bidder": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"bid_amount": "2000000000000000000",
"round": 17539,
"timestamp": 1653038046359
}
Parameter | Type | Description |
---|---|---|
bidder | String | The bidder Injective address |
bid_amount | String | The bid amount (in INJ) |
round | Integer | The auction round number |
timestamp | Integer | Bid timestamp in UNIX milliseconds |
- InjectiveExplorerRPC
InjectiveExplorerRPC defines the gRPC API of the Explorer provider.
GetTxByHash
Get the details for a specific transaction.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.composer import Composer
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
composer = Composer(network=network.string())
tx_hash = "0F3EBEC1882E1EEAC5B7BDD836E976250F1CD072B79485877CEACCB92ACDDF52"
transaction_response = await client.fetch_tx_by_tx_hash(tx_hash=tx_hash)
print(transaction_response)
transaction_messages = composer.unpack_transaction_messages(transaction_data=transaction_response["data"])
print(transaction_messages)
first_message = transaction_messages[0]
print(first_message)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
explorerclient "github.com/InjectiveLabs/sdk-go/client/explorer"
)
func main() {
network := common.LoadNetwork("mainnet", "sentry")
explorerClient, err := explorerclient.NewExplorerClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
hash := "E5DCF04CC670A0567F58683409F7DAFC49754278DAAD507FE6EB40DFBFD71830"
res, err := explorerClient.GetTxByTxHash(ctx, hash)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
tx_hash | String | The transaction hash | Yes |
Response Parameters
Response Example:
{
"s":"ok",
"data":{
"blockNumber":"5024371",
"blockTimestamp":"2022-11-14 13:16:18.946 +0000 UTC",
"hash":"0x0f3ebec1882e1eeac5b7bdd836e976250f1cd072b79485877ceaccb92acddf52",
"data":"CoQBCjwvaW5qZWN0aXZlLmV4Y2hhbmdlLnYxYmV0YTEuTXNnQ3JlYXRlQmluYXJ5T3B0aW9uc0xpbWl0T3JkZXISRApCMHhmMWQ5MWZiNWI5MGRjYjU3MzczODVlNGIyZDUxMWY3YWZjMmE0MGRkMDNiZWRkMjdjYmM4Nzc3MmIwZjZlMzgy",
"gasWanted":"123364",
"gasUsed":"120511",
"gasFee":{
"amount":[
{
"denom":"inj",
"amount":"61682000000000"
}
],
"gasLimit":"123364",
"payer":"inj174mewc3hc96t7cngep545eju9ksdcfvx6d3jqq",
"granter":""
},
"txType":"injective",
"messages":"W3sidHlwZSI6Ii9pbmplY3RpdmUuZXhjaGFuZ2UudjFiZXRhMS5Nc2dDcmVhdGVCaW5hcnlPcHRpb25zTGltaXRPcmRlciIsInZhbHVlIjp7Im9yZGVyIjp7Im9yZGVyX3R5cGUiOiJTRUxMIiwibWFyZ2luIjoiOTk5OTk5NDAwMDAuMDAwMDAwMDAwMDAwMDAwMDAwIiwidHJpZ2dlcl9wcmljZSI6IjAuMDAwMDAwMDAwMDAwMDAwMDAwIiwibWFya2V0X2lkIjoiMHhjMGM5ODU4MWJhZjkzNzQwZTBkNTdhYWUyZTM2YWVjMjYyODUyMzQxYTY4MTgxYzkzODhjOWZiYmU3NTY3ZmYxIiwib3JkZXJfaW5mbyI6eyJmZWVfcmVjaXBpZW50IjoiaW5qMTc0bWV3YzNoYzk2dDdjbmdlcDU0NWVqdTlrc2RjZnZ4NmQzanFxIiwicHJpY2UiOiI1MzAwMDAuMDAwMDAwMDAwMDAwMDAwMDAwIiwicXVhbnRpdHkiOiIxMDAwMDAuMDAwMDAwMDAwMDAwMDAwMDAwIiwic3ViYWNjb3VudF9pZCI6IjB4ZjU3Nzk3NjIzN2MxNzRiZjYyNjhjODY5NWE2NjVjMmRhMGRjMjU4NjAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMSJ9fSwic2VuZGVyIjoiaW5qMTc0bWV3YzNoYzk2dDdjbmdlcDU0NWVqdTlrc2RjZnZ4NmQzanFxIn19XQ==",
"signatures":[
{
"pubkey":"injvalcons174mewc3hc96t7cngep545eju9ksdcfvxechtd9",
"address":"inj174mewc3hc96t7cngep545eju9ksdcfvx6d3jqq",
"sequence":"283962",
"signature":"pqXQlPRK8aMEZg2GyW0aotlYcz82iX+FDYNtgkq/9P1e59QYcdyGT/DNV4INLQVXkMwNHUcbKti0dEurzQT6Tw=="
}
],
"txNumber":"635946",
"blockUnixTimestamp":"1668431778946",
"logs":"W3siZXZlbnRzIjpbeyJhdHRyaWJ1dGVzIjpbeyJrZXkiOiJhY3Rpb24iLCJ2YWx1ZSI6Ii9pbmplY3RpdmUuZXhjaGFuZ2UudjFiZXRhMS5Nc2dDcmVhdGVCaW5hcnlPcHRpb25zTGltaXRPcmRlciJ9XSwidHlwZSI6Im1lc3NhZ2UifV19XQ==",
"id":"",
"code":0,
"info":"",
"codespace":"",
"events":[
],
"memo":"",
"errorLog":"",
"claimIds":[
]
},
"errmsg":""
}
[
{
"type":"/injective.exchange.v1beta1.MsgCreateBinaryOptionsLimitOrder",
"value":{
"sender":"inj174mewc3hc96t7cngep545eju9ksdcfvx6d3jqq",
"order":{
"marketId":"0xc0c98581baf93740e0d57aae2e36aec262852341a68181c9388c9fbbe7567ff1",
"orderInfo":{
"subaccountId":"0xf577976237c174bf6268c8695a665c2da0dc2586000000000000000000000001",
"feeRecipient":"inj174mewc3hc96t7cngep545eju9ksdcfvx6d3jqq",
"price":"530000.000000000000000000",
"quantity":"100000.000000000000000000",
"cid":""
},
"orderType":"SELL",
"margin":"99999940000.000000000000000000",
"triggerPrice":"0.000000000000000000"
}
}
}
]
{
"type":"/injective.exchange.v1beta1.MsgCreateBinaryOptionsLimitOrder",
"value":{
"sender":"inj174mewc3hc96t7cngep545eju9ksdcfvx6d3jqq",
"order":{
"marketId":"0xc0c98581baf93740e0d57aae2e36aec262852341a68181c9388c9fbbe7567ff1",
"orderInfo":{
"subaccountId":"0xf577976237c174bf6268c8695a665c2da0dc2586000000000000000000000001",
"feeRecipient":"inj174mewc3hc96t7cngep545eju9ksdcfvx6d3jqq",
"price":"530000.000000000000000000",
"quantity":"100000.000000000000000000",
"cid":""
},
"orderType":"SELL",
"margin":"99999940000.000000000000000000",
"triggerPrice":"0.000000000000000000"
}
}
}
{
"block_number": 4362066,
"block_timestamp": "2022-04-25 09:27:48.303 +0000 UTC",
"hash": "0x4893b36b1b2d7a0a94973cda1a6eaabf32c43e9c51b629bbdee6a46891c8a63c",
"data": "CnsKMy9pbmplY3RpdmUuZXhjaGFuZ2UudjFiZXRhMS5Nc2dDcmVhdGVTcG90TGltaXRPcmRlchJECkIweDIzNGU3YTAzMzlmOTUzZGEyNDMxMTFlOTlhNDg2NTZiOGI5ODM5NGY3ZGJiNTNkZTNlY2QwYWZmMGQ0NTI4ZmI=",
"gas_wanted": 121770,
"gas_used": 115359,
"gas_fee": {
"amount": [
{
"denom": "inj",
"amount": "60885000000000"
}
],
"gas_limit": 121770,
"payer": "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
},
"tx_type": "injective",
"messages": "[{\"type\":\"/injective.exchange.v1beta1.MsgCreateSpotLimitOrder\",\"value\":{\"order\":{\"market_id\":\"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0\",\"order_info\":{\"fee_recipient\":\"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r\",\"price\":\"0.000000000007523000\",\"quantity\":\"10000000000000000.000000000000000000\",\"subaccount_id\":\"0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000\"},\"order_type\":\"BUY_PO\",\"trigger_price\":\"0.000000000000000000\"},\"sender\":\"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r\"}}]",
"signatures": [
{
"pubkey": "injvalcons1hkhdaj2a2clmq5jq6mspsggqs32vynpkflpeux",
"address": "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"sequence": 1114,
"signature": "Ylj8HMq6g0iwSEtMVm8xKwP6m2p9w2H/K/AeKlIeBzltKONBP2oPkdWYcQKkGimbozlxIZm4AYi3x0JGwNps+g=="
}
]
}
Parameter | Type | Description |
---|---|---|
s | String | Status of the response |
errmsg | String | Error message, if any |
data | TxDetailData | Tx detail information |
TxDetailData
Parameter | Type | Description |
---|---|---|
block_number | Integer | The block at which the transaction was executed |
block_timestamp | String | The timestamp of the block (yyyy-MM-dd HH:mm:ss.SSS ZZZZ zzz, e.g. 2022-11-14 13:16:18.946 +0000 UTC) |
hash | String | The transaction hash |
data | bytes | The raw data in bytes |
gas_wanted | Integer | The gas wanted for this transaction |
gas_used | Integer | The gas used for this transaction |
gas_fee | GasFee | Gas fee information |
tx_type | String | The transaction type |
messages | String | The messages included in this transaction |
signatures | Signatures Array | List of signatures |
tx_number | Integer | Monotonic index of the tx in database |
block_unix_timestamp | Integer | The timestamp of the block in UNIX millis |
GasFee
Parameter | Type | Description |
---|---|---|
amount | CosmosCoin Array | List of coins with denom and amount |
gas_limit | Integer | The gas limit for the transaction |
payer | String | The Injective Chain address paying the gas fee |
granter | String | Address of granter of the tx |
CosmosCoin
Parameter | Type | Description |
---|---|---|
denom | String | Coin denom |
amount | String | Coin amount |
Signatures
Parameter | Type | Description |
---|---|---|
pubkey | String | The public key of the block proposer |
address | String | The transaction sender address |
sequence | Integer | The sequence number of the sender's address |
signature | String | The signature |
AccountTxs
Get the details for a specific transaction.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.composer import Composer
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
composer = Composer(network=network.string())
address = "inj1phd706jqzd9wznkk5hgsfkrc8jqxv0kmlj0kex"
message_type = "cosmos.bank.v1beta1.MsgSend"
limit = 2
pagination = PaginationOption(limit=limit)
transactions_response = await client.fetch_account_txs(
address=address,
message_type=message_type,
pagination=pagination,
)
print(transactions_response)
first_transaction_messages = composer.unpack_transaction_messages(transaction_data=transactions_response["data"][0])
print(first_transaction_messages)
first_message = first_transaction_messages[0]
print(first_message)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
explorerPB "github.com/InjectiveLabs/sdk-go/exchange/explorer_rpc/pb"
"github.com/InjectiveLabs/sdk-go/client/common"
explorerclient "github.com/InjectiveLabs/sdk-go/client/explorer"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
explorerClient, err := explorerclient.NewExplorerClient(network)
if err != nil {
panic(err)
}
address := "inj1akxycslq8cjt0uffw4rjmfm3echchptu52a2dq"
after := uint64(14112176)
req := explorerPB.GetAccountTxsRequest{
After: after,
Address: address,
}
ctx := context.Background()
res, err := explorerClient.GetAccountTxs(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
address | String | The Injective Chain address | Yes |
before | Integer | Filter transactions before a given block height | No |
after | Integer | Filter transactions after a given block height | No |
message_type | String | Filter by message type | No |
module | String | Filter by module | No |
from_number | Integer | Filter from transaction number | No |
to_number | Integer | Filter to transaction number | No |
status | String | Filter by transaction status | No |
pagination | PaginationOption | Pagination configuration | No |
Response Parameters
Response Example:
{
"paging":{
"total":"5000",
"from":221428,
"to":221429,
"countBySubaccount":"0",
"next":[
]
},
"data":[
{
"blockNumber":"18138926",
"blockTimestamp":"2023-11-07 23:19:55.371 +0000 UTC",
"hash":"0x3790ade2bea6c8605851ec89fa968adf2a2037a5ecac11ca95e99260508a3b7e",
"data":"EiYKJC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmRSZXNwb25zZQ==",
"gasWanted":"400000",
"gasUsed":"93696",
"gasFee":{
"amount":[
{
"denom":"inj",
"amount":"200000000000000"
}
],
"gasLimit":"400000",
"payer":"inj1phd706jqzd9wznkk5hgsfkrc8jqxv0kmlj0kex",
"granter":""
},
"txType":"injective-web3",
"messages":"W3sidHlwZSI6Ii9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQiLCJ2YWx1ZSI6eyJmcm9tX2FkZHJlc3MiOiJpbmoxcGhkNzA2anF6ZDl3em5razVoZ3Nma3JjOGpxeHYwa21sajBrZXgiLCJ0b19hZGRyZXNzIjoiaW5qMWQ2cXg4M25oeDNhM2d4N2U2NTR4NHN1OGh1cjVzODN1ODRoMnhjIiwiYW1vdW50IjpbeyJkZW5vbSI6ImZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3dldGgiLCJhbW91bnQiOiIxMDAwMDAwMDAwMDAwMDAwMDAifV19fV0=",
"signatures":[
{
"pubkey":"02c33c539e2aea9f97137e8168f6e22f57b829876823fa04b878a2b7c2010465d9",
"address":"inj1phd706jqzd9wznkk5hgsfkrc8jqxv0kmlj0kex",
"sequence":"223460",
"signature":"gFXPJ5QENzq9SUHshE8g++aRLIlRCRVcOsYq+EOr3T4QgAAs5bVHf8NhugBjJP9B+AfQjQNNneHXPF9dEp4Uehs="
}
],
"txNumber":"221429",
"blockUnixTimestamp":"1699399195371",
"logs":"W3sibXNnX2luZGV4IjowLCJldmVudHMiOlt7InR5cGUiOiJtZXNzYWdlIiwiYXR0cmlidXRlcyI6W3sia2V5IjoiYWN0aW9uIiwidmFsdWUiOiIvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kIn0seyJrZXkiOiJzZW5kZXIiLCJ2YWx1ZSI6ImluajFwaGQ3MDZqcXpkOXd6bmtrNWhnc2ZrcmM4anF4djBrbWxqMGtleCJ9LHsia2V5IjoibW9kdWxlIiwidmFsdWUiOiJiYW5rIn1dfSx7InR5cGUiOiJjb2luX3NwZW50IiwiYXR0cmlidXRlcyI6W3sia2V5Ijoic3BlbmRlciIsInZhbHVlIjoiaW5qMXBoZDcwNmpxemQ5d3pua2s1aGdzZmtyYzhqcXh2MGttbGowa2V4In0seyJrZXkiOiJhbW91bnQiLCJ2YWx1ZSI6IjEwMDAwMDAwMDAwMDAwMDAwMGZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3dldGgifV19LHsidHlwZSI6ImNvaW5fcmVjZWl2ZWQiLCJhdHRyaWJ1dGVzIjpbeyJrZXkiOiJyZWNlaXZlciIsInZhbHVlIjoiaW5qMWQ2cXg4M25oeDNhM2d4N2U2NTR4NHN1OGh1cjVzODN1ODRoMnhjIn0seyJrZXkiOiJhbW91bnQiLCJ2YWx1ZSI6IjEwMDAwMDAwMDAwMDAwMDAwMGZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3dldGgifV19LHsidHlwZSI6InRyYW5zZmVyIiwiYXR0cmlidXRlcyI6W3sia2V5IjoicmVjaXBpZW50IiwidmFsdWUiOiJpbmoxZDZxeDgzbmh4M2EzZ3g3ZTY1NHg0c3U4aHVyNXM4M3U4NGgyeGMifSx7ImtleSI6InNlbmRlciIsInZhbHVlIjoiaW5qMXBoZDcwNmpxemQ5d3pua2s1aGdzZmtyYzhqcXh2MGttbGowa2V4In0seyJrZXkiOiJhbW91bnQiLCJ2YWx1ZSI6IjEwMDAwMDAwMDAwMDAwMDAwMGZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3dldGgifV19LHsidHlwZSI6Im1lc3NhZ2UiLCJhdHRyaWJ1dGVzIjpbeyJrZXkiOiJzZW5kZXIiLCJ2YWx1ZSI6ImluajFwaGQ3MDZqcXpkOXd6bmtrNWhnc2ZrcmM4anF4djBrbWxqMGtleCJ9XX1dfV0=",
"id":"",
"code":0,
"info":"",
"codespace":"",
"events":[
],
"memo":"",
"errorLog":"",
"claimIds":[
]
},
{
"blockNumber":"18138918",
"blockTimestamp":"2023-11-07 23:19:38.275 +0000 UTC",
"hash":"0xd1f313b090b8698223086c081f71d9590716b83390ae18bc7e6b84b9eb7c7500",
"data":"EiYKJC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmRSZXNwb25zZQ==",
"gasWanted":"400000",
"gasUsed":"93775",
"gasFee":{
"amount":[
{
"denom":"inj",
"amount":"200000000000000"
}
],
"gasLimit":"400000",
"payer":"inj1phd706jqzd9wznkk5hgsfkrc8jqxv0kmlj0kex",
"granter":""
},
"txType":"injective-web3",
"messages":"W3sidHlwZSI6Ii9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQiLCJ2YWx1ZSI6eyJmcm9tX2FkZHJlc3MiOiJpbmoxcGhkNzA2anF6ZDl3em5razVoZ3Nma3JjOGpxeHYwa21sajBrZXgiLCJ0b19hZGRyZXNzIjoiaW5qMWQ2cXg4M25oeDNhM2d4N2U2NTR4NHN1OGh1cjVzODN1ODRoMnhjIiwiYW1vdW50IjpbeyJkZW5vbSI6ImZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2F0b20iLCJhbW91bnQiOiIxMDAwMDAwMDAwMDAwMDAwMDAwIn1dfX1d",
"signatures":[
{
"pubkey":"02c33c539e2aea9f97137e8168f6e22f57b829876823fa04b878a2b7c2010465d9",
"address":"inj1phd706jqzd9wznkk5hgsfkrc8jqxv0kmlj0kex",
"sequence":"223459",
"signature":"3Xunour/wXJksgpgkAXC55UwSbUYYt1jpA2zgsMNbHpGucHhSJad13i+HtCXUQY5APABaKKgRC+KAD9UvlPV0Rs="
}
],
"txNumber":"221428",
"blockUnixTimestamp":"1699399178275",
"logs":"W3sibXNnX2luZGV4IjowLCJldmVudHMiOlt7InR5cGUiOiJtZXNzYWdlIiwiYXR0cmlidXRlcyI6W3sia2V5IjoiYWN0aW9uIiwidmFsdWUiOiIvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kIn0seyJrZXkiOiJzZW5kZXIiLCJ2YWx1ZSI6ImluajFwaGQ3MDZqcXpkOXd6bmtrNWhnc2ZrcmM4anF4djBrbWxqMGtleCJ9LHsia2V5IjoibW9kdWxlIiwidmFsdWUiOiJiYW5rIn1dfSx7InR5cGUiOiJjb2luX3NwZW50IiwiYXR0cmlidXRlcyI6W3sia2V5Ijoic3BlbmRlciIsInZhbHVlIjoiaW5qMXBoZDcwNmpxemQ5d3pua2s1aGdzZmtyYzhqcXh2MGttbGowa2V4In0seyJrZXkiOiJhbW91bnQiLCJ2YWx1ZSI6IjEwMDAwMDAwMDAwMDAwMDAwMDBmYWN0b3J5L2luajE3dnl0ZHdxY3pxejcyajY1c2F1a3Bscmt0ZDRneWZtZTVhZ2Y2Yy9hdG9tIn1dfSx7InR5cGUiOiJjb2luX3JlY2VpdmVkIiwiYXR0cmlidXRlcyI6W3sia2V5IjoicmVjZWl2ZXIiLCJ2YWx1ZSI6ImluajFkNnF4ODNuaHgzYTNneDdlNjU0eDRzdThodXI1czgzdTg0aDJ4YyJ9LHsia2V5IjoiYW1vdW50IiwidmFsdWUiOiIxMDAwMDAwMDAwMDAwMDAwMDAwZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYXRvbSJ9XX0seyJ0eXBlIjoidHJhbnNmZXIiLCJhdHRyaWJ1dGVzIjpbeyJrZXkiOiJyZWNpcGllbnQiLCJ2YWx1ZSI6ImluajFkNnF4ODNuaHgzYTNneDdlNjU0eDRzdThodXI1czgzdTg0aDJ4YyJ9LHsia2V5Ijoic2VuZGVyIiwidmFsdWUiOiJpbmoxcGhkNzA2anF6ZDl3em5razVoZ3Nma3JjOGpxeHYwa21sajBrZXgifSx7ImtleSI6ImFtb3VudCIsInZhbHVlIjoiMTAwMDAwMDAwMDAwMDAwMDAwMGZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2F0b20ifV19LHsidHlwZSI6Im1lc3NhZ2UiLCJhdHRyaWJ1dGVzIjpbeyJrZXkiOiJzZW5kZXIiLCJ2YWx1ZSI6ImluajFwaGQ3MDZqcXpkOXd6bmtrNWhnc2ZrcmM4anF4djBrbWxqMGtleCJ9XX1dfV0=",
"id":"",
"code":0,
"info":"",
"codespace":"",
"events":[
],
"memo":"",
"errorLog":"",
"claimIds":[
]
}
]
}
[
{
"type":"/cosmos.bank.v1beta1.MsgSend",
"value":{
"fromAddress":"inj1phd706jqzd9wznkk5hgsfkrc8jqxv0kmlj0kex",
"toAddress":"inj1d6qx83nhx3a3gx7e654x4su8hur5s83u84h2xc",
"amount":[
{
"denom":"factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/weth",
"amount":"100000000000000000"
}
]
}
}
]
{
"type":"/cosmos.bank.v1beta1.MsgSend",
"value":{
"fromAddress":"inj1phd706jqzd9wznkk5hgsfkrc8jqxv0kmlj0kex",
"toAddress":"inj1d6qx83nhx3a3gx7e654x4su8hur5s83u84h2xc",
"amount":[
{
"denom":"factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/weth",
"amount":"100000000000000000"
}
]
}
}
{
"paging": {
"total": 100000,
"from": 5968747,
"to": 5968675
},
"data": [
{
"block_number": 5968747,
"block_timestamp": "2022-05-30 16:01:23.09 +0000 UTC",
"hash": "0x1d5e86c296c70aa2c97b0d31d83a84fb5b7296ccc2e9887868c17a0c1c7a458f",
"data": "CoEBCjkvaW5qZWN0aXZlLmV4Y2hhbmdlLnYxYmV0YTEuTXNnQ3JlYXRlRGVyaXZhdGl2ZUxpbWl0T3JkZXISRApCMHhmYjEwMDdmYTZiODlmOWQwZDgyODU1MWZmOThhZDRkOTgxYWZkNWQ2NzUzYzljMmU1YTNiNWZiZjYyM2YxMjgw",
"gas_wanted": 200000,
"gas_used": 122413,
"gas_fee": {
"amount": [
{
"denom": "inj",
"amount": "100000000000000"
}
],
"gas_limit": 200000,
"payer": "inj1q4j3pkrl8jy07uf84t3l2srt345fppeeyagscf"
},
"tx_type": "injective-web3",
"messages": "[{\"type\":\"/injective.exchange.v1beta1.MsgCreateDerivativeLimitOrder\",\"value\":{\"order\":{\"margin\":\"2000000.000000000000000000\",\"market_id\":\"0x9b9980167ecc3645ff1a5517886652d94a0825e54a77d2057cbbe3ebee015963\",\"order_info\":{\"fee_recipient\":\"inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8\",\"price\":\"1000000.000000000000000000\",\"quantity\":\"2.000000000000000000\",\"subaccount_id\":\"0x056510d87f3c88ff7127aae3f5406b8d68908739000000000000000000000000\"},\"order_type\":\"BUY\",\"trigger_price\":\"0.000000000000000000\"},\"sender\":\"inj1q4j3pkrl8jy07uf84t3l2srt345fppeeyagscf\"}}]",
"signatures": [
{
"pubkey": "injvalcons1q4j3pkrl8jy07uf84t3l2srt345fppee8gwf4v",
"address": "inj1q4j3pkrl8jy07uf84t3l2srt345fppeeyagscf",
"sequence": 2,
"signature": "kUm97awCT/j5RrHR3pIUvU/pOp+qYC2RnYm3tyPpdLdwFIXAFHCzX94htDc0LQxFKT7by08VCOyifTpZJJ9UaRs="
}
]
},
{
"block_number": 5968725,
"block_timestamp": "2022-05-30 16:00:40.386 +0000 UTC",
"hash": "0x8d8a0995b99c7641f8e0cc0c7e779325a4c4f5c3a738d1878ee2970c9f7e6f36",
"data": "CoEBCjkvaW5qZWN0aXZlLmV4Y2hhbmdlLnYxYmV0YTEuTXNnQ3JlYXRlRGVyaXZhdGl2ZUxpbWl0T3JkZXISRApCMHgxZDE4Yzc4ZGYwMTAzZTg4NGZmZjdiZGU5OGIyMjgxNDQ3NDFmODA5NWE2NDY2OGZlNzc2MTEwNmQ1NDNkYWI1",
"gas_wanted": 200000,
"gas_used": 122263,
"gas_fee": {
"amount": [
{
"denom": "inj",
"amount": "100000000000000"
}
],
"gas_limit": 200000,
"payer": "inj1q4j3pkrl8jy07uf84t3l2srt345fppeeyagscf"
},
"tx_type": "injective-web3",
"messages": "[{\"type\":\"/injective.exchange.v1beta1.MsgCreateDerivativeLimitOrder\",\"value\":{\"order\":{\"margin\":\"3000000.000000000000000000\",\"market_id\":\"0x9b9980167ecc3645ff1a5517886652d94a0825e54a77d2057cbbe3ebee015963\",\"order_info\":{\"fee_recipient\":\"inj1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8dkncm8\",\"price\":\"3000000.000000000000000000\",\"quantity\":\"1.000000000000000000\",\"subaccount_id\":\"0x056510d87f3c88ff7127aae3f5406b8d68908739000000000000000000000000\"},\"order_type\":\"BUY\",\"trigger_price\":\"0.000000000000000000\"},\"sender\":\"inj1q4j3pkrl8jy07uf84t3l2srt345fppeeyagscf\"}}]",
"signatures": [
{
"pubkey": "injvalcons1q4j3pkrl8jy07uf84t3l2srt345fppee8gwf4v",
"address": "inj1q4j3pkrl8jy07uf84t3l2srt345fppeeyagscf",
"sequence": 1,
"signature": "2iFB8tsuNHcSdvYufaL/8JJ0J0D6JOwbjzRJwJueHlpgkfRbWrXU3mBYqkP324U8scBs7jNP2Wa/90KUVi1BLRw="
}
]
},
{
"block_number": 5968715,
"block_timestamp": "2022-05-30 16:00:19.878 +0000 UTC",
"hash": "0x1d584573d1df6135bb13238943b805c30c075bca9068f6fe756ba433e36bb978",
"data": "CigKJi9pbmplY3RpdmUuZXhjaGFuZ2UudjFiZXRhMS5Nc2dEZXBvc2l0",
"gas_wanted": 200000,
"gas_used": 119686,
"gas_fee": {
"amount": [
{
"denom": "inj",
"amount": "100000000000000"
}
],
"gas_limit": 200000,
"payer": "inj1q4j3pkrl8jy07uf84t3l2srt345fppeeyagscf"
},
"tx_type": "injective-web3",
"messages": "[{\"type\":\"/injective.exchange.v1beta1.MsgDeposit\",\"value\":{\"amount\":{\"amount\":\"2000000000\",\"denom\":\"peggy0xdAC17F958D2ee523a2206206994597C13D831ec7\"},\"sender\":\"inj1q4j3pkrl8jy07uf84t3l2srt345fppeeyagscf\",\"subaccount_id\":\"0x056510d87f3c88ff7127aae3f5406b8d68908739000000000000000000000000\"}}]",
"signatures": [
{
"pubkey": "injvalcons1q4j3pkrl8jy07uf84t3l2srt345fppee8gwf4v",
"address": "inj1q4j3pkrl8jy07uf84t3l2srt345fppeeyagscf",
"signature": "QYBDtZd3hc5/blM3DEk2MU64DsexOVQxMhDjbC+m5W4S1VM18DxbqN4fWfyr756jQNDAiAxAugXIaBgyDykfkRw="
}
]
},
{
"block_number": 5968675,
"block_timestamp": "2022-05-30 15:59:00.706 +0000 UTC",
"hash": "0x5f420c9e78f81e33614943834ae3913273b09b3e4b9ae6661bca0b695d6d2fde",
"data": "Ch4KHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQKHgocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZA==",
"gas_wanted": 400000,
"gas_used": 126714,
"gas_fee": {
"amount": [
{
"denom": "inj",
"amount": "200000000000000"
}
],
"gas_limit": 400000,
"payer": "inj1pmau7c2ll72l0p58vdchzd39dvacfln50n7e9r"
},
"tx_type": "injective-web3",
"messages": "[{\"type\":\"/cosmos.bank.v1beta1.MsgSend\",\"value\":{\"amount\":[{\"amount\":\"10000000000000000000\",\"denom\":\"inj\"}],\"from_address\":\"inj1pmau7c2ll72l0p58vdchzd39dvacfln50n7e9r\",\"to_address\":\"inj1q4j3pkrl8jy07uf84t3l2srt345fppeeyagscf\"}},{\"type\":\"/cosmos.bank.v1beta1.MsgSend\",\"value\":{\"amount\":[{\"amount\":\"10000000000\",\"denom\":\"peggy0xdAC17F958D2ee523a2206206994597C13D831ec7\"}],\"from_address\":\"inj1pmau7c2ll72l0p58vdchzd39dvacfln50n7e9r\",\"to_address\":\"inj1q4j3pkrl8jy07uf84t3l2srt345fppeeyagscf\"}}]",
"signatures": [
{
"pubkey": "injvalcons1pmau7c2ll72l0p58vdchzd39dvacfln5vxcqgx",
"address": "inj1pmau7c2ll72l0p58vdchzd39dvacfln50n7e9r",
"sequence": 49,
"signature": "4gw7HI6wT/+yuCs0TeB+qh63puimW7MSGnVOmX/ywKggKIgjRIXAzJHlT8c7graA0dXXxJX1Hn5yjuMDsBHQChw="
}
]
}
]
}
Parameter | Type | Description |
---|---|---|
data | TxDetailData Array | TxDetailData object |
paging | Paging | Pagination of results |
Paging
Parameter | Type | Description |
---|---|---|
total | Integer | Total number of records available |
Data
Parameter | Type | Description |
---|---|---|
block_number | Integer | The block at which the transaction was executed |
block_timestamp | String | The timestamp of the block (yyyy-MM-dd HH:mm:ss.SSS ZZZZ zzz, e.g. 2022-11-14 13:16:18.946 +0000 UTC) |
hash | String | The transaction hash |
data | bytes | The raw data in bytes |
gas_wanted | Integer | The gas wanted for this transaction |
gas_used | Integer | The gas used for this transaction |
gas_fee | GasFee | GasFee object |
tx_type | String | The transaction type |
messages | String | The messages included in this transaction |
signatures | Signatures Array | List of signatures |
tx_number | Integer | Monotonic index of the tx in database |
block_unix_timestamp | Integer | The timestamp of the block in UNIX millis |
GasFee
Parameter | Type | Description |
---|---|---|
amount | CosmosCoin Array | List of coins with denom and amount |
gas_limit | Integer | The gas limit for the transaction |
payer | String | The Injective Chain address paying the gas fee |
granter | String | Address of granter of the tx |
CosmosCoin
Parameter | Type | Description |
---|---|---|
denom | String | Coin denom |
amount | String | Coin amount |
Signatures
Parameter | Type | Description |
---|---|---|
pubkey | String | The public key of the block proposer |
address | String | The transaction sender address |
sequence | Integer | The sequence number of the sender's address |
signature | String | The signature |
Blocks
Get data for blocks.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
limit = 2
pagination = PaginationOption(limit=limit)
blocks = await client.fetch_blocks(pagination=pagination)
print(blocks)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
explorerclient "github.com/InjectiveLabs/sdk-go/client/explorer"
)
func main() {
network := common.LoadNetwork("mainnet", "lb")
explorerClient, err := explorerclient.NewExplorerClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := explorerClient.GetBlocks(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
before | Integer | Filter transactions before a given block height | No |
after | Integer | Filter transactions after a given block height | No |
pagination | PaginationOption | Pagination configuration | No |
Response Parameters
Response Example:
{
"paging":{
"total":"19388338",
"from":19388337,
"to":19388338,
"countBySubaccount":"0",
"next":[
]
},
"data":[
{
"height":"19388338",
"proposer":"injvalcons1xml3ew93xmjtuf5zwpcl9jzznphte30hvdre9a",
"moniker":"InjectiveNode2",
"blockHash":"0x349ba348107a78e27a21aa86f7b6a7eab3cda33067872234eef5e6967fa0964c",
"parentHash":"0x3cdbdc7eee0767651785b5ac978af2fe2162caab8596da651c3c6403284902d7",
"timestamp":"2023-12-08 12:35:08.059 +0000 UTC",
"numPreCommits":"0",
"numTxs":"0",
"txs":[
]
},
{
"height":"19388337",
"proposer":"injvalcons1e0rj6fuy9yn5fwm9x4vw69xyuv7kzjm8rvw5r3",
"moniker":"InjectiveNode3",
"blockHash":"0x275aaa7206b6272b50a7d697d2ed432a2ab51aca3bcf3a0da3009521a29b1e07",
"parentHash":"0x44b8faece543cba46e1391e918b4f397e99461092c178149185275fff30d40bc",
"numTxs":"1",
"timestamp":"2023-12-08 12:35:06.749 +0000 UTC",
"numPreCommits":"0",
"txs":[
]
}
]
}
{
"paging": {
"from": 6002843,
"to": 6002844
},
"data": [
{
"height": 6002844,
"proposer": "injvalcons1qmrj7lnzraref92lzuhrv6m7sxey248fzxmfnf",
"moniker": "InjectiveNode3",
"block_hash": "0x138f577b66db53405fd2e642223d563558dd5af85cae0c7f6bb4d5fbfa53c310",
"parent_hash": "0x4012fcb077810c5e5d70ad2a1fbb5874dd66c194f243800db2c02b6ffcac0f4d",
"timestamp": "2022-05-31 10:27:13.325 +0000 UTC"
},
{
"height": 6002843,
"proposer": "injvalcons1uq5z4v9jhxr3a3k5k94nxa6l8hzzqs5fcstvaa",
"moniker": "InjectiveNode1",
"block_hash": "0x5b04a48a7d757585af7acd28f97cd75a377e6b5e8dd807322a2b74f467a292a6",
"parent_hash": "0x82e4d22cf5ed64aa9bce69bcb9933295d0730a3dbfafdc3f0970949934435d70",
"timestamp": "2022-05-31 10:27:11.395 +0000 UTC"
}
]
}
Parameter | Type | Description |
---|---|---|
data | BlockInfo | Block data |
paging | Paging | Pagination of results |
Paging
Parameter | Type | Description |
---|---|---|
total | Integer | Total number of records available |
BlockInfo
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
proposer | String | The block proposer |
moniker | String | The validator moniker |
block_hash | String | The hash of the block |
parent_hash | String | The parent hash of the block |
timestamp | String | The timestamp of the block (yyyy-MM-dd HH:mm:ss.SSS ZZZZ zzz, e.g. 2022-11-14 13:16:18.946 +0000 UTC) |
Block
Get detailed data for a single block.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
block_height = "5825046"
block = await client.fetch_block(block_id=block_height)
print(block)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
explorerclient "github.com/InjectiveLabs/sdk-go/client/explorer"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
explorerClient, err := explorerclient.NewExplorerClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
blockHeight := "5825046"
res, err := explorerClient.GetBlock(ctx, blockHeight)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
block_id | String | Block height | Yes |
Response Parameters
Response Example:
{
"s":"ok",
"data":{
"height":"5825046",
"proposer":"injvalcons1xml3ew93xmjtuf5zwpcl9jzznphte30hvdre9a",
"moniker":"InjectiveNode2",
"blockHash":"0x5982527aa7bc62d663256d505ab396e699954e46ada71a11de2a75f6e514d073",
"parentHash":"0x439caaef7ed0c6d9c2bdd7ffcd8c7303a4eb6a7c33d7db189f85f9b3a496fbc6",
"numTxs":"2",
"txs":[
{
"blockNumber":"5825046",
"blockTimestamp":"2022-12-11 22:06:49.182 +0000 UTC",
"hash":"0xbe8c8ca9a41196adf59b88fe9efd78e7532e04169152e779be3dc14ba7c360d9",
"messages":"bnVsbA==",
"txNumber":"994979",
"txMsgTypes":"WyIvaW5qZWN0aXZlLmV4Y2hhbmdlLnYxYmV0YTEuTXNnQ3JlYXRlQmluYXJ5T3B0aW9uc0xpbWl0T3JkZXIiXQ==",
"id":"",
"codespace":"",
"errorLog":"",
"code":0,
"logs":"",
"claimIds":[
]
},
{
"blockNumber":"5825046",
"blockTimestamp":"2022-12-11 22:06:49.182 +0000 UTC",
"hash":"0xe46713fbedc907278b6bd22165946d8673169c1a0360383e5e31abf219290c6a",
"messages":"bnVsbA==",
"txNumber":"994978",
"txMsgTypes":"WyIvaWJjLmNvcmUuY2xpZW50LnYxLk1zZ1VwZGF0ZUNsaWVudCIsIi9pYmMuY29yZS5jaGFubmVsLnYxLk1zZ1JlY3ZQYWNrZXQiXQ==",
"id":"",
"codespace":"",
"errorLog":"",
"code":0,
"logs":"",
"claimIds":[
]
}
],
"timestamp":"2022-12-11 22:06:49.182 +0000 UTC",
"numPreCommits":"0",
"totalTxs":"0"
},
"errmsg":""
}
{
"height": 5825046,
"proposer": "injvalcons1qmrj7lnzraref92lzuhrv6m7sxey248fzxmfnf",
"moniker": "InjectiveNode3",
"block_hash": "0x06453296122c4db605b68aac9e2848ea778b8fb2cdbdeb77281515722a1457cf",
"parent_hash": "0x14cba82aa61d5ee2ddcecf8e1f0a7f0286c5ac1fe3f8c3dafa1729121152793d",
"timestamp": "2022-05-27 10:21:51.168 +0000 UTC"
}
Parameter | Type | Description |
---|---|---|
s | String | Status of the response |
errmsg | String | Error message, if any |
data | BlockDetailInfo | Detailed info on the block |
BlockDetailInfo
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
proposer | String | The block proposer |
moniker | String | The block proposer's moniker |
block_hash | String | The hash of the block |
parent_hash | String | The parent hash of the block |
num_txs | Integer | Number of transactions in the block |
txs | TxData Array | List of transactions |
timestamp | String | The timestamp of the block (yyyy-MM-dd HH:mm:ss.SSS ZZZZ zzz, e.g. 2022-11-14 13:16:18.946 +0000 UTC) |
TxData
Parameter | Type | Description |
---|---|---|
block_number | String | The block number |
block_timestamp | String | The timestamp of the block (yyyy-MM-dd HH:mm:ss.SSS ZZZZ zzz, e.g. 2022-11-14 13:16:18.946 +0000 UTC) |
hash | String | Transaction hash |
messages | bytes | Messages byte data of the transaction |
tx_number | Integer | Transaction number |
Txs
Get the transactions.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
limit = 2
pagination = PaginationOption(limit=limit)
txs = await client.fetch_txs(pagination=pagination)
print(txs)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
explorerPB "github.com/InjectiveLabs/sdk-go/exchange/explorer_rpc/pb"
"github.com/InjectiveLabs/sdk-go/client/common"
explorerclient "github.com/InjectiveLabs/sdk-go/client/explorer"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
explorerClient, err := explorerclient.NewExplorerClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
before := uint64(7158400)
req := explorerPB.GetTxsRequest{
Before: before,
}
res, err := explorerClient.GetTxs(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
before | Integer | Filter transactions before a given block height | No |
after | Integer | Filter transactions after a given block height | No |
message_type | String | Filter by message type | No |
module | String | Filter by module | No |
from_number | Integer | Filter from transaction number | No |
to_number | Integer | Filter to transaction number | No |
status | String | Filter by transaction status | No |
pagination | PaginationOption | Pagination configuration | No |
Response Parameters
Response Example:
{
"paging":{
"total":"17748338",
"from":17748337,
"to":17748338,
"countBySubaccount":"0",
"next":[
]
},
"data":[
{
"blockNumber":"19388410",
"blockTimestamp":"2023-12-08 12:37:42.632 +0000 UTC",
"hash":"0xe9e2bd81acb24a6d04ab3eb50e5188858a63b8ec05b694c8731b2be8dc34b2d0",
"messages":"W3sidHlwZSI6Ii9jb3Ntd2FzbS53YXNtLnYxLk1zZ0V4ZWN1dGVDb250cmFjdCIsInZhbHVlIjp7InNlbmRlciI6ImluajFmdXc4OTMyNmQ0NzlrbjR2aGd6dnRhYWY3bTJoeDltZ25nZnFhMyIsImNvbnRyYWN0IjoiaW5qMTNnOWhwbnRjdHpnaGU5Mjkzc2xlMjhxNGU0ZTVtMGdzM2hwcDBoIiwibXNnIjp7InBvc3RfZGF0YSI6eyJkYXRhIjoiQ3RFREN2MEJDZ0lJQ3hETjhTd1lscHpNcXdZaUlPMFUvUTdFSFF1VEVUSHoxcmhtK0g3MUdJdkhsTXRwRUhOVlZQTDZHbUpHS2lCdDlWcmszekdtdGI0UVY2Z3hiVmlvOUJlT3VzenRmWUhtSUlOYzRxbTFyeklnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQTZJQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFpQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUZJVW44bHVMWERzaHVYd2FBcm8wcjllYUNocCtRSmFJQThyemk3UXFtRng1eW8rR2tOKzk3RjIvRUZZNEVRVGVGQjdYSTFKWTg0TFlndHZjSFJwWHpFM016Z3RNUkpDQ2tBVWNraTd4K2dBMUlyNlpINnNWTWRDSWVndU9Cdm5ONVFoZVpYbU9FTWhyZG54eHl6bXpLbks0cEVuRUFFSEgvMTVnZE1HQXRIZ3BiV0N3VGtYSG5vT0dvb0JDa01LRkovSmJpMXc3SWJsOEdnSzZOSy9YbWdvYWZrQ0VpSUtJTlprU09wWUtNbldoNytFamlQWDJ5eG52d1VIRVlrdXROSjV4bU5qTmRyVEdJQ0FtcWJxcitNQkVrTUtGSi9KYmkxdzdJYmw4R2dLNk5LL1htZ29hZmtDRWlJS0lOWmtTT3BZS01uV2g3K0VqaVBYMnl4bnZ3VUhFWWt1dE5KNXhtTmpOZHJUR0lDQW1xYnFyK01CRWdBPSJ9fSwiZnVuZHMiOltdfX1d",
"txNumber":"17748338",
"txMsgTypes":"WyIvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QiXQ==",
"logs":"W3sibXNnX2luZGV4IjowLCJldmVudHMiOlt7InR5cGUiOiJtZXNzYWdlIiwiYXR0cmlidXRlcyI6W3sia2V5IjoiYWN0aW9uIiwidmFsdWUiOiIvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QifSx7ImtleSI6InNlbmRlciIsInZhbHVlIjoiaW5qMWZ1dzg5MzI2ZDQ3OWtuNHZoZ3p2dGFhZjdtMmh4OW1nbmdmcWEzIn0seyJrZXkiOiJtb2R1bGUiLCJ2YWx1ZSI6Indhc20ifV19LHsidHlwZSI6ImV4ZWN1dGUiLCJhdHRyaWJ1dGVzIjpbeyJrZXkiOiJfY29udHJhY3RfYWRkcmVzcyIsInZhbHVlIjoiaW5qMTNnOWhwbnRjdHpnaGU5Mjkzc2xlMjhxNGU0ZTVtMGdzM2hwcDBoIn1dfSx7InR5cGUiOiJ3YXNtIiwiYXR0cmlidXRlcyI6W3sia2V5IjoiX2NvbnRyYWN0X2FkZHJlc3MiLCJ2YWx1ZSI6ImluajEzZzlocG50Y3R6Z2hlOTI5M3NsZTI4cTRlNGU1bTBnczNocHAwaCJ9LHsia2V5IjoibWV0aG9kIiwidmFsdWUiOiJwb3N0ZGF0YSJ9XX1dfV0=",
"id":"",
"codespace":"",
"errorLog":"",
"code":0,
"claimIds":[
]
},
{
"blockNumber":"19388408",
"blockTimestamp":"2023-12-08 12:37:38.713 +0000 UTC",
"hash":"0xd9197814915db8cfcc38743d1680764530da238304899723f5b37b49500304d3",
"messages":"W3sidHlwZSI6Ii9jb3Ntd2FzbS53YXNtLnYxLk1zZ0V4ZWN1dGVDb250cmFjdCIsInZhbHVlIjp7InNlbmRlciI6ImluajFkZWVqYzY2dmhjcWVuNXFqdTJlZGxjOHdqczN4OTJzaHYza2F0cyIsImNvbnRyYWN0IjoiaW5qMThybGZscDM3MzVoMjVqbWp4OTdkMjJjNzJzeGsyNjBhbWRqeGx1IiwibXNnIjp7InVwZGF0ZV9wcmljZV9mZWVkcyI6eyJkYXRhIjpbIlVFNUJWUUVBQUFBQW9BRUFBQUFBQVFDK3FzR3JqcjdzeXVmS3l3VDN6dllvcXRyVzc3cXZlSFFIbDl3V3hhU3RMRVJaS1liS2Q2UE45clNReW5OU1ZkbGVIdkRJaWh2d2lrYnhCY2o2bkxSb0FXVnpEaEVBQUFBQUFCcmhBZnJ0ckZoUjR5dWJJN1g1UVJxTUs2eEtyajdVM1h1QkhkR25McVNxY1FBQUFBQUNhNVRJQVVGVlYxWUFBQUFBQUFiYjlqUUFBQ2NRNmRhVWViTjRsM25SWmtyZlZVayt6Z0poQ3VrT0FGVUEvbVVQQTJmVXArK1lGYVdUNmhYVFpaUHdaRHFxOEJTYnNFdm1lcmhSM3MwQUFBQUJ0TXJCaHdBQUFBQUFNdFZtLy8vLytBQUFBQUJsY3c0UkFBQUFBR1Z6RGc4QUFBQUJzU2Q5cUFBQUFBQUFPNEpiQ21Gbzh0UGlWbTl5WkFkVUxNUUROZzRVNmV1ZXhHMklqdVlia1VTdlo2ZWhIbStQTlpXNXIxSTZFeHFURGFZNWJTREtpSWYyZHZBRWN6NXAwcEdTTEJzQm0yRHhZZVFKTkRXaTZ5U3VFTXp1MGViL0M4SHR6NjJwbkZDd00vUEFzcVFXM3UxRC9GUDAwcDBMRldKL1FSQjRMQ1pnK09Bb09DM2FTODFBUElqajU0TkpEdm9aMC9vTU5ucTlhdE5qV2dQWUhvaERDNUpZaWtzM3ZCM1MrMzNwK0daM1VVcC8yK3pKTjVCUVBTQTJQbFpCZXpuMEFseG8yM1IvcjQ3bCt4czJ2YnNXajFxa0FGVUFIOEdJWVNNaWtDSVVZU0lMMU9LczBkemZ2SW5JUUpMSlBCaTl4M1ZzRllnQUFBQUFCZllLTndBQUFBQUFBRlloLy8vLytBQUFBQUJsY3c0UkFBQUFBR1Z6RGc4QUFBQUFCZllYY3dBQUFBQUFBR05wQ24wRnd6c1lTem54aEtYc2JhQWhDd2phYTVhTHU4bVhKL2xtQWlJV050d2lnc1BWd09KN0hKb0VZWkpXb0ZxTTVoRVZvdmtDWWF5NG5jMFFqK2N3WkJHWmdGbmlYTGdEVjU3dEZHeE0rWWFMTkE5YWpTV2lLb0sxemVxUjN2TGpLMkIxSVgweHYwQVVTL0FVWURIYmREcDFYRzJyM1dveExzZlV4QVgrMnJ0UEVYN0syWEZkNFlHSUpvc21laXIxSThBZ3owUlp6c2JMZlo1ZHdwWWs1bStrRUVFN0l3SHllYXI0UTlub2orLzI0OVVBZmpuMEFseG8yM1IvcjQ3bCt4czJ2YnNXajFxa0FGVUErY0FYSzZFTitrMFpDSTJVOWI5aDA3Vk5XOWRJT2pJcW1DNFRjKzZPb3hzQUFBUDVhSU9ib1FBQUFBQmF1WVlwLy8vLytBQUFBQUJsY3c0UkFBQUFBR1Z6RGc4QUFBUDBZWjdLWUFBQUFBQlBSM1dlQ2dOdE94cWZPdFZOTXNwdm1NT0NZclB4MnBOSkpxVVJvdVYzalZKejdjNXY3QktTeVNxVWJtOVVUUkFOcHkrc05abnE1NVprUUVuaExTU20wckZIeXNZV0s4Rm13NVN4TFJjQUlUNXRQTnpaam5wWGR1aDJPK20vVmcwdG5RL1kxTXJ4N29sRC9GUDAwcDBMRldKL1FSQjRMQ1pnK09Bb09DM2FTODFBUElqajU0TkpEdm9aMC9vTU5ucTlhdE5qV2dQWUhvaERDNUpZaWtzM3ZCM1MrMzNwK0daM1VVcC8yK3pKTjVCUVBTQTJQbFpCZXpuMEFseG8yM1IvcjQ3bCt4czJ2YnNXajFxa0FGVUFOL1FOS0pnVm5vOHVVcms4dDQ5SHpEZ3BveDVTV3JsMXhKekZ4ZGtYWTNnQUFBQUFCdm5jR0FBQUFBQUFBT0lvLy8vLytBQUFBQUJsY3c0UkFBQUFBR1Z6RGc4QUFBQUFCdkZFWlFBQUFBQUFBUGxKQ21GaEpCK0ZMMlJka3Q0RzVNd1VZNTE4anlMQ0xEMUZTaGNUSnV0V1hSUjEwaEJFVit1N0RkNThUV1FncnlPQXpsMnQyaE1IM1dpbXFNNkZGOVkwbytGblh1K3dCcnE5ZXhWelpIRU1UcTJvM3doZjJ5bVY0aVZhbDhnNzI5MjdONGlRQkl4QnRJVDhuVkRxUERuQ3RJcVVlUEY1alpydTBPM2RZeVpxUjQwT2RGK3VtVkplUnNnZ0FEV0FlaXIxSThBZ3owUlp6c2JMZlo1ZHdwWWs1bStrRUVFN0l3SHllYXI0UTlub2orLzI0OVVBZmpuMEFseG8yM1IvcjQ3bCt4czJ2YnNXajFxa0FGVUFNS0dSV1BXbFRBcmZqN2RXQmljMFB5S2h2SVVyaWRWcjRhek54ZHY1YlE0QUFBQUFBQjcwMkFBQUFBQUFBQUJ6Ly8vLy9RQUFBQUJsY3c0UkFBQUFBR1Z6RGc4QUFBQUFBQjczV0FBQUFBQUFBQUI5Q3ZNTTI2VVlPVlBBRVBnZmMwOU0zYkthcklVdEhqVDhidU5HQms4MTQrQ1VQOGZMTjR3Vkd5dkJETzQzNC9GbnF3MENqNUhTZisrbmdhSTFLUlUvMVZaSnN5MFE2TER0eFpuRnpMK1NqVXlyd3RmV3J1V1ZkQnJBVDFFMDFYdmtnL094QlpKQnRJVDhuVkRxUERuQ3RJcVVlUEY1alpydTBPM2RZeVpxUjQwT2RGK3VtVkplUnNnZ0FEV0FlaXIxSThBZ3owUlp6c2JMZlo1ZHdwWWs1bStrRUVFN0l3SHllYXI0UTlub2orLzI0OVVBZmpuMEFseG8yM1IvcjQ3bCt4czJ2YnNXajFxa0FGVUF3YkVuYWZaak41alVXdC9XSy94d0VVZzVJeTRwU2JBZnM5UDVKOUpnWVZRQUFBQUFBQUdsT3dBQUFBQUFBQUFLLy8vLyt3QUFBQUJsY3c0UkFBQUFBR1Z6RGc4QUFBQUFBQUdsTVFBQUFBQUFBQUFLQ2lnRHd3eUo5TDRjaFNBSzZnRVZsckxkaUVQdmJhQ1owd09WUGpHNEpSeEpwMHBBY1BnbFo3YnVFQXdDd2tvN1JDVUxHRElPQ0k5aWg4ZlA4eTNzcnI0ekp6UkYycmI0MXZlM3pYeU9iRXJNVEZ1UGkvRmhtR3M5Mlh5NEV4eXZleVRrY056Mnc3OHFRMTIrckN6R0F3ejdwTjNNbnJyUVRQR0tGUnVjUU5FekF1WjBOaXVaUjd4dk8xdC9hdE5qV2dQWUhvaERDNUpZaWtzM3ZCM1MrMzNwK0daM1VVcC8yK3pKTjVCUVBTQTJQbFpCZXpuMEFseG8yM1IvcjQ3bCt4czJ2YnNXajFxa0FGVUFNaHVrMWdqNmRicDIxdGM5cW5GYXZMM3JuYm9DSlg4Rm9iV1JlTFNmV1pzQUFBQUFBQ1JIWndBQUFBQUFBQUp4Ly8vLyt3QUFBQUJsY3c0UkFBQUFBR1Z6RGc4QUFBQUFBQ1JTZndBQUFBQUFBQUgwQ3VXM0tTaW95T0dIQ0FCK3Nsc2ZKWldESWVtN0pmNlVueElLd3hRMWkrNzUwQ1lPTFFpbEJ5SnRHR3VqVGllbzlubXo4dVJsSkx1b3hEVm11eFUvMVZaSnN5MFE2TER0eFpuRnpMK1NqVXlyd3RmV3J1V1ZkQnJBVDFFMDFYdmtnL094QlpKQnRJVDhuVkRxUERuQ3RJcVVlUEY1alpydTBPM2RZeVpxUjQwT2RGK3VtVkplUnNnZ0FEV0FlaXIxSThBZ3owUlp6c2JMZlo1ZHdwWWs1bStrRUVFN0l3SHllYXI0UTlub2orLzI0OVVBZmpuMEFseG8yM1IvcjQ3bCt4czJ2YnNXajFxa0FGVUFJS2s0OVV0bzhmTHZHT29ES1BiZEIwZjQ2aEZJYlNLd0llZzZrQXZvbDNZQUFBQUFBQUl6blFBQUFBQUFBQUFJLy8vLy9RQUFBQUJsY3c0UkFBQUFBR1Z6RGc4QUFBQUFBQUl6L1FBQUFBQUFBQUFJQ2hwOEhiS1JRdnRrWUJKdzMxR1lPdjJPTUFURXU4bVhKL2xtQWlJV050d2lnc1BWd09KN0hKb0VZWkpXb0ZxTTVoRVZvdmtDWWF5NG5jMFFqK2N3WkJHWmdGbmlYTGdEVjU3dEZHeE0rWWFMTkE5YWpTV2lLb0sxemVxUjN2TGpLMkIxSVgweHYwQVVTL0FVWURIYmREcDFYRzJyM1dveExzZlV4QVgrMnJ0UEVYN0syWEZkNFlHSUpvc21laXIxSThBZ3owUlp6c2JMZlo1ZHdwWWs1bStrRUVFN0l3SHllYXI0UTlub2orLzI0OVVBZmpuMEFseG8yM1IvcjQ3bCt4czJ2YnNXajFxa0FGVUF2TDNDZFZ2WFNpQmwrZE1vUEN1S3k5aVk1SE85dVFwblpMUGIxR2ZGYnMwQUFBQUFBQUhyUUFBQUFBQUFBQUFLLy8vLyt3QUFBQUJsY3c0UkFBQUFBR1Z6RGc4QUFBQUFBQUhyVFFBQUFBQUFBQUFKQ3BySEprTUViNFk1R1EwQ0R5bktnZkxyODBYNzRXOGM3dG1FWGE3RG43WHk0SjlSeVZiYngyWElBQWRBSzRnTVlCTWNLVTNmZ0VUdEE5L0U1S1kvTWRLVERFNVhvS25ULzdaYkxZUGdxd3F1aEQ4WFNRVEVxZU1JYm9hUWRkblVMTVkzd2hiMnc3OHFRMTIrckN6R0F3ejdwTjNNbnJyUVRQR0tGUnVjUU5FekF1WjBOaXVaUjd4dk8xdC9hdE5qV2dQWUhvaERDNUpZaWtzM3ZCM1MrMzNwK0daM1VVcC8yK3pKTjVCUVBTQTJQbFpCZXpuMEFseG8yM1IvcjQ3bCt4czJ2YnNXajFxa0FGVUF5b0M2YmNNdUNOQnZHcWlHQVI3dEhYZkhlK25yZGh6QkRYSzMwS0w5VjZZQUFBQTNFZDZLc2dBQUFBQUZlOGp5Ly8vLytBQUFBQUJsY3c0UkFBQUFBR1Z6RGc4QUFBQTNBN29GWUFBQUFBQUZjbnJyQ2p3UmZsTzI3N1JXaTkxaXBEMEhIbWFzL3M0WWVEME5YNlo3Qnk3cDVhV1UzOC84ZEFsNVZFTUVsM2djeC96Mjl2ditDL2tjd05zSnlYTVFHY1Z5Z1JvOUdRcXp0cFl6MmxpRVBzcFhOR0F3dkhhekRvVkJIWHhMQ2dBT1VrWTVwUGYvc3QxQURuekVwd0hvYTlVQ29DZGhGbE5TN0d3NVhmR0tGUnVjUU5FekF1WjBOaXVaUjd4dk8xdC9hdE5qV2dQWUhvaERDNUpZaWtzM3ZCM1MrMzNwK0daM1VVcC8yK3pKTjVCUVBTQTJQbFpCZXpuMEFseG8yM1IvcjQ3bCt4czJ2YnNXajFxa0FGVUFZU0p0T2I3cUdkTTA4WHd2Njg0bjRTWkcyRVoxa2s2N0Fybk5ycWFISitNQUFBQUFQUkNMYXdBQUFBQUFDT3I4Ly8vLytBQUFBQUJsY3c0UkFBQUFBR1Z6RGc4QUFBQUFQR01hYmdBQUFBQUFDY0xZQ3I0dEhHVk9sNkh0dnpwVFlTMGNjaTdLTk5FYmxWRXlJU1lMTVpSemxhOEI2VnhOQ3FKbHZYUExZM0p3ckw4RG1NS2czNXJMVk14TWF4TE5EdkZOOHBTK2VzRjZrKy96SVc3WkxKY2l1MzE0N1NpcmpSbm42MHhhRlJYVkZWVVJycWlML1U0ZXlDTXIrWTdvRndFQ3RzS0F6OTdWNzQ4QlB6QnVtd3Fkc2d1Rnl1Q3ZJWldGTzNaVWlEMXp1dE1XYjBpYW9zK2o5SmVLeDhZRTZvQnVFRWlrRUVFN0l3SHllYXI0UTlub2orLzI0OVVBZmpuMEFseG8yM1IvcjQ3bCt4czJ2YnNXajFxa0FGVUFMWk1WcUk4d0dmanZxSTMrbkE4SVEzRXRvTHJJRkVZZUozTS9hNFByVWJNQUFBQUFkT2pNaXdBQUFBQUFKUDRCLy8vLytBQUFBQUJsY3c0UkFBQUFBR1Z6RGc4QUFBQUFjNlN1L0FBQUFBQUFJdXIzQ2hsMVJhT3BEV2k2S1VCbkozS1kwUUJ5WE5hdVlsNXV5YWpsQ0IwNlVxS29YM2h4VUFhbmdmWi83Wk1vWDlvdStEc2x5MW9hWkV3Z1ZqcVAvS3ZVeUh2QzhEcElDVU16aTNxakRab0c0ZjNoclJrQ1NjZmtiWGFybXNpOGZOVi9RUHJYN3U0eHYwQVVTL0FVWURIYmREcDFYRzJyM1dveExzZlV4QVgrMnJ0UEVYN0syWEZkNFlHSUpvc21laXIxSThBZ3owUlp6c2JMZlo1ZHdwWWs1bStrRUVFN0l3SHllYXI0UTlub2orLzI0OVVBZmpuMEFseG8yM1IvcjQ3bCt4czJ2YnNXajFxa0FGVUE3WUx2djYzZ0VJUC9xUFpHWk1ocTg1S0N5ZkNFaDNCbXJuSzJOZWQzR1BBQUFBQUFBQUE4V2dBQUFBQUFBQUJDLy8vLzlnQUFBQUJsY3c0UEFBQUFBR1Z6RGc0QUFBQUFBQUE4RkFBQUFBQUFBQUE2Q2lNOHhBaUtQUzByN2xOQnFGUVdvQUIySHN5cDArTm9vcmxKT3hJZzlMYmJOZEdMNHZUUzNZaTF6TUczOGVjSk1NM05zL1Q3OEkvS1JDajBUc3c1dWlZNlpncDROSmROMnJjSXBxekNsNVZNVkNnYUxBVHVienR3blNReDI5UDdBWU80T2RCbVhtSkF5TWg5YytwT01vWnY0dFo3ZEt3dnB5M2FTODFBUElqajU0TkpEdm9aMC9vTU5ucTlhdE5qV2dQWUhvaERDNUpZaWtzM3ZCM1MrMzNwK0daM1VVcC8yK3pKTjVCUVBTQTJQbFpCZXpuMEFseG8yM1IvcjQ3bCt4czJ2YnNXajFxa0FGVUFRZk5pV1hIS0x0SW1QbmhYUCtYT0krRTlKVmp0UHk1SHF3K0UrNTU2NXlJQUFBQUFCZlhnL3dBQUFBQUFBSFV0Ly8vLytBQUFBQUJsY3c0UkFBQUFBR1Z6RGc4QUFBQUFCZlhsakFBQUFBQUFBR3NYQ2tYVS94MUtZdEczb2VvUzVuQUlOV0tyUlBDc1R0NmVodjcxNXBSS25VZzJTTWNqbEVWdU91aklJUm5nZFpXSjlGVi9FV2hBMjdmaGZrT1pEeTZqQzUxTzlYT3cwTTByc0VlYUtWNzQ0NWFGM3doZjJ5bVY0aVZhbDhnNzI5MjdONGlRQkl4QnRJVDhuVkRxUERuQ3RJcVVlUEY1alpydTBPM2RZeVpxUjQwT2RGK3VtVkplUnNnZ0FEV0FlaXIxSThBZ3owUlp6c2JMZlo1ZHdwWWs1bStrRUVFN0l3SHllYXI0UTlub2orLzI0OVVBZmpuMEFseG8yM1IvcjQ3bCt4czJ2YnNXajFxayJdfX0sImZ1bmRzIjpbeyJkZW5vbSI6ImluaiIsImFtb3VudCI6IjE0In1dfX1d",
"txNumber":"17748337",
"txMsgTypes":"WyIvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QiXQ==",
"logs":"W3sibXNnX2luZGV4IjowLCJldmVudHMiOlt7InR5cGUiOiJtZXNzYWdlIiwiYXR0cmlidXRlcyI6W3sia2V5IjoiYWN0aW9uIiwidmFsdWUiOiIvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QifSx7ImtleSI6InNlbmRlciIsInZhbHVlIjoiaW5qMWRlZWpjNjZ2aGNxZW41cWp1MmVkbGM4d2pzM3g5MnNodjNrYXRzIn0seyJrZXkiOiJtb2R1bGUiLCJ2YWx1ZSI6Indhc20ifV19LHsidHlwZSI6ImNvaW5fc3BlbnQiLCJhdHRyaWJ1dGVzIjpbeyJrZXkiOiJzcGVuZGVyIiwidmFsdWUiOiJpbmoxZGVlamM2NnZoY3FlbjVxanUyZWRsYzh3anMzeDkyc2h2M2thdHMifSx7ImtleSI6ImFtb3VudCIsInZhbHVlIjoiMTRpbmoifV19LHsidHlwZSI6ImNvaW5fcmVjZWl2ZWQiLCJhdHRyaWJ1dGVzIjpbeyJrZXkiOiJyZWNlaXZlciIsInZhbHVlIjoiaW5qMThybGZscDM3MzVoMjVqbWp4OTdkMjJjNzJzeGsyNjBhbWRqeGx1In0seyJrZXkiOiJhbW91bnQiLCJ2YWx1ZSI6IjE0aW5qIn1dfSx7InR5cGUiOiJ0cmFuc2ZlciIsImF0dHJpYnV0ZXMiOlt7ImtleSI6InJlY2lwaWVudCIsInZhbHVlIjoiaW5qMThybGZscDM3MzVoMjVqbWp4OTdkMjJjNzJzeGsyNjBhbWRqeGx1In0seyJrZXkiOiJzZW5kZXIiLCJ2YWx1ZSI6ImluajFkZWVqYzY2dmhjcWVuNXFqdTJlZGxjOHdqczN4OTJzaHYza2F0cyJ9LHsia2V5IjoiYW1vdW50IiwidmFsdWUiOiIxNGluaiJ9XX0seyJ0eXBlIjoiZXhlY3V0ZSIsImF0dHJpYnV0ZXMiOlt7ImtleSI6Il9jb250cmFjdF9hZGRyZXNzIiwidmFsdWUiOiJpbmoxOHJsZmxwMzczNWgyNWptang5N2QyMmM3MnN4azI2MGFtZGp4bHUifV19LHsidHlwZSI6Indhc20iLCJhdHRyaWJ1dGVzIjpbeyJrZXkiOiJfY29udHJhY3RfYWRkcmVzcyIsInZhbHVlIjoiaW5qMThybGZscDM3MzVoMjVqbWp4OTdkMjJjNzJzeGsyNjBhbWRqeGx1In0seyJrZXkiOiJhY3Rpb24iLCJ2YWx1ZSI6InVwZGF0ZV9wcmljZV9mZWVkcyJ9LHsia2V5IjoibnVtX2F0dGVzdGF0aW9ucyIsInZhbHVlIjoiMTQifSx7ImtleSI6Im51bV91cGRhdGVkIiwidmFsdWUiOiIxNCJ9XX0seyJ0eXBlIjoiaW5qZWN0aXZlLm9yYWNsZS52MWJldGExLkV2ZW50U2V0UHl0aFByaWNlcyIsImF0dHJpYnV0ZXMiOlt7ImtleSI6InByaWNlcyIsInZhbHVlIjoiW3tcInByaWNlX2lkXCI6XCIweGZlNjUwZjAzNjdkNGE3ZWY5ODE1YTU5M2VhMTVkMzY1OTNmMDY0M2FhYWYwMTQ5YmIwNGJlNjdhYjg1MWRlY2RcIixcImVtYV9wcmljZVwiOlwiNzIuNjcxMjI2MDAwMDAwMDAwMDAwXCIsXCJlbWFfY29uZlwiOlwiMC4wMzg5OTk5NTAwMDAwMDAwMDBcIixcImNvbmZcIjpcIjAuMDMzMzE0MzAwMDAwMDAwMDAwXCIsXCJwdWJsaXNoX3RpbWVcIjpcIjE3MDIwMzkwNTdcIixcInByaWNlX3N0YXRlXCI6e1wicHJpY2VcIjpcIjczLjI4MTUzOTkxMDAwMDAwMDAwMFwiLFwiY3VtdWxhdGl2ZV9wcmljZVwiOlwiNTk1NjAyMjQ3LjEzNjEzNTY0MDAwMDAwMDAwMFwiLFwidGltZXN0YW1wXCI6XCIxNzAyMDM5MDU4XCJ9fSx7XCJwcmljZV9pZFwiOlwiMHgxZmMxODg2MTIzMjI5MDIyMTQ2MTIyMGJkNGUyYWNkMWRjZGZiYzg5Yzg0MDkyYzkzYzE4YmRjNzc1NmMxNTg4XCIsXCJlbWFfcHJpY2VcIjpcIjEuMDAwMTM5MzkwMDAwMDAwMDAwXCIsXCJlbWFfY29uZlwiOlwiMC4wMDAyNTQ0OTAwMDAwMDAwMDBcIixcImNvbmZcIjpcIjAuMDAwMjIwNDkwMDAwMDAwMDAwXCIsXCJwdWJsaXNoX3RpbWVcIjpcIjE3MDIwMzkwNTdcIixcInByaWNlX3N0YXRlXCI6e1wicHJpY2VcIjpcIjEuMDAwMTA1NTEwMDAwMDAwMDAwXCIsXCJjdW11bGF0aXZlX3ByaWNlXCI6XCIyMzIyNzc5Ni40NzU2MjQ3MzAwMDAwMDAwMDBcIixcInRpbWVzdGFtcFwiOlwiMTcwMjAzOTA1OFwifX0se1wicHJpY2VfaWRcIjpcIjB4ZjljMDE3MmJhMTBkZmE0ZDE5MDg4ZDk0ZjViZjYxZDNiNTRkNWJkNzQ4M2EzMjJhOTgyZTEzNzNlZThlYTMxYlwiLFwiZW1hX3ByaWNlXCI6XCI0MzQ4MS40NDcwMDAwMDAwMDAwMDAwMDBcIixcImVtYV9jb25mXCI6XCIxMy4zMDA4MzIzMDAwMDAwMDAwMDBcIixcImNvbmZcIjpcIjE1LjIyMTA3OTQ1MDAwMDAwMDAwMFwiLFwicHVibGlzaF90aW1lXCI6XCIxNzAyMDM5MDU3XCIsXCJwcmljZV9zdGF0ZVwiOntcInByaWNlXCI6XCI0MzY5Ny4zNTE5NTU1MzAwMDAwMDAwMDBcIixcImN1bXVsYXRpdmVfcHJpY2VcIjpcIjY4MzMwNjY2NjY4NC45NjIwNDczMjAwMDAwMDAwMDBcIixcInRpbWVzdGFtcFwiOlwiMTcwMjAzOTA1OFwifX0se1wicHJpY2VfaWRcIjpcIjB4MzdmNDBkMjg5ODE1OWU4ZjJlNTJiOTNjYjc4ZjQ3Y2MzODI5YTMxZTUyNWFiOTc1YzQ5Y2M1YzVkOTE3NjM3OFwiLFwiZW1hX3ByaWNlXCI6XCIxLjE2NDc0OTgxMDAwMDAwMDAwMFwiLFwiZW1hX2NvbmZcIjpcIjAuMDAwNjM4MTcwMDAwMDAwMDAwXCIsXCJjb25mXCI6XCIwLjAwMDU3ODk2MDAwMDAwMDAwMFwiLFwicHVibGlzaF90aW1lXCI6XCIxNzAyMDM5MDU3XCIsXCJwcmljZV9zdGF0ZVwiOntcInByaWNlXCI6XCIxLjE3MDM4MTA0MDAwMDAwMDAwMFwiLFwiY3VtdWxhdGl2ZV9wcmljZVwiOlwiMjQxNzYzMTkuNDE3NDMwMDgwMDAwMDAwMDAwXCIsXCJ0aW1lc3RhbXBcIjpcIjE3MDIwMzkwNThcIn19LHtcInByaWNlX2lkXCI6XCIweDMwYTE5MTU4ZjVhNTRjMGFkZjhmYjc1NjA2MjczNDNmMjJhMWJjODUyYjg5ZDU2YmUxYWNjZGM1ZGJmOTZkMGVcIixcImVtYV9wcmljZVwiOlwiMjAyOS40MDAwMDAwMDAwMDAwMDAwMDBcIixcImVtYV9jb25mXCI6XCIwLjEyNTAwMDAwMDAwMDAwMDAwMFwiLFwiY29uZlwiOlwiMC4xMTUwMDAwMDAwMDAwMDAwMDBcIixcInB1Ymxpc2hfdGltZVwiOlwiMTcwMjAzOTA1N1wiLFwicHJpY2Vfc3RhdGVcIjp7XCJwcmljZVwiOlwiMjAyOC43NjAwMDAwMDAwMDAwMDAwMDBcIixcImN1bXVsYXRpdmVfcHJpY2VcIjpcIjQzNzQ1MDU5NjM4LjQyMDAwMDAwMDAwMDAwMDAwMFwiLFwidGltZXN0YW1wXCI6XCIxNzAyMDM5MDU4XCJ9fSx7XCJwcmljZV9pZFwiOlwiMHhjMWIxMjc2OWY2NjMzNzk4ZDQ1YWRmZDYyYmZjNzAxMTQ4MzkyMzJlMjk0OWIwMWZiM2QzZjkyN2QyNjA2MTU0XCIsXCJlbWFfcHJpY2VcIjpcIjEuMDc4MjUwMDAwMDAwMDAwMDAwXCIsXCJlbWFfY29uZlwiOlwiMC4wMDAxMDAwMDAwMDAwMDAwMDBcIixcImNvbmZcIjpcIjAuMDAwMTAwMDAwMDAwMDAwMDAwXCIsXCJwdWJsaXNoX3RpbWVcIjpcIjE3MDIwMzkwNTdcIixcInByaWNlX3N0YXRlXCI6e1wicHJpY2VcIjpcIjEuMDc4MzUwMDAwMDAwMDAwMDAwXCIsXCJjdW11bGF0aXZlX3ByaWNlXCI6XCIyNDIzNzczMS4wNzEwMTAwMDAwMDAwMDAwMDBcIixcInRpbWVzdGFtcFwiOlwiMTcwMjAzOTA1OFwifX0se1wicHJpY2VfaWRcIjpcIjB4MzIxYmE0ZDYwOGZhNzViYTc2ZDZkNzNkYWE3MTVhYmNiZGViOWRiYTAyMjU3ZjA1YTFiNTkxNzhiNDlmNTk5YlwiLFwiZW1hX3ByaWNlXCI6XCIyMy44MDQxNTAwMDAwMDAwMDAwMDBcIixcImVtYV9jb25mXCI6XCIwLjAwNTAwMDAwMDAwMDAwMDAwMFwiLFwiY29uZlwiOlwiMC4wMDYyNTAwMDAwMDAwMDAwMDBcIixcInB1Ymxpc2hfdGltZVwiOlwiMTcwMjAzOTA1N1wiLFwicHJpY2Vfc3RhdGVcIjp7XCJwcmljZVwiOlwiMjMuNzc1NzUwMDAwMDAwMDAwMDAwXCIsXCJjdW11bGF0aXZlX3ByaWNlXCI6XCI1MjkwNjUwMTUuNTE0ODEwMDAwMDAwMDAwMDAwXCIsXCJ0aW1lc3RhbXBcIjpcIjE3MDIwMzkwNThcIn19LHtcInByaWNlX2lkXCI6XCIweDIwYTkzOGY1NGI2OGYxZjJlZjE4ZWEwMzI4ZjZkZDA3NDdmOGVhMTE0ODZkMjJiMDIxZTgzYTkwMGJlODk3NzZcIixcImVtYV9wcmljZVwiOlwiMTQ0LjM4MTAwMDAwMDAwMDAwMDAwMFwiLFwiZW1hX2NvbmZcIjpcIjAuMDA4MDAwMDAwMDAwMDAwMDAwXCIsXCJjb25mXCI6XCIwLjAwODAwMDAwMDAwMDAwMDAwMFwiLFwicHVibGlzaF90aW1lXCI6XCIxNzAyMDM5MDU3XCIsXCJwcmljZV9zdGF0ZVwiOntcInByaWNlXCI6XCIxNDQuMjg1MDAwMDAwMDAwMDAwMDAwXCIsXCJjdW11bGF0aXZlX3ByaWNlXCI6XCIzMTQ4MTY5NTYzLjY5MjAwMDAwMDAwMDAwMDAwMFwiLFwidGltZXN0YW1wXCI6XCIxNzAyMDM5MDU4XCJ9fSx7XCJwcmljZV9pZFwiOlwiMHhiY2JkYzI3NTViZDc0YTIwNjVmOWQzMjgzYzJiOGFjYmQ4OThlNDczYmRiOTBhNjc2NGIzZGJkNDY3YzU2ZWNkXCIsXCJlbWFfcHJpY2VcIjpcIjEuMjU3NzMwMDAwMDAwMDAwMDAwXCIsXCJlbWFfY29uZlwiOlwiMC4wMDAwOTAwMDAwMDAwMDAwMDBcIixcImNvbmZcIjpcIjAuMDAwMTAwMDAwMDAwMDAwMDAwXCIsXCJwdWJsaXNoX3RpbWVcIjpcIjE3MDIwMzkwNTdcIixcInByaWNlX3N0YXRlXCI6e1wicHJpY2VcIjpcIjEuMjU3NjAwMDAwMDAwMDAwMDAwXCIsXCJjdW11bGF0aXZlX3ByaWNlXCI6XCIyNzk5MTIyNS43NTQ3MDAwMDAwMDAwMDAwMDBcIixcInRpbWVzdGFtcFwiOlwiMTcwMjAzOTA1OFwifX0se1wicHJpY2VfaWRcIjpcIjB4Y2E4MGJhNmRjMzJlMDhkMDZmMWFhODg2MDExZWVkMWQ3N2M3N2JlOWViNzYxY2MxMGQ3MmI3ZDBhMmZkNTdhNlwiLFwiZW1hX3ByaWNlXCI6XCIyMzYyLjg1NzI0MDAwMDAwMDAwMDAwMFwiLFwiZW1hX2NvbmZcIjpcIjAuOTEzODg2NTEwMDAwMDAwMDAwXCIsXCJjb25mXCI6XCIwLjkxOTk4NDUwMDAwMDAwMDAwMFwiLFwicHVibGlzaF90aW1lXCI6XCIxNzAyMDM5MDU3XCIsXCJwcmljZV9zdGF0ZVwiOntcInByaWNlXCI6XCIyMzY1LjIyOTk4NDUwMDAwMDAwMDAwMFwiLFwiY3VtdWxhdGl2ZV9wcmljZVwiOlwiNDE3OTY4MDExMjEuNzk4MDYyMjEwMDAwMDAwMDAwXCIsXCJ0aW1lc3RhbXBcIjpcIjE3MDIwMzkwNThcIn19LHtcInByaWNlX2lkXCI6XCIweDYxMjI2ZDM5YmVlYTE5ZDMzNGYxN2MyZmViY2UyN2UxMjY0NmQ4NDY3NTkyNGViYjAyYjljZGFlYTY4NzI3ZTNcIixcImVtYV9wcmljZVwiOlwiMTAuMTMxMjc3OTAwMDAwMDAwMDAwXCIsXCJlbWFfY29uZlwiOlwiMC4wMDYzOTcwNDAwMDAwMDAwMDBcIixcImNvbmZcIjpcIjAuMDA1ODQ0NDQwMDAwMDAwMDAwXCIsXCJwdWJsaXNoX3RpbWVcIjpcIjE3MDIwMzkwNTdcIixcInByaWNlX3N0YXRlXCI6e1wicHJpY2VcIjpcIjEwLjI0NDk0NDQzMDAwMDAwMDAwMFwiLFwiY3VtdWxhdGl2ZV9wcmljZVwiOlwiMjEzODk1OTI4Ljc1Nzk5NTcyMDAwMDAwMDAwMFwiLFwidGltZXN0YW1wXCI6XCIxNzAyMDM5MDU4XCJ9fSx7XCJwcmljZV9pZFwiOlwiMHgyZDkzMTVhODhmMzAxOWY4ZWZhODhkZmU5YzBmMDg0MzcxMmRhMGJhYzgxNDQ2MWUyNzczM2Y2YjgzZWI1MWIzXCIsXCJlbWFfcHJpY2VcIjpcIjE5LjQwMTcyNTQwMDAwMDAwMDAwMFwiLFwiZW1hX2NvbmZcIjpcIjAuMDIyODgzNzUwMDAwMDAwMDAwXCIsXCJjb25mXCI6XCIwLjAyNDI0MzIxMDAwMDAwMDAwMFwiLFwicHVibGlzaF90aW1lXCI6XCIxNzAyMDM5MDU3XCIsXCJwcmljZV9zdGF0ZVwiOntcInByaWNlXCI6XCIxOS42MTQxMzc3MTAwMDAwMDAwMDBcIixcImN1bXVsYXRpdmVfcHJpY2VcIjpcIjE5Njk2NjI1Ni4xNTc4MjA0ODAwMDAwMDAwMDBcIixcInRpbWVzdGFtcFwiOlwiMTcwMjAzOTA1OFwifX0se1wicHJpY2VfaWRcIjpcIjB4ZWQ4MmVmYmZhZGUwMTA4M2ZmYThmNjQ2NjRjODZhZjM5MjgyYzlmMDg0ODc3MDY2YWU3MmI2MzVlNzc3MThmMFwiLFwiZW1hX3ByaWNlXCI6XCIwLjAwMDAwMTUzODAwMDAwMDAwMFwiLFwiZW1hX2NvbmZcIjpcIjAuMDAwMDAwMDA1ODAwMDAwMDAwXCIsXCJjb25mXCI6XCIwLjAwMDAwMDAwNjYwMDAwMDAwMFwiLFwicHVibGlzaF90aW1lXCI6XCIxNzAyMDM5MDU1XCIsXCJwcmljZV9zdGF0ZVwiOntcInByaWNlXCI6XCIwLjAwMDAwMTU0NTAwMDAwMDAwMFwiLFwiY3VtdWxhdGl2ZV9wcmljZVwiOlwiMjAuOTYzNzUwNDQyMjAwMDAwMDAwXCIsXCJ0aW1lc3RhbXBcIjpcIjE3MDIwMzkwNThcIn19LHtcInByaWNlX2lkXCI6XCIweDQxZjM2MjU5NzFjYTJlZDIyNjNlNzg1NzNmZTVjZTIzZTEzZDI1NThlZDNmMmU0N2FiMGY4NGZiOWU3YWU3MjJcIixcImVtYV9wcmljZVwiOlwiMS4wMDAwMTE2NDAwMDAwMDAwMDBcIixcImVtYV9jb25mXCI6XCIwLjAwMDI3NDE1MDAwMDAwMDAwMFwiLFwiY29uZlwiOlwiMC4wMDAyOTk5NzAwMDAwMDAwMDBcIixcInB1Ymxpc2hfdGltZVwiOlwiMTcwMjAzOTA1N1wiLFwicHJpY2Vfc3RhdGVcIjp7XCJwcmljZVwiOlwiMC45OTk5OTk5OTAwMDAwMDAwMDBcIixcImN1bXVsYXRpdmVfcHJpY2VcIjpcIjIzMjIyMDc2Ljg1MzYxNTM4MDAwMDAwMDAwMFwiLFwidGltZXN0YW1wXCI6XCIxNzAyMDM5MDU4XCJ9fV0ifV19XX1d",
"id":"",
"codespace":"",
"errorLog":"",
"code":0,
"claimIds":[
]
}
]
}
}
{
"paging": {
"total": 100000,
"from": 6007200,
"to": 6001687
},
"data": [
{
"block_number": 6007200,
"block_timestamp": "2022-05-31 12:48:34.886 +0000 UTC",
"hash": "0xaaf6e69819ade1b9bdc128ec84d35a0d928c46082007522f1ac80b999f62adfd",
"data": "CjQKMi9pbmplY3RpdmUub3JhY2xlLnYxYmV0YTEuTXNnUmVsYXlDb2luYmFzZU1lc3NhZ2Vz",
"gas_wanted": 784680,
"gas_used": 538379,
"gas_fee": {
"amount": [
{
"denom": "inj",
"amount": "392340000000000"
}
],
"gas_limit": 784680,
"payer": "inj128jwakuw3wrq6ye7m4p64wrzc5rfl8tvwzc6s8"
},
"tx_type": "injective",
"messages": "[{\"type\":\"/injective.oracle.v1beta1.MsgRelayCoinbaseMessages\",\"value\":{\"messages\":[\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYORAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1rce1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANCVEMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYORAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHT/28gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANFVEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYORAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf0IgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANYVFoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpX2mAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPQRQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANEQUkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYORAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACk3wgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANSRVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYORAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGaOoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANaUlgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYORAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGHVEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANCQVQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYORAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAh82gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANLTkMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYORAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwiJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARMSU5LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYORAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPA/6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARDT01QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYORAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABXleAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANVTkkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYORAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACWcIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANHUlQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYORAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv2/QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANTTlgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\"],\"sender\":\"inj128jwakuw3wrq6ye7m4p64wrzc5rfl8tvwzc6s8\",\"signatures\":[\"zCWD1dTt0tIGMPwd/8ff81HrG6nloxk6EVb1r7SOgO+c3NDRFoTqRGbQ4PwuDYAXzrTIznkiax808YeqbltB+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc\",\"/kefMAblMcZEff6jiTRbYl0nmhSGVkCGeKBznKhQ5sldNytKBgWV7WQxGS9vbRXk/PSOgt6wHJ7ZRxdHw3LogwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb\",\"FdnISEwJs5jBx4PQFO4snJLjc7KSZ46hWzeruHnqFcoMN9ojanwnk/vKO13rKVqUWZb7l4Oak9hWJ/rYXLi86wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb\",\"0dWYExhIsaEL2/7xD1z2tPFbmxtXE9SRnOF/FCLsvMkenMopwQxK82oe+qK2Ts2pXVE7oFO6IyMQWCLIeVIcrQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc\",\"+UhX91gBZchuBZ21gdg6toGJEU4egivkRT5lEoh+AReN7ClIDhEKvKp/nVhEa5+zzIXY/5KCWOcGZlJ/Pfx8zgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc\",\"e1ho1uftysZdxNIg+701zAanvZxtEjSnfXynDWW7x6Wo79/mBs+KUpHzUfhlYxp8mgoOZbGCp3k5l83/4lhYwwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb\",\"n8MD/MYj6B4u0YMiGrJOYdlQ3U6tfbOxBRptWgr6x/aLj2eKbcE5gmg6gGVas9WBvjquKAhQR8U5MhYkLbqYbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb\",\"txgWSFuq4x8o44kvl4I1GCryAa6gUzPTWAKWLxfp6HtzIWVoFDsiz1dFDngfaIBPo+lmvak1lEBES+I9Ai2O6wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb\",\"BrWea8Hrzn6hd2rEZ6MYMcxUw7+a3xomj554oY4okaW8YaDFHl+Qjx83rYN/hV++I016oofLLpSQ7Un/t2gGVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb\",\"A8Ls0YNqqj8DHofRIhkpG+KgM1qitVYyx72/8qPhi9kymmzEnWNaAnsNqBvBGvXka1e5u9bCFTmdx3lHpVe3pwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc\",\"QCnXDJR/47TZ9OJ0jEUxdPgp2tvbJvNUMkupmY0qE6rbrdMbbihu0oRn8q3TAzfELimrj3HuXqmi4dHjCfulVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb\",\"oE3BN/deGTEqyXcfx+jmTjzp3uY9YPo3x8m678U6zKPTkE3eR1tnQ5tmwOOfejm7h5XzFWpnSdFylVKLBNqU1wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc\",\"+QU+45qb2cZL3jtmCtmXpUl1kROnRF0f4XiQ5sU+liRoqY/LKJDfKoy/ufqmApjGzYNuB6ccmKS2fLduARDZ0wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc\"]}}]",
"signatures": [
{
"pubkey": "injvalcons128jwakuw3wrq6ye7m4p64wrzc5rfl8tvdh7raz",
"address": "inj128jwakuw3wrq6ye7m4p64wrzc5rfl8tvwzc6s8",
"sequence": 54715,
"signature": "DDzBCEVmF9uNCt0kH9BSBcWYNs/D4ePWAPil/JU8FaMInn5ENSGNZ2qzPQPtnPxl63Z6pIMkeGFlxIlZo4COuAE="
}
]
},
{
"block_number": 6007111,
"block_timestamp": "2022-05-31 12:45:41.945 +0000 UTC",
"hash": "0x57d2c0dd087206f9772efdb6901b66c604d75c023d89a5c9614893e6157d1df1",
"data": "CjQKMi9pbmplY3RpdmUub3JhY2xlLnYxYmV0YTEuTXNnUmVsYXlDb2luYmFzZU1lc3NhZ2Vz",
"gas_wanted": 710127,
"gas_used": 488677,
"gas_fee": {
"amount": [
{
"denom": "inj",
"amount": "355063500000000"
}
],
"gas_limit": 710127,
"payer": "inj128jwakuw3wrq6ye7m4p64wrzc5rfl8tvwzc6s8"
},
"tx_type": "injective",
"messages": "[{\"type\":\"/injective.oracle.v1beta1.MsgRelayCoinbaseMessages\",\"value\":{\"messages\":[\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYNkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1oqt4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANCVEMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYNkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHTk7UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANFVEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYNkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfqXgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANYVFoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpX2mAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPQRQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANEQUkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYNkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAClLSgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANSRVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYNkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGaNIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANaUlgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYNVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGFSQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANCQVQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYNkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhyTgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANLTkMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYNkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwTgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARMSU5LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYNkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO84PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARDT01QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYNkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABXW0gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANVTkkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYNkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACWDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANHUlQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYpYNkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvrwgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnByaWNlcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANTTlgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\"],\"sender\":\"inj128jwakuw3wrq6ye7m4p64wrzc5rfl8tvwzc6s8\",\"signatures\":[\"YL231HABMdVXctipqLhc638wBgdTFpwOZAdAgPgefAjXC8Vvl65gXzw9cNRJOY0kA4vCt0g8FiF9YqdOw1jnbQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc\",\"kGtm079wAMRGGjJPT/WuLvd4M5LNTcjkIoTDI8SW6j6wwFhUYblYscAvJsqdtNxKzUB/s93g48nbfYbV+HRlrQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc\",\"LXYjHiXRC5HTKlylmfF+diCBzrAOY74yrKPNNqnN8RS+d+TKT/hx8CLGQt3QuLxlWnNg7BwucO+/TfhMauyp0wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb\",\"0dWYExhIsaEL2/7xD1z2tPFbmxtXE9SRnOF/FCLsvMkenMopwQxK82oe+qK2Ts2pXVE7oFO6IyMQWCLIeVIcrQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc\",\"kkHcQL/fE+b4cXcTpxwL6gCiEHSx6vFapLVJ6pD+VQ5fv+FUZDj20fgMhigsA3cKa0TRhqB4VW/yeBeYeo+dtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc\",\"NgCe7fZDDgiHYKzTQGCmRvcCBO6hAtK+Lray3inBoJ2U5X102+9+hrW0843QToBG1LYHZ9kQ81DzkMNe6lKmLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb\",\"RGiVY4JdjfVmXcIu5qcwhFwTTDl/Vi8etEMA3wGCisPqmG5x1/ibcTBqwu+bRftdaS1tR1EndDW+wsVvyJ27tAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb\",\"wvgniA1t3o6E/2t9OsqWKZq9vDlmOD8KR8/m3rjUnupQpv1fQ/b84T/FsFRezSZrfD1FUGUJZU4OpI90cvsN1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc\",\"/Eks8pFIMrD64hlAwpNVmns4AwCVgsjty7ckBiKrau6ZPtmm7JyW0PcaAuvHtT+y2NE0F6I9h2fPzOIi+VCXLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc\",\"Ielef8mF/3IUz3VMl1uvbcgqs1i4jvgHPviwF5S6gkFDSa/YfPUp022c9+Q3pW7tidxaqWQbbayOUI9XrFBoNwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc\",\"1EDj3Pq/bh07CAE7EYReXiZgMH/tEFkar112JmsK83tWaCBuw6iRvZ43GqMvmnn5vU66axYg58UdxAcrkexfRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb\",\"V1yoJNEvPhwT6BQ3HlpZsEaJgy/SHrb9cfMi9gg3GpbfkDvDx0qhrgkMPyd/YSCk+0Vpfyc9p15GbM4KfjwPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc\",\"iUoHMZwEx1gIjM8p8fejb6YAwMw+xzDshdnlr9mdosrP6qDjxOXqzcX644Nk8J2qG5Jd3QPgrSfbYP5fz9CggQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb\"]}}]",
"signatures": [
{
"pubkey": "injvalcons128jwakuw3wrq6ye7m4p64wrzc5rfl8tvdh7raz",
"address": "inj128jwakuw3wrq6ye7m4p64wrzc5rfl8tvwzc6s8",
"sequence": 54714,
"signature": "HetA8jXHA1wsAF4HhO5DkQL+qZNkYnZP6IRlYANqz+ZByTFXbJ9suv1qZFMtHxANMkThjsNHfoNR3FyLCH+z9AA="
}
]
}
]
}
Parameter | Type | Description |
---|---|---|
data | TxData Array | Transactions data |
paging | Paging | Pagination of results |
Paging
Parameter | Type | Description |
---|---|---|
total | Integer | Total number of records available |
TxData
Parameter | Type | Description |
---|---|---|
block_number | Integer | The block at which the transaction was executed |
block_timestamp | String | The timestamp of the block (yyyy-MM-dd HH:mm:ss.SSS ZZZZ zzz, e.g. 2022-11-14 13:16:18.946 +0000 UTC) |
hash | String | The transaction hash |
messages | bytes | The raw data in bytes |
tx_number | Integer | The transaction number |
error_log | String | Logged errors, if any |
StreamTxs
Stream transactions.
IP rate limit group: indexer
Request Example:
import asyncio
from typing import Any, Dict
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def tx_event_processor(event: Dict[str, Any]):
print(event)
def stream_error_processor(exception: RpcError):
print(f"There was an error listening to txs updates ({exception})")
def stream_closed_processor():
print("The txs updates stream has been closed")
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
task = asyncio.get_event_loop().create_task(
client.listen_txs_updates(
callback=tx_event_processor,
on_end_callback=stream_closed_processor,
on_status_callback=stream_error_processor,
)
)
await asyncio.sleep(delay=60)
task.cancel()
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
explorerclient "github.com/InjectiveLabs/sdk-go/client/explorer"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
explorerClient, err := explorerclient.NewExplorerClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
stream, err := explorerClient.StreamTxs(ctx)
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
return
default:
res, err := stream.Recv()
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
}
}
Parameter | Type | Description | Required |
---|---|---|---|
callback | Function | Function receiving one parameter (a stream event JSON dictionary) to process each new event | Yes |
on_end_callback | Function | Function with the logic to execute when the stream connection is interrupted | No |
on_status_callback | Function | Function receiving one parameter (the exception) with the logic to execute when an exception happens | No |
Response Parameters
Response Example:
{
"blockNumber":"19388455",
"blockTimestamp":"2023-12-08 12:39:19.596 +0000 UTC",
"hash":"0xf4f17301c06df63160b60a071985fc0e0093a53e4027a2086fc51b0a46b6b43c",
"messages":"[{\"type\":\"/cosmos.authz.v1beta1.MsgExec\",\"value\":{\"grantee\":\"inj12shqy72r0apr4d9ft9x6z59t5yfjj4jv9n79l6\",\"msgs\":[{\"@type\":\"/injective.exchange.v1beta1.MsgBatchUpdateOrders\",\"sender\":\"inj15uad884tqeq9r76x3fvktmjge2r6kek55c2zpa\",\"subaccount_id\":\"\",\"spot_market_ids_to_cancel_all\":[],\"derivative_market_ids_to_cancel_all\":[],\"spot_orders_to_cancel\":[],\"derivative_orders_to_cancel\":[],\"spot_orders_to_create\":[],\"derivative_orders_to_create\":[{\"market_id\":\"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6\",\"order_info\":{\"subaccount_id\":\"0xa73ad39eab064051fb468a5965ee48ca87ab66d4000000000000000000000004\",\"fee_recipient\":\"inj15uad884tqeq9r76x3fvktmjge2r6kek55c2zpa\",\"price\":\"18495900.000000000000000000\",\"quantity\":\"60.000000000000000000\",\"cid\":\"HBOTSIJUT60bfedf775353d7bf700310e7cd\"},\"order_type\":\"SELL\",\"margin\":\"0.000000000000000000\",\"trigger_price\":\"0.000000000000000000\"}],\"binary_options_orders_to_cancel\":[],\"binary_options_market_ids_to_cancel_all\":[],\"binary_options_orders_to_create\":[]}]}}]",
"txNumber":"17748407",
"id":"",
"codespace":"",
"errorLog":"",
"code":0,
"claimIds":[
]
}
{
"block_number": 6129344,
"block_timestamp": "2022-06-03 06:48:33.883 +0000 UTC",
"hash": "0x8cbfc9c361abea5b59c95ed8096cd55d9b41af68e0fd81fab049f9e9aaace206",
"data": "CnwKNC9pbmplY3RpdmUuZXhjaGFuZ2UudjFiZXRhMS5Nc2dDcmVhdGVTcG90TWFya2V0T3JkZXISRApCMHgzNGVjMGEyNTQzYWM5NmZlZmM2NWE0ZmQyMDUyOWE5MWQ4MzRiYzgwMzEwMzQ3M2FhYTlmYWY2YWMyMjVmYzNm",
"gas_wanted": 129946,
"gas_used": 101840,
"gas_fee": {
"amount": [
{
"denom": "inj",
"amount": "64973000000000"
}
],
"gas_limit": 129946,
"payer": "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r"
},
"tx_type": "injective",
"messages": "[{\"type\":\"/injective.exchange.v1beta1.MsgCreateSpotMarketOrder\",\"value\":{\"order\":{\"market_id\":\"0x8b1a4d3e8f6b559e30e40922ee3662dd78edf7042330d4d620d188699d1a9715\",\"order_info\":{\"fee_recipient\":\"inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r\",\"price\":\"0.984400000000000000\",\"quantity\":\"23000000.000000000000000000\",\"subaccount_id\":\"0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000\"},\"order_type\":\"BUY\",\"trigger_price\":null},\"sender\":\"inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r\"}}]",
"signatures": [
{
"pubkey": "injvalcons1cml96vmptgw99syqrrz8az79xer2pcgpvgp7ex",
"address": "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r",
"sequence": 2087458,
"signature": "UWKbIKeR4a2Ws1zE5vno5Q71WLIiUzB4dGhJzLuUtLQWV09PcP/a40L0nzw0hnMEhSqJUeDk9oj0PVr6c0ZMZQE="
}
]
}{
"block_number": 6129345,
"block_timestamp": "2022-06-03 06:48:35.803 +0000 UTC",
"hash": "0x13177ab51add513cfae7586886954c6bc818c18d8523a4c29475d66114917cb3",
"data": "CnwKNC9pbmplY3RpdmUuZXhjaGFuZ2UudjFiZXRhMS5Nc2dDcmVhdGVTcG90TWFya2V0T3JkZXISRApCMHhmY2MyNmRjYzc0OTQwMWRjZTA0NmNkM2M5M2QwNzczMzZkOGI1MDhiYTk0N2MxMzA4MjlhMzllNThjYzA1YzI2",
"gas_wanted": 130489,
"gas_used": 102202,
"gas_fee": {
"amount": [
{
"denom": "inj",
"amount": "65244500000000"
}
],
"gas_limit": 130489,
"payer": "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r"
},
"tx_type": "injective",
"messages": "[{\"type\":\"/injective.exchange.v1beta1.MsgCreateSpotMarketOrder\",\"value\":{\"order\":{\"market_id\":\"0xbe9d4a0a768c7e8efb6740be76af955928f93c247e0b3a1a106184c6cf3216a7\",\"order_info\":{\"fee_recipient\":\"inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r\",\"price\":\"0.000000000071480000\",\"quantity\":\"240000000000000000000.000000000000000000\",\"subaccount_id\":\"0xc6fe5d33615a1c52c08018c47e8bc53646a0e101000000000000000000000000\"},\"order_type\":\"BUY\",\"trigger_price\":null},\"sender\":\"inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r\"}}]",
"signatures": [
{
"pubkey": "injvalcons1cml96vmptgw99syqrrz8az79xer2pcgpvgp7ex",
"address": "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r",
"sequence": 2087459,
"signature": "yXQON133B3lJlVNkFwf0pvZof6GCoeKoIhMkKHe3sndfgf2aWs4DwlOVlbEZTY4X++x+PU6sZNngHACiuGqPmAE="
}
]
}
Parameter | Type | Description |
---|---|---|
block_number | Integer | The block at which the transaction was executed |
block_timestamp | String | The timestamp of the block (yyyy-MM-dd HH:mm:ss.SSS ZZZZ zzz, e.g. 2022-11-14 13:16:18.946 +0000 UTC) |
hash | String | The transaction hash |
messages | bytes | The raw data in bytes |
tx_number | Integer | The transaction number |
error_log | String | Logged errors, if any |
StreamBlocks
Stream blocks.
IP rate limit group: indexer
Request Example:
import asyncio
from typing import Any, Dict
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def block_event_processor(event: Dict[str, Any]):
print(event)
def stream_error_processor(exception: RpcError):
print(f"There was an error listening to blocks updates ({exception})")
def stream_closed_processor():
print("The blocks updates stream has been closed")
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
task = asyncio.get_event_loop().create_task(
client.listen_blocks_updates(
callback=block_event_processor,
on_end_callback=stream_closed_processor,
on_status_callback=stream_error_processor,
)
)
await asyncio.sleep(delay=60)
task.cancel()
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
explorerclient "github.com/InjectiveLabs/sdk-go/client/explorer"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
explorerClient, err := explorerclient.NewExplorerClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
stream, err := explorerClient.StreamBlocks(ctx)
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
return
default:
res, err := stream.Recv()
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
}
}
Parameter | Type | Description | Required |
---|---|---|---|
callback | Function | Function receiving one parameter (a stream event JSON dictionary) to process each new event | Yes |
on_end_callback | Function | Function with the logic to execute when the stream connection is interrupted | No |
on_status_callback | Function | Function receiving one parameter (the exception) with the logic to execute when an exception happens | No |
Response Parameters
Response Example:
{
"height":"19388498",
"proposer":"injvalcons1xml3ew93xmjtuf5zwpcl9jzznphte30hvdre9a",
"moniker":"InjectiveNode2",
"blockHash":"0xf12fd7ce5a00a4bab5028f6b6e94e014d31074b8f4a45d03731ab640533c71b7",
"parentHash":"0x601b7b2c202e8142535b1a76ec095a05e91c2507cbb462d59c0fd251fd769255",
"numTxs":"2",
"timestamp":"2023-12-08 12:40:51.641 +0000 UTC",
"numPreCommits":"0",
"txs":[
]
}
{
"height":"19388499",
"proposer":"injvalcons1xwg7xkmpqp8q804c37sa4dzyfwgnh4a74ll9pz",
"moniker":"InjectiveNode0",
"blockHash":"0x36bc946dba7fd81ea9b8dac4a70ca20ff4bc8e59b6ed2005e397d6ab0d3655d7",
"parentHash":"0xf37f966ec5d8275c74f25fbb3c39e7f58b30ca36dff5592cde44dd251b943fd8",
"numTxs":"3",
"timestamp":"2023-12-08 12:40:53.945 +0000 UTC",
"numPreCommits":"0",
"txs":[
]
}
{
"height":"19388500",
"proposer":"injvalcons18x63wcw5hjxlf535lgn4qy20yer7mm0qedu0la",
"moniker":"InjectiveNode1",
"blockHash":"0x1da9e10a726da84a5f7b53e25a598165a5ac44b573b7a3a7a1044242f9de2c83",
"parentHash":"0xad1f884d19fac8c6abc8b1e896e34a84583c49dc3ff66070c477a5af71bf54a2",
"numTxs":"2",
"timestamp":"2023-12-08 12:40:56.463 +0000 UTC",
"numPreCommits":"0",
"txs":[
]
}
{
"height": 6009287,
"proposer": "injvalcons1aju53n6la4xzemws8gqnvr9v8hsjdea706jq7f",
"moniker": "InjectiveNode2",
"block_hash": "0x9ad53714c72b66d4c347814a0b14975160cda0f22e48df1e59cf1f4e9c083526",
"parent_hash": "0x3a8aa6a5f7b9c3647442a0a7f43586c30b66b216ff3e29c373e9b02cbb81f51b",
"timestamp": "2022-05-31 13:56:17.644 +0000 UTC"
}{
"height": 6009288,
"proposer": "injvalcons1qmrj7lnzraref92lzuhrv6m7sxey248fzxmfnf",
"moniker": "InjectiveNode3",
"block_hash": "0x1869065635c1b726d973ea154c49736dbcf3159975b4ef6236a85128ee0ad69a",
"parent_hash": "0xb9054fd1f6ca37ba8d2507636685ceb548a6dc224c4658f6ec4e118ef803a6e8",
"timestamp": "2022-05-31 13:56:19.657 +0000 UTC"
}
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
proposer | String | The block proposer |
moniker | String | The block proposer's moniker |
block_hash | String | The block hash |
parent_hash | String | The parent hash |
num_txs | Integer | The number of transactions in the block |
timestamp | String | The block's timestamp (yyyy-MM-dd HH:mm:ss.SSS ZZZZ zzz, e.g. 2022-11-14 13:16:18.946 +0000 UTC) |
PeggyDeposits
Get info on peggy deposits. By default, deposits for all senders and receivers will be fetched.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
receiver = "inj1phd706jqzd9wznkk5hgsfkrc8jqxv0kmlj0kex"
peggy_deposits = await client.fetch_peggy_deposit_txs(receiver=receiver)
print(peggy_deposits)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
explorerPB "github.com/InjectiveLabs/sdk-go/exchange/explorer_rpc/pb"
"github.com/InjectiveLabs/sdk-go/client/common"
explorerclient "github.com/InjectiveLabs/sdk-go/client/explorer"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
explorerClient, err := explorerclient.NewExplorerClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
receiver := "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku"
req := explorerPB.GetPeggyDepositTxsRequest{
Receiver: receiver,
}
res, err := explorerClient.GetPeggyDeposits(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | Filter by sender address | No |
receiver | String | Filter by receiver address | No |
pagination | PaginationOption | Pagination configuration | No |
Response Parameters
Response Example:
{
"field":[
{
"sender":"0x197E6c3f19951eA0bA90Ddf465bcC79790cDD12d",
"receiver":"inj1r9lxc0cej502pw5smh6xt0x8j7gvm5fdrj6xhk",
"eventNonce":"624",
"eventHeight":"10122722",
"amount":"500000000000000000",
"denom":"0xAD1794307245443B3Cb55d88e79EEE4d8a548C03",
"orchestratorAddress":"inj1c8rpu79mr70hqsgzutdd6rhvzhej9vntm6fqku",
"state":"Completed",
"claimType":1,
"txHashes":[
"0x028a43ad2089cad45a8855143508f7381787d7f17cc19e3cda1bc2300c1d043f"
],
"createdAt":"2023-11-28 16:55:54.841 +0000 UTC",
"updatedAt":"2023-11-28 16:56:07.944 +0000 UTC"
},
{
"sender":"0x197E6c3f19951eA0bA90Ddf465bcC79790cDD12d",
"receiver":"inj1r9lxc0cej502pw5smh6xt0x8j7gvm5fdrj6xhk",
"eventNonce":"622",
"eventHeight":"10094898",
"amount":"550000000000000000",
"denom":"0xAD1794307245443B3Cb55d88e79EEE4d8a548C03",
"orchestratorAddress":"inj1c8rpu79mr70hqsgzutdd6rhvzhej9vntm6fqku",
"state":"Completed",
"claimType":1,
"txHashes":[
"0xa528a522ce00b0f44add4a634ec92417c483fc045aa6b3f1cfceb685cdcf13a7"
],
"createdAt":"2023-11-23 18:09:52.228 +0000 UTC",
"updatedAt":"2023-11-23 18:10:31.294 +0000 UTC"
}
]
}
{
"field": [
{
"sender": "0xbdAEdEc95d563Fb05240d6e01821008454c24C36",
"receiver": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"event_nonce": 201,
"event_height": 31544480,
"amount": "1000000000000000000",
"denom": "0x36B3D7ACe7201E28040eFf30e815290D7b37ffaD",
"orchestrator_address": "inj1ultw9r29l8nxy5u6thcgusjn95vsy2caecl0ps",
"state": "Completed",
"claim_type": 1,
"tx_hashes": [
"0x8de1bf0f32966d2edf09378bc0e1d292f8ae34c45ae0b37a847867753a4b37a6"
],
"created_at": "2022-06-01 07:25:47.077 +0000 UTC",
"updated_at": "2022-06-01 07:32:01.671 +0000 UTC"
},
{
"sender": "0xbdAEdEc95d563Fb05240d6e01821008454c24C36",
"receiver": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"event_nonce": 200,
"event_height": 31396037,
"amount": "1000000000000000000",
"denom": "0x36B3D7ACe7201E28040eFf30e815290D7b37ffaD",
"orchestrator_address": "inj1ultw9r29l8nxy5u6thcgusjn95vsy2caecl0ps",
"state": "Completed",
"claim_type": 1,
"tx_hashes": [
"0x377c52c94f8cab6e91d4b56a5e65710c1452acc4b10bc26d111ceeab9e30a67f"
],
"created_at": "2022-06-01 07:17:52.285 +0000 UTC",
"updated_at": "2022-06-01 07:31:57.848 +0000 UTC"
},
{
"sender": "0xAF79152AC5dF276D9A8e1E2E22822f9713474902",
"receiver": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"event_nonce": 2,
"event_height": 29335363,
"amount": "50000000000000000000",
"denom": "0xA3a9029B8120e2F09B194Df4A249A24dB461E573",
"orchestrator_address": "inj1hs9q5xuvzunl77uv0mf0amsfa79uzhsrzak00a",
"state": "InjectiveConfirming",
"tx_hashes": [
"0x97d223982ffef0a0550d75c8dfdb8fd661b8be28744d3f5b23cb8c1b328d1b3b"
],
"created_at": "2022-05-18 21:03:34.991 +0000 UTC",
"updated_at": "0001-01-01 00:00:00 +0000 UTC"
}
]
}
Parameter | Type | Description |
---|---|---|
field | PeggyDepositTx Array | List of peggy deposits |
PeggyDepositTx
Parameter | Type | Description |
---|---|---|
sender | String | The sender address |
receiver | String | The receiver address |
event_nonce | Integer | The event nonce |
event_height | Integer | The event height |
amount | String | The deposited amount |
denom | Integer | The token denom |
orchestrator_address | String | The orchestrator address |
state | String | Transaction state |
claim_type | Integer | Claim type of the deposit, always equal to 1 |
tx_hashes | String Array | List of transaction hashes |
created_at | Integer | The timestamp of the tx creation (yyyy-MM-dd HH:mm:ss.SSS ZZZZ zzz, e.g. 2022-11-14 13:16:18.946 +0000 UTC) |
updated_at | String | The timestamp of the tx update (yyyy-MM-dd HH:mm:ss.SSS ZZZZ zzz, e.g. 2022-11-14 13:16:18.946 +0000 UTC) |
PeggyWithdrawals
Get info on peggy withdrawals.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
sender = "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku"
limit = 2
pagination = PaginationOption(limit=limit)
peggy_deposits = await client.fetch_peggy_withdrawal_txs(sender=sender, pagination=pagination)
print(peggy_deposits)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
explorerPB "github.com/InjectiveLabs/sdk-go/exchange/explorer_rpc/pb"
"github.com/InjectiveLabs/sdk-go/client/common"
explorerclient "github.com/InjectiveLabs/sdk-go/client/explorer"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
explorerClient, err := explorerclient.NewExplorerClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
sender := "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku"
req := explorerPB.GetPeggyWithdrawalTxsRequest{
Sender: sender,
}
res, err := explorerClient.GetPeggyWithdrawals(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | Filter by sender address | No |
receiver | String | Filter by receiver address | No |
pagination | PaginationOption | Pagination configuration | No |
Response Parameters
Response Example:
{
"field":[
{
"sender":"inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"receiver":"0xAF79152AC5dF276D9A8e1E2E22822f9713474902",
"amount":"1424956871765382404",
"denom":"inj",
"bridgeFee":"575043128234617596",
"outgoingTxId":"1136",
"batchTimeout":"10125614",
"batchNonce":"1600",
"orchestratorAddress":"inj1c8rpu79mr70hqsgzutdd6rhvzhej9vntm6fqku",
"state":"Cancelled",
"txHashes":[
"0x0d9a7e280898b4452a4cd283c0447ea36d9f09f223d9812f64bbd694851dec8c",
"0x9a456aa20d613c2cd646cbfff0b77c49e746757c24352e967578cd6e86ad62e1",
"0x6ad03f12df86ead8efe52b1aecc35a4527c548283a901c71d6ca731a5bcf0a71",
"0x8cb343b8ec48de5b30c9825156e29ab649570f15a8d1b4a4c850d736d99a670e",
"0x9830d597d9ef2e60fa0c161cb0f39528e3d589c52bf365bf6971369025ce55ee",
"0xa955975323aac3a3ad52adc45379a6ce19ec4d91f661265521a55139b2a6ad8d",
"0x15dfa29c3f0e888b808b488c02f4596bbd6d30d566ddcf12fb80f658e6e2bc50",
"0x016df0af7326ea14160f8f6d233578c9dfdecc9568b5b464deb80584ea00d652",
"0xcf07704ba6ddf1ee4cdda30c594098ec7d4826fffc4a32891f76d1f632de5f61",
"0xc6198363885fda70ec365020a99df9ba9b0a6dc880d7b83e956e7441c1cd8824",
"0x25081d4593dc0f31c7e7465d2fbdb4f68289cd64b47968f532038085f9013ace",
"0x684b59d4cd779d1333b9f2cfa5db1a28ed5ba6a9be3b96fa63aa0cf6577ade0e"
],
"createdAt":"2023-11-09 07:37:31.258 +0000 UTC",
"updatedAt":"2023-11-28 16:59:17.646 +0000 UTC",
"eventNonce":"0",
"eventHeight":"0",
"claimType":0
},
{
"sender":"inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"receiver":"0xAF79152AC5dF276D9A8e1E2E22822f9713474902",
"amount":"19254843517138599106",
"denom":"inj",
"bridgeFee":"745156482861400894",
"outgoingTxId":"912",
"batchTimeout":"10125613",
"batchNonce":"1598",
"orchestratorAddress":"inj1qu62yv9xutqgeqms7gzvdnay5j5lph2j2e4q5h",
"state":"Cancelled",
"txHashes":[
"0x1fc11c1db466716ad08237ec13128dead7a5edc2324a2d10eede9c45fd1789bc",
"0x747b809a56f1e2f9065378df6f46a9e2d725f04ccf505608756aa41a73551235",
"0x06db2f347054b394a70326314c04c2421757960a5b23724ec40cd84cc27ce44c",
"0x3c36a54a326ad9eb37ccfb2b8d8db72f3d2b5bdbc8d3693bf202ce98b315bdd8",
"0x7a2df716dae67e1fe9acbb336beda22882e92dc60836d19396305f9f03d34530",
"0xe31b3b5cabdae870a4c93d15cadfa6ac173e7d60ee2f021f4a047d4523bf7481",
"0x9d8d67e82d9f54477ca31e339643fc18b655fb24a9ebaa122400f49c5737df5e",
"0xa9039fee3b119f27fb0e733d8cfe2f9e96af51802a6a4088af3a5cabb1fb6de8",
"0x77d86350929b7cf6f4fe0094365bb71e9dc36a3e089a6af961cf05a153b54ade",
"0x3846355740bcfa46d7ac9092e9065df0a7f232f2736ac05a09fff69ee32314f2",
"0x86771d5fef383f8e256196d50ab62843aba63f3d23d3190f99cb882bcdaa45c9",
"0x27c712e45ec0458c9a39cf031d3d5de2d1ba1ef8833528062508a1ef0a02e64b",
"0x534fe5777662f31d098f6a5da2a73efc553a8fa81010da319162b7673062a90c",
"0xaafcd570b535ecc063573a94e9dd58dfcfcb0f30853945aa79e64fccc5907688",
"0x58258c46c3a674051e8c74c75ebe234942f85dacbeaba57c95ead9fa41b6d3a8",
"0xa434119dd2e647db048cfad61f3b97feef6008c38e68d7c574a6153b41dd49fe"
],
"createdAt":"2023-10-27 16:18:16.23 +0000 UTC",
"updatedAt":"2023-11-28 16:59:04.777 +0000 UTC",
"eventNonce":"0",
"eventHeight":"0",
"claimType":0
}
]
}
{
"field": [
{
"sender": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"receiver": "0xAF79152AC5dF276D9A8e1E2E22822f9713474902",
"amount": "5000000000000000000",
"denom": "inj",
"bridge_fee": "2000000000000000000",
"outgoing_tx_id": 113,
"state": "InjectiveConfirming",
"tx_hashes": [
"0x391ab87558318bd7ff2ccb9d68ed309ad073fa64c8395a493d6c347ff572af38"
],
"created_at": "2022-05-13 16:14:16.912 +0000 UTC",
"updated_at": "0001-01-01 00:00:00 +0000 UTC"
},
{
"sender": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
"receiver": "0xAF79152AC5dF276D9A8e1E2E22822f9713474902",
"amount": "23000000000000000000",
"denom": "inj",
"bridge_fee": "3546099290780142080",
"outgoing_tx_id": 110,
"state": "InjectiveConfirming",
"tx_hashes": [
"0x088975b8a12119944a254f0e4d7659df4c2b9c85c2c110305393f83be4f7f6ed"
],
"created_at": "2022-05-11 10:32:20.19 +0000 UTC",
"updated_at": "0001-01-01 00:00:00 +0000 UTC"
}
]
}
Parameter | Type | Description |
---|---|---|
field | PeggyWithdrawalTx Array | List of peggy withdrawals |
PeggyWithdrawalTx
Parameter | Type | Description |
---|---|---|
sender | String | The sender address |
receiver | String | The receiver address |
amount | String | The amount withdrawn |
denom | Integer | The token denom |
bridge_fee | String | The bridge fee |
outgoing_tx_id | Integer | The tx nonce |
batch_timeout | Integer | The timestamp after which batch request will be discarded if not processed already |
BatchNonce | Integer | An auto incremented unique ID representing the Withdrawal Batches |
orchestrator_address | String | Address that created batch request |
event_nonce | Integer | The event nonce of WithdrawalClaim event emitted by Ethereum chain upon batch withdrawal |
event_height | Integer | The block height of WithdrawalClaim event emitted by Ethereum chain upon batch withdrawal |
state | String | Transaction state |
claim_type | Integer | Claim type of the transaction, always equal to 2 |
tx_hashes | String Array | List of transaction hashes |
created_at | Integer | The timestamp of the tx creation (yyyy-MM-dd HH:mm:ss.SSS ZZZZ zzz, e.g. 2022-11-14 13:16:18.946 +0000 UTC) |
updated_at | String | The timestamp of the tx update (yyyy-MM-dd HH:mm:ss.SSS ZZZZ zzz, e.g. 2022-11-14 13:16:18.946 +0000 UTC) |
IBCTransfers
Get data on IBC transfers.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
sender = "inj1cll5cv3ezgal30gagkhnq2um6zf6qrmhw4r6c8"
receiver = "cosmos1usr9g5a4s2qrwl63sdjtrs2qd4a7huh622pg82"
src_channel = "channel-2"
src_port = "transfer"
destination_channel = "channel-30"
dest_port = "transfer"
limit = 1
skip = 10
pagination = PaginationOption(limit=limit, skip=skip)
ibc_transfers = await client.fetch_ibc_transfer_txs(
sender=sender,
receiver=receiver,
src_channel=src_channel,
src_port=src_port,
dest_channel=destination_channel,
dest_port=dest_port,
pagination=pagination,
)
print(ibc_transfers)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
explorerPB "github.com/InjectiveLabs/sdk-go/exchange/explorer_rpc/pb"
"github.com/InjectiveLabs/sdk-go/client/common"
explorerclient "github.com/InjectiveLabs/sdk-go/client/explorer"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
explorerClient, err := explorerclient.NewExplorerClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
receiver := "inj1ddcp5ftqmntudn4m6heg2adud6hn58urnwlmkh"
req := explorerPB.GetIBCTransferTxsRequest{
Receiver: receiver,
}
res, err := explorerClient.GetIBCTransfers(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | Filter transfers based on sender address | No |
receiver | String | Filter transfers based on receiver address | No |
src_channel | String | Filter transfers based on source channel | No |
src_port | String | Filter transfers based on source port | No |
dest_channel | String | Filter transfers based on destination channel | No |
dest_port | String | Filter transfers based on destination port | No |
pagination | PaginationOption | Pagination configuration | No |
Response Parameters
Response Example:
{
"field":[
{
"sender":"inj14nendtsz0c40n7xtzwkjmdc8dkuz835jdydxhn",
"receiver":"nois1mvuupgre7pjx3k5tm5729frkn9nvju6pgsxawc47pgamctypdzlsm7hg90",
"sourcePort":"transfer",
"sourceChannel":"channel-74",
"destinationPort":"transfer",
"destinationChannel":"channel-33",
"amount":"1000000",
"denom":"transfer/channel-74/unois",
"timeoutHeight":"0-0",
"timeoutTimestamp":"1702124625185146392",
"packetSequence":"20509",
"dataHex":"N2IyMjYxNmQ2Zjc1NmU3NDIyM2EyMjMxMzAzMDMwMzAzMDMwMjIyYzIyNjQ2NTZlNmY2ZDIyM2EyMjc0NzI2MTZlNzM2NjY1NzIyZjYzNjg2MTZlNmU2NTZjMmQzNzM0MmY3NTZlNmY2OTczMjIyYzIyNzI2NTYzNjU2OTc2NjU3MjIyM2EyMjZlNmY2OTczMzE2ZDc2NzU3NTcwNjc3MjY1Mzc3MDZhNzgzMzZiMzU3NDZkMzUzNzMyMzk2NjcyNmI2ZTM5NmU3NjZhNzUzNjcwNjc3Mzc4NjE3NzYzMzQzNzcwNjc2MTZkNjM3NDc5NzA2NDdhNmM3MzZkMzc2ODY3MzkzMDIyMmMyMjczNjU2ZTY0NjU3MjIyM2EyMjY5NmU2YTMxMzQ2ZTY1NmU2NDc0NzM3YTMwNjMzNDMwNmUzNzc4NzQ3YTc3NmI2YTZkNjQ2MzM4NjQ2Yjc1N2EzODMzMzU2YTY0Nzk2NDc4Njg2ZTIyN2Q=",
"state":"Completed",
"txHashes":[
"0x3bf678143df5202cb9646e3d449978d385aff8d7b7e8cd5b1e1442163816d609",
"0x5abaf2ac5afd669c5cf5b8e22eceb211f6a334510dc58a5766d66848eede9407"
],
"createdAt":"2023-12-08 12:23:45.185 +0000 UTC",
"updatedAt":"2023-12-08 12:23:58.769 +0000 UTC"
}
]
}
{
"field": [
{
"sender": "terra1nrgj0e5l98y07zuenvnpa76x8e5dmm4cdkppws",
"receiver": "inj1ddcp5ftqmntudn4m6heg2adud6hn58urnwlmkh",
"source_port": "transfer",
"source_channel": "channel-17",
"destination_port": "transfer",
"destination_channel": "channel-4",
"amount": "10000000000",
"denom": "uusd",
"timeout_height": "5-7072846",
"timeout_timestamp": 1648784773000000000,
"packet_sequence": 1892,
"data_hex": "N2IyMjYxNmQ2Zjc1NmU3NDIyM2EyMjMxMzAzMDMwMzAzMDMwMzAzMDMwMzAyMjJjMjI2NDY1NmU2ZjZkMjIzYTIyNzU3NTczNjQyMjJjMjI3MjY1NjM2NTY5NzY2NTcyMjIzYTIyNjk2ZTZhMzE2NDY0NjM3MDM1NjY3NDcxNmQ2ZTc0NzU2NDZlMzQ2ZDM2Njg2NTY3MzI2MTY0NzU2NDM2Njg2ZTM1Mzg3NTcyNmU3NzZjNmQ2YjY4MjIyYzIyNzM2NTZlNjQ2NTcyMjIzYTIyNzQ2NTcyNzI2MTMxNmU3MjY3NmEzMDY1MzU2YzM5Mzg3OTMwMzc3YTc1NjU2ZTc2NmU3MDYxMzczNjc4Mzg2NTM1NjQ2ZDZkMzQ2MzY0NmI3MDcwNzc3MzIyN2Q=",
"state": "Completed",
"tx_hashes": [
"0xf52d55dd6b68d78d137d4e5526a450d74689d3cba7f69640acd41b68ee26cd15"
],
"created_at": "2022-04-01 03:45:39.338 +0000 UTC",
"updated_at": "2022-04-01 03:45:39.338 +0000 UTC"
},
{
"sender": "terra1nrgj0e5l98y07zuenvnpa76x8e5dmm4cdkppws",
"receiver": "inj1ddcp5ftqmntudn4m6heg2adud6hn58urnwlmkh",
"source_port": "transfer",
"source_channel": "channel-17",
"destination_port": "transfer",
"destination_channel": "channel-4",
"amount": "200000000",
"denom": "uluna",
"timeout_height": "5-6753065",
"timeout_timestamp": 1646665141000000000,
"packet_sequence": 1516,
"data_hex": "N2IyMjYxNmQ2Zjc1NmU3NDIyM2EyMjMyMzAzMDMwMzAzMDMwMzAzMDIyMmMyMjY0NjU2ZTZmNmQyMjNhMjI3NTZjNzU2ZTYxMjIyYzIyNzI2NTYzNjU2OTc2NjU3MjIyM2EyMjY5NmU2YTMxNjQ2NDYzNzAzNTY2NzQ3MTZkNmU3NDc1NjQ2ZTM0NmQzNjY4NjU2NzMyNjE2NDc1NjQzNjY4NmUzNTM4NzU3MjZlNzc2YzZkNmI2ODIyMmMyMjczNjU2ZTY0NjU3MjIyM2EyMjc0NjU3MjcyNjEzMTZlNzI2NzZhMzA2NTM1NmMzOTM4NzkzMDM3N2E3NTY1NmU3NjZlNzA2MTM3MzY3ODM4NjUzNTY0NmQ2ZDM0NjM2NDZiNzA3MDc3NzMyMjdk",
"state": "Completed",
"tx_hashes": [
"0xe5782979f08f7f939b6ed6f4687b70542295ef91f3de84a3e10c4044230f8474"
],
"created_at": "2022-03-07 14:58:31.905 +0000 UTC",
"updated_at": "2022-03-07 14:58:31.905 +0000 UTC"
}
]
}
Parameter | Type | Description |
---|---|---|
field | IBCTransferTx Array | List of IBC transfers |
IBCTransferTx
Parameter | Type | Description |
---|---|---|
sender | String | Sender address |
receiver | String | Receiver address |
source_channel | String | Source channel |
source_port | String | Source port |
destination_channel | String | Destination channel |
destination_port | String | Destination port |
amount | String | Transfer amount |
denom | String | Token denom |
timeout_height | Integer | Timeout height relative to the current block height. Timeout disabled if set to 0 |
timeout_timestamp | Integer | Timeout timestamp (in nanoseconds) relative to the current block timestamp |
packet_sequence | String | Corresponds to the order of sends and receives, where a Packet with an earlier sequence number must be sent and received before a Packet with a later sequence number |
data_hex | String | IBC request data in hex format |
state | String | Transaction state |
tx_hashes | String Array | List of transaction hashes |
created_at | Integer | The timestamp of the tx creation (yyyy-MM-dd HH:mm:ss.SSS ZZZZ zzz, e.g. 2022-11-14 13:16:18.946 +0000 UTC) |
updated_at | String | The timestamp of the tx update (yyyy-MM-dd HH:mm:ss.SSS ZZZZ zzz, e.g. 2022-11-14 13:16:18.946 +0000 UTC) |
GetWasmCodes
List all cosmwasm code on injective chain. Results are paginated.
IP rate limit group: indexer
Request Example:
package main
import (
"context"
"encoding/json"
"fmt"
explorerPB "github.com/InjectiveLabs/sdk-go/exchange/explorer_rpc/pb"
"github.com/InjectiveLabs/sdk-go/client/common"
explorerclient "github.com/InjectiveLabs/sdk-go/client/explorer"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
explorerClient, err := explorerclient.NewExplorerClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
req := explorerPB.GetWasmCodesRequest{
Limit: 10,
}
res, err := explorerClient.GetWasmCodes(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Response Example:
{
"paging": {
"total": 501,
"from": 497,
"to": 501
},
"data": [
{
"code_id": 501,
"tx_hash": "0x6f218f72f68b3c90e578c1b1fad735f8016fc9b3618664ceb301234f2725d218",
"checksum": {
"algorithm": "sha256",
"hash": "0x4f6e56bbbe7ebec55f7e9d49c4a6e534f57ba3402c0282c1c3ec1aac83753ccf"
},
"created_at": 1677495117914,
"permission": {
"access_type": 3
},
"creator": "inj13dyu3ukelncq95s7dqhg6crqvjursramcazkka",
"code_number": 515
},
{
"code_id": 500,
"tx_hash": "0x9a8035a3cd85651b7266f813f3dd909772a7cec5ca0b4f9266832d50c85921b8",
"checksum": {
"algorithm": "sha256",
"hash": "0xdcaa8a03707966ebfedbb927f755fabf9e7f095663f4b9f45a5b437a8276ea0f"
},
"created_at": 1677495084552,
"permission": {
"access_type": 3
},
"creator": "inj13dyu3ukelncq95s7dqhg6crqvjursramcazkka",
"code_number": 514
},
{
"code_id": 499,
"tx_hash": "0x3809b1b61e218144c4f50e0a61b6ae89f8942cbe7cadfe67e23127c70949a3f1",
"checksum": {
"algorithm": "sha256",
"hash": "0xdbef810fdc577f4e983620b16eccafdf359e924af0752a13820bf679b260ffe1"
},
"created_at": 1677495060759,
"permission": {
"access_type": 3
},
"creator": "inj13dyu3ukelncq95s7dqhg6crqvjursramcazkka",
"code_number": 513
},
{
"code_id": 498,
"tx_hash": "0x9c5a44981506fe7658fa38b2bd63ddd20717842433ce75eba60cb2d7ca548b54",
"checksum": {
"algorithm": "sha256",
"hash": "0xe17581873943e1fe3671bfca9a3360398be10a28245fc0d5c55403f64808019c"
},
"created_at": 1677495034788,
"permission": {
"access_type": 3
},
"creator": "inj13dyu3ukelncq95s7dqhg6crqvjursramcazkka",
"code_number": 512
},
{
"code_id": 497,
"tx_hash": "0xeaa3d642a049d0b09920bacf7989a2371ecf43ec20bb5d6dbb3b54326cec63e7",
"checksum": {
"algorithm": "sha256",
"hash": "0x1a1278f43c03e9ed12ba9c1995bae8ea1554cf67a38e9eedd97e9cd61a3e411d"
},
"created_at": 1677495006505,
"permission": {
"access_type": 3
},
"creator": "inj13dyu3ukelncq95s7dqhg6crqvjursramcazkka",
"code_number": 511
}
]
}
Request Parameters
Parameter | Type | Description | Required |
---|---|---|---|
limit | Integer | Limit number of codes to return | No |
from_number | Integer | List all codes whose number (code_id) is not lower than from_number | No |
to_number | Integer | List all codes whose number (code_id) is not greater than to_number | No |
Response Parameters
Parameter | Type | Description |
---|---|---|
paging | Paging | Pagination of results |
data | WasmCode Array | List of WasmCodes, after applying filters |
Paging
Parameter | Type | Description |
---|---|---|
total | Integer | Total number of records available |
WasmCode
Parameter | Type | Description |
---|---|---|
code_id | Integer | ID of stored wasm code, sorted in descending order |
tx_hash | String | Tx hash of store code transaction |
checksum | Checksum | Checksum of the cosmwasm code |
created_at | Integer | Block time when the code is stored, in millisecond |
contract_type | String | Contract type of the wasm code |
version | String | Version of the wasm code |
permission | ContractPermission | Describes instantiation permissions |
code_schema | String | Code schema preview (to be supported) |
code_view | String | Code repo preview, may contain schema folder (to be supported) |
instantiates | Integer | Number of contract instantiations from this code |
creator | String | Creator of this code |
code_number | Integer | Monotonic order of the code stored |
proposal_id | Integer | ID of the proposal that store this code |
ContractPermission
Parameter | Type | Description |
---|---|---|
access_type | Integer | Access type of instantiation |
address | Integer | Account address |
Checksum
Parameter | Type | Description |
---|---|---|
algorithm | String | Hash function algorithm |
hash | String | Hash of the cosmwasm bytecode |
GetWasmCodeByID
Get cosmwasm code by its code ID
IP rate limit group: indexer
Request Example:
package main
import (
"context"
"encoding/json"
"fmt"
explorerPB "github.com/InjectiveLabs/sdk-go/exchange/explorer_rpc/pb"
"github.com/InjectiveLabs/sdk-go/client/common"
explorerclient "github.com/InjectiveLabs/sdk-go/client/explorer"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
explorerClient, err := explorerclient.NewExplorerClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
req := explorerPB.GetWasmCodeByIDRequest{
CodeId: 10,
}
res, err := explorerClient.GetWasmCodeByID(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Response Example:
{
"code_id": 10,
"tx_hash": "0x476b1988ba0ea020a337b92f46afefde8af2ac9e72934a1b9882673b3926388c",
"checksum": {
"algorithm": "sha256",
"hash": "0xdba30bcea6d5997c00a7922b475e42f172e72b8ef6ad522c09bc1868bc6caff4"
},
"created_at": 1658305428842,
"instantiates": 4,
"creator": "inj10hpqmlskky8azz5qca20xau2ppf3x23jsh9k8r",
"code_number": 10
}
Request Parameters
Parameter | Type | Description | Required |
---|---|---|---|
code_id | Integer | ID of the code | Yes |
Response Parameters
Parameter | Type | Description |
---|---|---|
code_id | Integer | ID of stored wasm code, sorted in descending order |
tx_hash | String | Tx hash of store code transaction |
checksum | Checksum | Checksum of the cosmwasm code |
created_at | Integer | Block time when the code is stored, in millisecond |
contract_type | String | Contract type of the wasm code |
version | String | Version of the wasm code |
permission | ContractPermission | Describes instantiation permissions |
code_schema | String | Code schema preview (to be supported) |
code_view | String | Code repo preview, may contain schema folder (to be supported) |
instantiates | Integer | Number of contract instantiations from this code |
creator | String | Creator of this code |
code_number | Integer | Monotonic order of the code stored |
proposal_id | Integer | ID of the proposal that store this code |
ContractPermission
Parameter | Type | Description |
---|---|---|
access_type | Integer | Access type of instantiation |
address | Integer | Account address |
Checksum
Parameter | Type | Description |
---|---|---|
algorithm | String | Hash function algorithm |
hash | String | Hash of the cosmwasm bytecode |
GetWasmContracts
Get cosmwasm instantiated contracts on injective-chain. Results are paginated.
IP rate limit group: indexer
Request Example:
package main
import (
"context"
"encoding/json"
"fmt"
explorerPB "github.com/InjectiveLabs/sdk-go/exchange/explorer_rpc/pb"
"github.com/InjectiveLabs/sdk-go/client/common"
explorerclient "github.com/InjectiveLabs/sdk-go/client/explorer"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
explorerClient, err := explorerclient.NewExplorerClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
req := explorerPB.GetWasmContractsRequest{}
res, err := explorerClient.GetWasmContracts(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Response Example:
{
"paging": {
"total": 529,
"from": 1,
"to": 5
},
"data": [
{
"label": "Instantiation",
"address": "inj138nnvqqx4t49n6u8r7d8g6h2ek3kpztk3s4svy",
"tx_hash": "0xdc1c7dc4bb47710b22894def0c4fa12d2d86d9d3d6e3ed3a348d83e9052ea7c2",
"creator": "inj1rhsl5eld5qg7qe2w2nretw6s6xnwdpaju3rp5j",
"instantiated_at": 1677520960574,
"init_message": "{\"app_components\":[],\"name\":\"First Aoo\",\"primitive_contract\":\"inj1hsrl44l3gm5p52r26nx89g9tpptacuy755y6yd\"}",
"last_executed_at": 1677520960574,
"code_id": 481,
"admin": "inj1rhsl5eld5qg7qe2w2nretw6s6xnwdpaju3rp5j",
"contract_number": 529,
"version": "0.1.0",
"type": "crates.io:andromeda-app-contract"
},
{
"label": "CounterTestInstance",
"address": "inj1xd48d9fs7rmh9rhf36fj69mw8yxplnq66m3gxq",
"tx_hash": "0x05f44c2dd194a41a7e4606d350d85bd49cf59597dbb63681eaf97e51416a2df2",
"creator": "inj1kpps36y8c5qm9axr5w3v3ukqtth99pq40ga84e",
"executes": 1,
"instantiated_at": 1677252138256,
"init_message": "{\"count\":99}",
"last_executed_at": 1677255965387,
"code_id": 476,
"contract_number": 528,
"version": "0.1.0",
"type": "crates.io:cw-counter"
},
{
"label": "Wormhole Wrapped CW20",
"address": "inj1m4g54lg2mhhm7a4h3ms5xlyecafhe4macgsuen",
"tx_hash": "0xce9b5b713da1b1b0e48d1b5451769ba80ca905145a90c704d01221986083c2d8",
"creator": "inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh",
"instantiated_at": 1677179269211,
"init_message": "{\"name\":\"QAT\",\"symbol\":\"QAT\",\"asset_chain\":2,\"asset_address\":\"AAAAAAAAAAAAAAAAGQLhj+sSNNANiA8frKXI106FAek=\",\"decimals\":8,\"mint\":null,\"init_hook\":{\"msg\":\"eyJyZWdpc3Rlcl9hc3NldF9ob29rIjp7ImNoYWluIjoyLCJ0b2tlbl9hZGRyZXNzIjp7ImJ5dGVzIjpbMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMjUsMiwyMjUsMTQzLDIzNSwxOCw1MiwyMDgsMTMsMTM2LDE1LDMxLDE3MiwxNjUsMjAwLDIxNSw3OCwxMzMsMSwyMzNdfX19\",\"contract_addr\":\"inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh\"}}",
"last_executed_at": 1677179269211,
"code_id": 14,
"admin": "inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh",
"contract_number": 527,
"version": "0.1.0",
"type": "crates.io:cw20-base",
"cw20_metadata": {
"token_info": {
"name": "QAT (Wormhole)",
"symbol": "QAT",
"decimals": 8,
"total_supply": "0"
}
}
},
{
"label": "xAccount Registry",
"address": "inj1s4alfevl7u84v7c3klh2flv6fw95s3q08eje53",
"tx_hash": "0xad817a8a4fcef1c36f8c5535b5598a4bc2ddc069f8a60634438dae90a242efed",
"creator": "inj1dc6rrxhfjaxexzdcrec5w3ryl4jn6x5t7t9j3z",
"instantiated_at": 1677176719385,
"init_message": "{\"wormhole_id_here\":19,\"wormhole_core_contract\":\"inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg\",\"factory_code_id\":474,\"x_account_code_id\":475,\"vm_id_here\":1}",
"last_executed_at": 1677176719385,
"code_id": 473,
"admin": "inj1dc6rrxhfjaxexzdcrec5w3ryl4jn6x5t7t9j3z",
"contract_number": 526
},
{
"label": "xAccount Deployer",
"address": "inj1a0s058avjct43t7cwn7rfvmxt2p37v29xladv8",
"tx_hash": "0xad817a8a4fcef1c36f8c5535b5598a4bc2ddc069f8a60634438dae90a242efed",
"creator": "inj1s4alfevl7u84v7c3klh2flv6fw95s3q08eje53",
"instantiated_at": 1677176719385,
"init_message": "{\"x_account_registry\":\"inj1s4alfevl7u84v7c3klh2flv6fw95s3q08eje53\",\"commanders\":[{\"wormhole_id\":19,\"address_byte_length\":20,\"address\":\"AAAAAAAAAAAAAAAAQjjjD/fOAVOq8xb1O7rhomqGArc=\"}]}",
"last_executed_at": 1677176719385,
"code_id": 475,
"admin": "inj1gguwxrlhecq482hnzm6nhwhp5f4gvq4hmxpn7p",
"contract_number": 525
}
]
}
Request Parameters
Parameter | Type | Description | Required |
---|---|---|---|
limit | Integer | Max number of items to be returned, defaults to 100 | No |
code_id | Integer | Contract's code ID to be filtered | No |
from_number | Integer | List all contracts whose number is not lower than from_number | No |
to_number | Integer | List all contracts whose number is not greater than to_number | No |
assets_only | Boolean | Filter only CW20 contracts | No |
skip | Integer | Skip the first n cosmwasm contracts. This can be used to fetch all results since the API caps at 100 | No |
Response Parameters
Parameter | Type | Description |
---|---|---|
paging | Paging | Pagination of results |
data | WasmContract Array | List of WasmContracts after filtering |
Paging
Parameter | Type | Description |
---|---|---|
total | Integer | Total number of records available |
WasmContract
Parameter | Type | Description |
---|---|---|
label | String | General name of the contract |
address | String | Address of the contract |
tx_hash | String | Hash of the instantiate transaction |
creator | String | Address of the contract creator |
executes | Integer | Number of times call to execute contract |
instantiated_at | Integer | Block timestamp that contract was instantiated, in UNIX millis |
init_message | String | Init message when this contract was instantiated |
last_executed_at | Integer | Block timestamp that contract was last called, in UNIX millis |
funds | ContractFund Array | List of contract funds |
code_id | Integer | Code ID of the contract |
admin | String | Admin of the contract |
current_migrate_message | String | Latest migrate message of the contract |
contract_number | Integer | Monotonic contract number in database |
version | String | Contract version |
type | String | Contract type |
cw20_metadata | Cw20Metadata | Metadata of the CW20 contract |
proposal_id | Integer | ID of the proposal that instantiates this contract |
ContractFund
Parameter | Type | Description |
---|---|---|
denom | String | Denominator |
amount | String | Amount of denom |
Cw20Metadata
Parameter | Type | Description |
---|---|---|
token_info | Cw20TokenInfo | CW20 token info structure |
marketing_info | Cw20MarketingInfo | Marketing info structure |
Cw20TokenInfo
Parameter | Type | Description |
---|---|---|
name | String | General name of the token |
symbol | String | Symbol of the token |
decimals | Integer | Decimal places of token |
Cw20MarketingInfo
Parameter | Type | Description |
---|---|---|
project | String | Project information |
description | String | Token's description |
logo | String | Logo (url/embedded) |
marketing | Bytes Array | Address that can update the contract's marketing info |
GetWasmContractByAddress
Get cosmwasm contract by its address
IP rate limit group: indexer
Request Example:
package main
import (
"context"
"encoding/json"
"fmt"
explorerPB "github.com/InjectiveLabs/sdk-go/exchange/explorer_rpc/pb"
"github.com/InjectiveLabs/sdk-go/client/common"
explorerclient "github.com/InjectiveLabs/sdk-go/client/explorer"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
explorerClient, err := explorerclient.NewExplorerClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
req := explorerPB.GetWasmContractByAddressRequest{
ContractAddress: "inj1ru9nhdjtjtz8u8wrwxmcl9zsns4fh2838yr5ga",
}
res, err := explorerClient.GetWasmContractByAddress(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Response Example:
{
"label": "xAccount Registry",
"address": "inj1ru9nhdjtjtz8u8wrwxmcl9zsns4fh2838yr5ga",
"tx_hash": "0x7dbc4177ef6253b6cfb33c0345e023eec3a6603aa615fa836271d2f3743e33fb",
"creator": "inj1dc6rrxhfjaxexzdcrec5w3ryl4jn6x5t7t9j3z",
"executes": 6,
"instantiated_at": 1676450262441,
"init_message": "{\"wormhole_id_here\":19,\"wormhole_core_contract\":\"inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg\",\"factory_code_id\":422,\"x_account_code_id\":421,\"vm_id_here\":1}",
"last_executed_at": 1676464935254,
"code_id": 420,
"admin": "inj1dc6rrxhfjaxexzdcrec5w3ryl4jn6x5t7t9j3z",
"contract_number": 430
}
Request Parameters
Parameter | Type | Description | Required |
---|---|---|---|
contract_address | String | Contract address | Yes |
Response Parameters
Parameter | Type | Description |
---|---|---|
label | String | General name of the contract |
address | String | Address of the contract |
tx_hash | String | Hash of the instantiate transaction |
creator | String | Address of the contract creator |
executes | Integer | Number of times call to execute contract |
instantiated_at | Integer | Block timestamp that contract was instantiated, in UNIX millis |
init_message | String | Init message when this contract was instantiated |
last_executed_at | Integer | Block timestamp that contract was last called, in UNIX millis |
funds | ContractFund Array | List of contract funds |
code_id | Integer | Code ID of the contract |
admin | String | Admin of the contract |
current_migrate_message | String | Latest migrate message of the contract |
contract_number | Integer | Monotonic contract number in database |
version | String | Contract version |
type | String | Contract type |
cw20_metadata | Cw20Metadata | Metadata of the CW20 contract |
proposal_id | Integer | ID of the proposal that instantiates this contract |
ContractFund
Parameter | Type | Description |
---|---|---|
denom | String | Denominator |
amount | String | Amount of denom |
Cw20Metadata
Parameter | Type | Description |
---|---|---|
token_info | Cw20TokenInfo | CW20 token info structure |
marketing_info | Cw20MarketingInfo | Marketing info structure |
Cw20TokenInfo
Parameter | Type | Description |
---|---|---|
name | String | General name of the token |
symbol | String | Symbol of the token |
decimals | Integer | Decimal places of token |
Cw20MarketingInfo
Parameter | Type | Description |
---|---|---|
project | String | Project information |
description | String | Token's description |
logo | String | Logo (url/embedded) |
marketing | Bytes Array | Address that can update the contract's marketing info |
GetCw20Balance
Get CW20 balances of an injective account across all instantiated CW20 contracts
IP rate limit group: indexer
Request Example:
package main
import (
"context"
"encoding/json"
"fmt"
explorerPB "github.com/InjectiveLabs/sdk-go/exchange/explorer_rpc/pb"
"github.com/InjectiveLabs/sdk-go/client/common"
explorerclient "github.com/InjectiveLabs/sdk-go/client/explorer"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
explorerClient, err := explorerclient.NewExplorerClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
req := explorerPB.GetCw20BalanceRequest{
Address: "inj1dc6rrxhfjaxexzdcrec5w3ryl4jn6x5t7t9j3z",
}
res, err := explorerClient.GetCW20Balance(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Response Example:
{
"field": [
{
"contract_address": "inj1v6p2u2pgk9qdcf3ussudszjetqwjaj6l89ce0k",
"account": "inj1dc6rrxhfjaxexzdcrec5w3ryl4jn6x5t7t9j3z",
"balance": "10000000000000000",
"updated_at": 1666153787458,
"cw20_metadata": {
"token_info": {
"name": "test coin",
"symbol": "TEST",
"decimals": 6,
"total_supply": "10000000000000000"
},
"marketing_info": {
"marketing": "bnVsbA=="
}
}
}
]
}
Request Parameters
Parameter | Type | Description | Required |
---|---|---|---|
address | String | Address to list balance of | Yes |
limit | Integer | Limit number of balances to return | No |
Response Parameters
Parameter | Type | Description |
---|---|---|
Parameter | WasmCw20Balance Array | CW20 balance array |
WasmCw20Balance
Parameter | Type | Description |
---|---|---|
contract_address | String | Address of CW20 contract |
account | String | Account address |
balance | String | Account balance |
updated_at | Integer | Update timestamp in UNIX millis |
cw20_metadata | Cw20Metadata | Metadata of the CW20 contract |
Cw20Metadata
Parameter | Type | Description |
---|---|---|
token_info | Cw20TokenInfo | CW20 token info |
marketing_info | Cw20MarketingInfo | Marketing info |
Cw20TokenInfo
Parameter | Type | Description |
---|---|---|
name | String | General name of the token |
symbol | String | Symbol of the token |
decimals | Integer | Decimal places of token |
Cw20MarketingInfo
Parameter | Type | Description |
---|---|---|
project | String | Project information |
description | String | Token's description |
logo | String | Logo (url/embedded) |
marketing | Bytes Array | Address that can update the contract's marketing info |
- InjectiveMetaRPC
InjectiveMetaRPC defines the gRPC API of the Exchange Meta provider.
Ping
Get the server health.
IP rate limit group: indexer
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
resp = await client.fetch_ping()
print("Health OK?", resp)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
metaPB "github.com/InjectiveLabs/sdk-go/exchange/meta_rpc/pb"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
req := metaPB.PingRequest{}
res, err := exchangeClient.Ping(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Response Example:
Health OK?
Health OK?{}
Version
Get the server version.
IP rate limit group: indexer
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
resp = await client.fetch_version()
print("Version:", resp)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
metaPB "github.com/InjectiveLabs/sdk-go/exchange/meta_rpc/pb"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
req := metaPB.VersionRequest{}
res, err := exchangeClient.GetVersion(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Response Parameters
Response Example:
{
"version":"v1.12.46-rc1",
"build":{
"BuildDate":"20231110-0736",
"GitCommit":"2b326fe",
"GoVersion":"go1.20.5",
"GoArch":"amd64"
}
}
{
"version": "dev",
"build": {
"BuildDate": "20220426-0810",
"GitCommit": "4f3bc09",
"GoArch": "amd64",
"GoVersion": "go1.17.3"
}
}
Parameter | Type | Description |
---|---|---|
version | String | injective-exchange code version |
build | VersionResponse.BuildEntry Array | Additional build meta info |
VersionResponse.BuildEntry
Parameter | Type | Description |
---|---|---|
key | String | Name |
value | String | Description |
Info
Get the server information.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
import time
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
resp = await client.fetch_info()
print("[!] Info:")
print(resp)
latency = int(time.time() * 1000) - int(resp["timestamp"])
print(f"Server Latency: {latency}ms")
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
metaPB "github.com/InjectiveLabs/sdk-go/exchange/meta_rpc/pb"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
req := metaPB.InfoRequest{}
res, err := exchangeClient.GetInfo(ctx, &req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
timestamp | Integer | Your current system UNIX timestamp in millis | No, if using our async_client implementation, otherwise yes |
Response Parameters
Response Example:
{
"timestamp":"1702040535291",
"serverTime":"1702040536394",
"version":"v1.12.46-guilds-rc5",
"build":{
"BuildDate":"20231113-1523",
"GitCommit":"78a9ea2",
"GoVersion":"go1.20.5",
"GoArch":"amd64"
},
"region":""
}
Parameter | Type | Description |
---|---|---|
timestamp | Integer | The original timestamp (from your system) of the request in UNIX millis |
server_time | Integer | UNIX time on the server in millis |
version | String | injective-exchange code version |
build | VersionResponse.BuildEntry Array | Additional build meta info |
VersionResponse.BuildEntry
Parameter | Type | Description |
---|---|---|
key | String | Name |
value | String | Description |
StreamKeepAlive
Subscribe to a stream and gracefully disconnect and connect to another sentry node if the primary becomes unavailable.
IP rate limit group: indexer
Request Example:
import asyncio
from typing import Any, Dict
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
def stream_error_processor(exception: RpcError):
print(f"There was an error listening to keepalive updates ({exception})")
def stream_closed_processor():
print("The keepalive stream has been closed")
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
tasks = []
async def keepalive_event_processor(event: Dict[str, Any]):
print("Server announce:", event)
for task in tasks:
task.cancel()
print("Cancelled all tasks")
market_task = asyncio.get_event_loop().create_task(get_markets(client))
tasks.append(market_task)
keepalive_task = asyncio.get_event_loop().create_task(
client.listen_keepalive(
callback=keepalive_event_processor,
on_end_callback=stream_closed_processor,
on_status_callback=stream_error_processor,
)
)
try:
await asyncio.gather(market_task, keepalive_task)
except asyncio.CancelledError:
print("main(): get_markets is cancelled now")
async def get_markets(client):
async def print_market_updates(event: Dict[str, Any]):
print(event)
await client.listen_spot_markets_updates(
callback=print_market_updates,
on_end_callback=stream_closed_processor,
on_status_callback=stream_error_processor,
)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
stream, err := exchangeClient.StreamKeepalive(ctx)
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
return
default:
res, err := stream.Recv()
if err != nil {
fmt.Println(err)
return
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
}
}
Parameter | Type | Description | Required |
---|---|---|---|
callback | Function | Function receiving one parameter (a stream event JSON dictionary) to process each new event | Yes |
on_end_callback | Function | Function with the logic to execute when the stream connection is interrupted | No |
on_status_callback | Function | Function receiving one parameter (the exception) with the logic to execute when an exception happens | No |
Response Parameters
Response Example:
event: "shutdown",
timestamp: 1636236225847,
"Cancelled all tasks"
Parameter | Type | Description |
---|---|---|
event | String | Server event |
new_endpoint | String | New connection endpoint for the gRPC API |
timestamp | Integer | Operation timestamp in UNIX millis |
- InjectivePortfolioRPC
InjectivePortfolioRPC defines the gRPC API of the Exchange Portfolio provider.
AccountPortfolio
Get details about an account's portfolio.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
account_address = "inj1clw20s2uxeyxtam6f7m84vgae92s9eh7vygagt"
portfolio = await client.fetch_account_portfolio_balances(account_address=account_address)
print(portfolio)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
// select network: local, testnet, mainnet
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
accountAddress := "inj1clw20s2uxeyxtam6f7m84vgae92s9eh7vygagt"
res, err := exchangeClient.GetAccountPortfolioBalances(ctx, accountAddress)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
account_address | String | Address of the account to get portfolio for | Yes |
Response Parameters
Response Example:
{
"portfolio":{
"accountAddress":"inj1clw20s2uxeyxtam6f7m84vgae92s9eh7vygagt",
"bankBalances":[
{
"denom":"factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/atom",
"amount":"10000000000"
},
{
"denom":"factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/usdc",
"amount":"10000000000"
},
{
"denom":"factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/weth",
"amount":"5000000000"
},
{
"denom":"inj",
"amount":"9699395972014420000000"
},
{
"denom":"peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7",
"amount":"100000000000000000000"
},
{
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"amount":"18689670208"
}
],
"subaccounts":[
{
"subaccountId":"0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001",
"denom":"inj",
"deposit":{
"totalBalance":"11010001000000000000",
"availableBalance":"11010001000000000000"
}
},
{
"subaccountId":"0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001",
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"deposit":{
"totalBalance":"298666021.6838251182660625",
"availableBalance":"298666021.6838251182660625"
}
},
{
"subaccountId":"0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000002",
"denom":"inj",
"deposit":{
"totalBalance":"1000000000000",
"availableBalance":"1000000000000"
}
},
{
"subaccountId":"0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000000",
"denom":"inj",
"deposit":{
"totalBalance":"0.458458",
"availableBalance":"0.458458"
}
},
{
"subaccountId":"0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000000",
"denom":"peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7",
"deposit":{
"totalBalance":"0",
"availableBalance":"0"
}
},
{
"subaccountId":"0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000000",
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"deposit":{
"totalBalance":"0.170858923182467801",
"availableBalance":"0.170858923182467801"
}
}
]
}
}
{
"portfolio": {
"account_address": "inj1clw20s2uxeyxtam6f7m84vgae92s9eh7vygagt",
"bank_balances": [
{
"denom": "factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/atom",
"amount": "10000000000"
},
{
"denom": "factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/usdc",
"amount": "10000000000"
},
{
"denom": "factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/weth",
"amount": "5000000000"
},
{
"denom": "inj",
"amount": "9699395972014420000000"
},
{
"denom": "peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7",
"amount": "100000000000000000000"
},
{
"denom": "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"amount": "18689670208"
}
],
"subaccounts": [
{
"subaccount_id": "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000000",
"denom": "peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7",
"deposit": {
"total_balance": "0",
"available_balance": "0"
}
},
{
"subaccount_id": "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000000",
"denom": "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"deposit": {
"total_balance": "0.170858923182467801",
"available_balance": "0.170858923182467801"
}
},
{
"subaccount_id": "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000000",
"denom": "inj",
"deposit": {
"total_balance": "0.458458",
"available_balance": "0.458458"
}
},
{
"subaccount_id": "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001",
"denom": "inj",
"deposit": {
"total_balance": "11010001000000000000",
"available_balance": "11010001000000000000"
}
},
{
"subaccount_id": "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001",
"denom": "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"deposit": {
"total_balance": "298666021.6838251182660625",
"available_balance": "298666021.6838251182660625"
}
},
{
"subaccount_id": "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000002",
"denom": "inj",
"deposit": {
"total_balance": "1000000000000",
"available_balance": "1000000000000"
}
}
]
}
}
Parameter | Type | Description |
---|---|---|
portfolio | Portfolio | The portfolio of the account |
PortfolioBalances
Parameter | Type | Description |
---|---|---|
account_address | String | The account's portfolio address |
bank_balances | Coin Array | Account available bank balances |
subaccounts | SubaccountBalanceV2 | Subaccounts list |
Coin
Parameter | Type | Description |
---|---|---|
denom | String | Denom of the coin |
amount | String | Amount of the coin |
SubaccountBalanceV2
Parameter | Type | Description |
---|---|---|
subaccount_id | String | Related subaccount ID |
denom | String | Coin denom on the chain |
deposit | SubaccountDeposit | Subaccount's total balanace and available balances |
SubaccountDeposit
Parameter | Type | Description |
---|---|---|
total_balance | String | All balances (in specific denom) that this subaccount has |
available_balance | String | Available balance (in specific denom), the balance that is not used by current orders |
StreamAccountPortfolio
Get continuous updates on account's portfolio.
IP rate limit group: indexer
Request Parameters
Request Example:
import asyncio
from typing import Any, Dict
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def account_portfolio_event_processor(event: Dict[str, Any]):
print(event)
def stream_error_processor(exception: RpcError):
print(f"There was an error listening to account portfolio updates ({exception})")
def stream_closed_processor():
print("The account portfolio updates stream has been closed")
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
account_address = "inj1clw20s2uxeyxtam6f7m84vgae92s9eh7vygagt"
task = asyncio.get_event_loop().create_task(
client.listen_account_portfolio_updates(
account_address=account_address,
callback=account_portfolio_event_processor,
on_end_callback=stream_closed_processor,
on_status_callback=stream_error_processor,
)
)
await asyncio.sleep(delay=60)
task.cancel()
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
)
func main() {
// select network: local, testnet, mainnet
network := common.LoadNetwork("testnet", "lb")
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
stream, err := exchangeClient.StreamAccountPortfolio(ctx, "inj1clw20s2uxeyxtam6f7m84vgae92s9eh7vygagt", "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001", "total_balances")
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
return
default:
res, err := stream.Recv()
if err != nil {
fmt.Println(err)
return
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
}
}
Parameter | Type | Description | Required |
---|---|---|---|
account_address | String | The account's portfolio address | Yes |
subaccount_id | String | Related subaccount ID | No |
callback | Function | Function receiving one parameter (a stream event JSON dictionary) to process each new event | Yes |
on_end_callback | Function | Function with the logic to execute when the stream connection is interrupted | No |
on_status_callback | Function | Function receiving one parameter (the exception) with the logic to execute when an exception happens | No |
Response Parameters
Response Example:
{
"type": "total_balances",
"denom": "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"amount": "302686408.8456",
"subaccountId": "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001",
"timestamp": "342423423"
}
{
"type": "total_balances",
"denom": "inj",
"amount": "11040001000000000000",
"subaccount_id": "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001",
"timestamp": "342432343"
}
{
"type": "total_balances",
"denom": "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"amount": "302686408.8456",
"subaccount_id": "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001"
}{
"type": "total_balances",
"denom": "inj",
"amount": "11040001000000000000",
"subaccount_id": "0xc7dca7c15c364865f77a4fb67ab11dc95502e6fe000000000000000000000001"
}
Parameter | Type | Description |
---|---|---|
type | String | Type of portfolio document (should be one of ["bank", "total_balance", "available_balance"]) |
denom | String | Denom of portfolio entry |
amount | String | Amount of portfolio entry |
subaccount_id | String | Subaccount id of portfolio entry |
Chain API
The Indexer API is read-only whereas the Chain API is write and also includes a limited set of API requests to read data. The Chain API reads query the blockchain state from the node directly as opposed to the Indexer API which reconstructs state from events emitted by chain.
On a high-level the end-user trading applications and Injective Products use the Indexer API to read data and the Chain API to write data to the blockchain. Even though it’s possible to develop trading applications using the Chain API only, the Indexer API includes more methods, streaming support, gRPC and also allows you to fetch historical data as the Chain API queries the blockchain state which doesn’t include historical records.
- Account
Includes all messages related to accounts and transfers.
MsgDeposit
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
# prepare tx msg
msg = composer.msg_deposit(
sender=address.to_acc_bech32(), subaccount_id=subaccount_id, amount=0.000001, denom="INJ"
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"fmt"
"os"
"time"
"cosmossdk.io/math"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
sdktypes "github.com/cosmos/cosmos-sdk/types"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
msg := &exchangetypes.MsgDeposit{
Sender: senderAddress.String(),
SubaccountId: "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
Amount: sdktypes.Coin{
Denom: "inj", Amount: math.NewInt(1000000000000000000), // 1 INJ
},
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The address doing the deposit | Yes |
subaccount_id | String | Subaccount ID to deposit funds into. If empty, the coin will be deposited to the sender's default subaccount address. | No |
amount | Coin | The token amount to deposit | Yes |
Coin
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | The token denom | Yes |
amount | String | The amount of tokens | Yes |
Response Parameters
Response Example:
txhash: "49CA54DA708B5F58E401B661A8A6B590447AFCFCD192D95AE2DAFDBEB00DCD33"
raw_log: "[]"
gas wanted: 105793
gas fee: 0.0000528965 INJ
DEBU[0001] broadcastTx with nonce 3491 fn=func1 src="client/chain/chain.go:598"
DEBU[0002] msg batch committed successfully at height 5212649 fn=func1 src="client/chain/chain.go:619" txHash=8B3F45BB7247C0BFC916B4D9177601E512BBAEF8FA60E5B61D5CC815910D059F
DEBU[0002] nonce incremented to 3492 fn=func1 src="client/chain/chain.go:623"
DEBU[0002] gas wanted: 132099 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.0000660495 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgWithdraw
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
# prepare tx msg
msg = composer.msg_withdraw(sender=address.to_acc_bech32(), subaccount_id=subaccount_id, amount=1, denom="USDT")
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"fmt"
"os"
"time"
"cosmossdk.io/math"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
sdktypes "github.com/cosmos/cosmos-sdk/types"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
msg := &exchangetypes.MsgWithdraw{
Sender: senderAddress.String(),
SubaccountId: "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
Amount: sdktypes.Coin{
Denom: "inj", Amount: math.NewInt(1000000000000000000), // 1 INJ
},
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The address doing the withdraw | Yes |
subaccount_id | String | Subaccount ID to withdraw funds from | Yes |
amount | Coin | The token amount to deposit | Yes |
Coin
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | The token denom | Yes |
amount | String | The amount of tokens | Yes |
Response Parameters
Response Example:
txhash: "30724652FB970C8C08B0179D134AC519795068885541B08C6BB0AE3E8F0E59CE"
raw_log: "[]"
gas wanted: 111105
gas fee: 0.0000555525 INJ
DEBU[0001] broadcastTx with nonce 3504 fn=func1 src="client/chain/chain.go:598"
DEBU[0004] msg batch committed successfully at height 5214520 fn=func1 src="client/chain/chain.go:619" txHash=B73529AE8EE92B931B5E52102DE67251B71B492421D718644A79ED826BD6B451
DEBU[0004] nonce incremented to 3505 fn=func1 src="client/chain/chain.go:623"
DEBU[0004] gas wanted: 129606 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.000064803 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgSubaccountTransfer
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
from decimal import Decimal
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
dest_subaccount_id = address.get_subaccount_id(index=1)
# prepare tx msg
msg = composer.msg_subaccount_transfer(
sender=address.to_acc_bech32(),
source_subaccount_id=subaccount_id,
destination_subaccount_id=dest_subaccount_id,
amount=Decimal(100),
denom="INJ",
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"fmt"
"os"
"time"
"cosmossdk.io/math"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
sdktypes "github.com/cosmos/cosmos-sdk/types"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
msg := &exchangetypes.MsgSubaccountTransfer{
Sender: senderAddress.String(),
SourceSubaccountId: "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
DestinationSubaccountId: "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000001",
Amount: sdktypes.Coin{
Denom: "inj", Amount: math.NewInt(1000000000000000000), // 1 INJ
},
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The sender's address | Yes |
source_subaccount_id | String | Subaccount ID from where the funds are deducted | Yes |
destination_subaccount_id | String | Subaccount ID the funds are deposited into | Yes |
amount | Coin | The transfer token amount | Yes |
Coin
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | The token denom | Yes |
amount | String | The amount of tokens | Yes |
Response Parameters
Response Example:
txhash: "2E37F37501D025D09FADEB8A64DD47362292DE47D81514723BB061410409C956"
raw_log: "[]"
gas wanted: 97883
gas fee: 0.0000489415 INJ
DEBU[0001] broadcastTx with nonce 3506 fn=func1 src="client/chain/chain.go:598"
DEBU[0003] msg batch committed successfully at height 5214566 fn=func1 src="client/chain/chain.go:619" txHash=11181E2B0ACD1B0358CA19D52EF05D191B24F4E91B7548E94F3B7AC5841ABD8F
DEBU[0003] nonce incremented to 3507 fn=func1 src="client/chain/chain.go:623"
DEBU[0003] gas wanted: 122103 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.0000610515 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgExternalTransfer
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
from decimal import Decimal
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
dest_subaccount_id = "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000"
# prepare tx msg
msg = composer.msg_external_transfer(
sender=address.to_acc_bech32(),
source_subaccount_id=subaccount_id,
destination_subaccount_id=dest_subaccount_id,
amount=Decimal(100),
denom="INJ",
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"fmt"
"os"
"time"
"cosmossdk.io/math"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
sdktypes "github.com/cosmos/cosmos-sdk/types"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
msg := &exchangetypes.MsgExternalTransfer{
Sender: senderAddress.String(),
SourceSubaccountId: "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
DestinationSubaccountId: "0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000",
Amount: sdktypes.Coin{
Denom: "inj", Amount: math.NewInt(1000000000000000000), // 1 INJ
},
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The sender's address | Yes |
source_subaccount_id | String | Subaccount ID from where the funds are deducted | Yes |
destination_subaccount_id | String | Subaccount ID the funds are deposited into | Yes |
amount | Coin | The transfer token amount | Yes |
Coin
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | The token denom | Yes |
amount | String | The amount of tokens | Yes |
Response Parameters
Response Example:
txhash: "6790503C993094B50A7E0CBAD4B27E1ABFE24060509CB189DCC408A0AD99F894"
raw_log: "[]"
gas wanted: 99159
gas fee: 0.0000495795 INJ
DEBU[0002] broadcastTx with nonce 3658 fn=func1 src="client/chain/chain.go:607"
DEBU[0005] msg batch committed successfully at height 6556107 fn=func1 src="client/chain/chain.go:628" txHash=BD185F427DD1987969605695779C48FD4BEECC7AEC9C51ED5E0BF1747A471F4E
DEBU[0005] nonce incremented to 3659 fn=func1 src="client/chain/chain.go:632"
DEBU[0005] gas wanted: 122397 fn=func1 src="client/chain/chain.go:633"
gas fee: 0.0000611985 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgSendToEth
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
import requests
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
# prepare msg
asset = "injective-protocol"
coingecko_endpoint = f"https://api.coingecko.com/api/v3/simple/price?ids={asset}&vs_currencies=usd"
token_price = requests.get(coingecko_endpoint).json()[asset]["usd"]
minimum_bridge_fee_usd = 10
bridge_fee = minimum_bridge_fee_usd / token_price
# prepare tx msg
msg = composer.MsgSendToEth(
sender=address.to_acc_bech32(),
denom="INJ",
eth_dest="0xaf79152ac5df276d9a8e1e2e22822f9713474902",
amount=23,
bridge_fee=bridge_fee,
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"fmt"
"os"
"time"
"cosmossdk.io/math"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
peggytypes "github.com/InjectiveLabs/sdk-go/chain/peggy/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
sdktypes "github.com/cosmos/cosmos-sdk/types"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ethDest := "0xaf79152ac5df276d9a8e1e2e22822f9713474902"
amount := sdktypes.Coin{
Denom: "inj", Amount: math.NewInt(5000000000000000000), // 5 INJ
}
bridgeFee := sdktypes.Coin{
Denom: "inj", Amount: math.NewInt(2000000000000000000), // 2 INJ
}
msg := &peggytypes.MsgSendToEth{
Sender: senderAddress.String(),
Amount: amount,
EthDest: ethDest,
BridgeFee: bridgeFee,
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The sender's address | Yes |
eth_dest | String | Destination Ethereum address | Yes |
amount | Coin | The coin to send across the bridge (note the restriction that this is a single coin, not a set of coins) | Yes |
bridge_fee | Coin | The fee paid for the bridge, distinct from the fee paid to the chain to actually send this message in the first place. So a successful send has two layers of fees for the user | Yes |
Coin
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | The token denom | Yes |
amount | String | The amount of tokens | Yes |
Response Parameters
Response Example:
txhash: "5529016817553230024B45B44ABEB0538DC0AF9EEE0DEAD467B91C85BCCCAC87"
raw_log: "[]"
gas wanted: 125732
gas fee: 0.000062866 INJ
DEBU[0001] broadcastTx with nonce 3515 fn=func1 src="client/chain/chain.go:598"
DEBU[0004] msg batch committed successfully at height 5215066 fn=func1 src="client/chain/chain.go:619" txHash=391AB87558318BD7FF2CCB9D68ED309AD073FA64C8395A493D6C347FF572AF38
DEBU[0004] nonce incremented to 3516 fn=func1 src="client/chain/chain.go:623"
DEBU[0004] gas wanted: 161907 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.0000809535 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
SendToInjective
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import json
import os
import dotenv
from pyinjective.core.network import Network
from pyinjective.sendtocosmos import Peggo
async def main() -> None:
dotenv.load_dotenv()
private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: testnet, mainnet
network = Network.testnet()
peggo_composer = Peggo(network=network.string())
ethereum_endpoint = "https://eth-goerli.g.alchemy.com/v2/q-7JVv4mTfsNh1y_djKkKn3maRBGILLL"
maxFeePerGas_Gwei = 4
maxPriorityFeePerGas_Gwei = 4
token_contract = "0xBe8d71D26525440A03311cc7fa372262c5354A3c"
receiver = "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku"
amount = 1
data = (
'{"@type": "/injective.exchange.v1beta1.MsgDeposit",'
'"sender": "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",'
'"subaccountId": "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",'
'"amount": {"denom": "inj","amount": "1000000000000000000"}}'
)
with open("../pyinjective/Peggo_ABI.json") as pego_file:
peggo_data = pego_file.read()
peggo_abi = json.loads(peggo_data)
peggo_composer.sendToInjective(
ethereum_endpoint=ethereum_endpoint,
private_key=private_key,
token_contract=token_contract,
receiver=receiver,
amount=amount,
maxFeePerGas=maxFeePerGas_Gwei,
maxPriorityFeePerGas=maxPriorityFeePerGas_Gwei,
data=data,
peggo_abi=peggo_abi,
)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
Parameter | Type | Description | Required |
---|---|---|---|
ethereum_endpoint | String | The ethereum endpoint, you can get one from providers like Infura and Alchemy | Yes |
private_key | String | Private key of the account to be used to sign the transaction | Yes |
token_contract | String | The token contract, you can find the contract for the token you want to transfer on etherscan | Yes |
receiver | String | The Injective Chain address to receive the funds | Yes |
amount | Float | The amount to transfer | Yes |
maxFeePerGas | Integer | The maxFeePerGas in Gwei | Yes |
maxPriorityFeePerGas | Integer | The maxPriorityFeePerGas in Gwei | Yes |
peggo_abi | String | Peggo contract ABI| | Yes |
data | String | The body of the message to send to Injective chain to do the deposit | Yes |
decimals | Integer | Number of decimals in Injective chain of the token being transferred (default: 18) | No |
Response Parameters
Response Example:
Transferred 1 0x36b3d7ace7201e28040eff30e815290d7b37ffad from 0xbdAEdEc95d563Fb05240d6e01821008454c24C36 to inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku
Transaction hash: 0xb538abc7c2f893a2fe24c7a8ea606ff48d980a754499f1bec89b862c2bcb9ea7
GetTx
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
tx_hash = "D265527E3171C47D01D7EC9B839A95F8F794D4E683F26F5564025961C96EFDDA"
tx_logs = await client.fetch_tx(hash=tx_hash)
print(tx_logs)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"os"
"time"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
)
func main() {
// network := common.LoadNetwork("mainnet", "k8s")
network := common.LoadNetwork("mainnet", "lb")
tmRPC, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmRPC)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
timeOutCtx, cancelFn := context.WithTimeout(ctx, 30*time.Second)
defer cancelFn()
resp, err := chainClient.GetTx(timeOutCtx, "A2B2B971C690AE7977451D24D6F450AECE6BCCB271E91E32C2563342DDA5254B")
if err != nil {
panic(err)
}
fmt.Println(resp.TxResponse)
}
Parameter | Type | Description | Required |
---|---|---|---|
hash | String | The TX hash to query, encoded as a hex string | Yes |
Response Example:
{
"tx":{
"body":{
"messages":[
"OrderedDict("[
"(""@type",
"/cosmos.authz.v1beta1.MsgExec"")",
"(""grantee",
"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7"")",
"(""msgs",
[
"OrderedDict("[
"(""@type",
"/injective.exchange.v1beta1.MsgCreateSpotMarketOrder"")",
"(""sender",
"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7"")",
"(""order",
{
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"orderInfo":{
"subaccountId":"0x6561b5033700b734c54df4084240395889d23492000000000000000000000000",
"feeRecipient":"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7",
"price":"10194000",
"quantity":"175000000000000000000000000000000000",
"cid":""
},
"orderType":"SELL",
"triggerPrice":"0"
}")"
]")"
]")"
]")"
],
"timeoutHeight":"17518637",
"memo":"",
"extensionOptions":[
],
"nonCriticalExtensionOptions":[
]
},
"authInfo":{
"signerInfos":[
{
"publicKey":"OrderedDict("[
"(""@type",
"/injective.crypto.v1beta1.ethsecp256k1.PubKey"")",
"(""key",
"AmHqvENFf9E5s9vQFLQbcbHv4OIKTEWXVO4f7PZS9YOz"")"
]")",
"modeInfo":{
"single":{
"mode":"SIGN_MODE_DIRECT"
}
},
"sequence":"211255"
}
],
"fee":{
"amount":[
{
"denom":"inj",
"amount":"52378500000000"
}
],
"gasLimit":"104757",
"payer":"",
"granter":""
}
},
"signatures":[
"Hn4Ugl50quZLQv/btmpWGMDr4F4RX5eeaGMIbc5VzC06a0sH3yRLvcNPyAcODcVjMQ1jbIRM01SYkvu2By+xJw=="
]
},
"txResponse":{
"height":"17518608",
"txhash":"D265527E3171C47D01D7EC9B839A95F8F794D4E683F26F5564025961C96EFDDA",
"data":"126F0A252F636F736D6F732E617574687A2E763162657461312E4D736745786563526573706F6E736512460A440A42307834316630316536623266646433623463303631663834323235666165653033333536646238643137656265373631356661393232663132363861666434316136",
"rawLog":"[{\"msg_index\":0,\"events\":[{\"type\":\"message\",\"attributes\":[{\"key\":\"action\",\"value\":\"/cosmos.authz.v1beta1.MsgExec\"},{\"key\":\"sender\",\"value\":\"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7\"},{\"key\":\"module\",\"value\":\"authz\"}]},{\"type\":\"coin_spent\",\"attributes\":[{\"key\":\"spender\",\"value\":\"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7\"},{\"key\":\"amount\",\"value\":\"175000000000000000inj\"},{\"key\":\"authz_msg_index\",\"value\":\"0\"}]},{\"type\":\"coin_received\",\"attributes\":[{\"key\":\"receiver\",\"value\":\"inj14vnmw2wee3xtrsqfvpcqg35jg9v7j2vdpzx0kk\"},{\"key\":\"amount\",\"value\":\"175000000000000000inj\"},{\"key\":\"authz_msg_index\",\"value\":\"0\"}]},{\"type\":\"transfer\",\"attributes\":[{\"key\":\"recipient\",\"value\":\"inj14vnmw2wee3xtrsqfvpcqg35jg9v7j2vdpzx0kk\"},{\"key\":\"sender\",\"value\":\"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7\"},{\"key\":\"amount\",\"value\":\"175000000000000000inj\"},{\"key\":\"authz_msg_index\",\"value\":\"0\"}]},{\"type\":\"message\",\"attributes\":[{\"key\":\"sender\",\"value\":\"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7\"},{\"key\":\"authz_msg_index\",\"value\":\"0\"}]}]}]",
"logs":[
{
"events":[
{
"type":"message",
"attributes":[
{
"key":"action",
"value":"/cosmos.authz.v1beta1.MsgExec"
},
{
"key":"sender",
"value":"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7"
},
{
"key":"module",
"value":"authz"
}
]
},
{
"type":"coin_spent",
"attributes":[
{
"key":"spender",
"value":"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7"
},
{
"key":"amount",
"value":"175000000000000000inj"
},
{
"key":"authz_msg_index",
"value":"0"
}
]
},
{
"type":"coin_received",
"attributes":[
{
"key":"receiver",
"value":"inj14vnmw2wee3xtrsqfvpcqg35jg9v7j2vdpzx0kk"
},
{
"key":"amount",
"value":"175000000000000000inj"
},
{
"key":"authz_msg_index",
"value":"0"
}
]
},
{
"type":"transfer",
"attributes":[
{
"key":"recipient",
"value":"inj14vnmw2wee3xtrsqfvpcqg35jg9v7j2vdpzx0kk"
},
{
"key":"sender",
"value":"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7"
},
{
"key":"amount",
"value":"175000000000000000inj"
},
{
"key":"authz_msg_index",
"value":"0"
}
]
},
{
"type":"message",
"attributes":[
{
"key":"sender",
"value":"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7"
},
{
"key":"authz_msg_index",
"value":"0"
}
]
}
],
"msgIndex":0,
"log":""
}
],
"gasWanted":"104757",
"gasUsed":"102564",
"tx":"OrderedDict("[
"(""@type",
"/cosmos.tx.v1beta1.Tx"")",
"(""body",
{
"messages":[
"OrderedDict("[
"(""@type",
"/cosmos.authz.v1beta1.MsgExec"")",
"(""grantee",
"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7"")",
"(""msgs",
[
"OrderedDict("[
"(""@type",
"/injective.exchange.v1beta1.MsgCreateSpotMarketOrder"")",
"(""sender",
"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7"")",
"(""order",
{
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"orderInfo":{
"subaccountId":"0x6561b5033700b734c54df4084240395889d23492000000000000000000000000",
"feeRecipient":"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7",
"price":"10194000",
"quantity":"175000000000000000000000000000000000",
"cid":""
},
"orderType":"SELL",
"triggerPrice":"0"
}")"
]")"
]")"
]")"
],
"timeoutHeight":"17518637",
"memo":"",
"extensionOptions":[
],
"nonCriticalExtensionOptions":[
]
}")",
"(""authInfo",
{
"signerInfos":[
{
"publicKey":"OrderedDict("[
"(""@type",
"/injective.crypto.v1beta1.ethsecp256k1.PubKey"")",
"(""key",
"AmHqvENFf9E5s9vQFLQbcbHv4OIKTEWXVO4f7PZS9YOz"")"
]")",
"modeInfo":{
"single":{
"mode":"SIGN_MODE_DIRECT"
}
},
"sequence":"211255"
}
],
"fee":{
"amount":[
{
"denom":"inj",
"amount":"52378500000000"
}
],
"gasLimit":"104757",
"payer":"",
"granter":""
}
}")",
"(""signatures",
[
"Hn4Ugl50quZLQv/btmpWGMDr4F4RX5eeaGMIbc5VzC06a0sH3yRLvcNPyAcODcVjMQ1jbIRM01SYkvu2By+xJw=="
]")"
]")",
"timestamp":"2023-10-23T18:48:19Z",
"events":[
{
"type":"coin_spent",
"attributes":[
{
"key":"spender",
"value":"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7",
"index":true
},
{
"key":"amount",
"value":"52378500000000inj",
"index":true
}
]
},
{
"type":"coin_received",
"attributes":[
{
"key":"receiver",
"value":"inj17xpfvakm2amg962yls6f84z3kell8c5l6s5ye9",
"index":true
},
{
"key":"amount",
"value":"52378500000000inj",
"index":true
}
]
},
{
"type":"transfer",
"attributes":[
{
"key":"recipient",
"value":"inj17xpfvakm2amg962yls6f84z3kell8c5l6s5ye9",
"index":true
},
{
"key":"sender",
"value":"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7",
"index":true
},
{
"key":"amount",
"value":"52378500000000inj",
"index":true
}
]
},
{
"type":"message",
"attributes":[
{
"key":"sender",
"value":"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7",
"index":true
}
]
},
{
"type":"tx",
"attributes":[
{
"key":"fee",
"value":"52378500000000inj",
"index":true
},
{
"key":"fee_payer",
"value":"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7",
"index":true
}
]
},
{
"type":"tx",
"attributes":[
{
"key":"acc_seq",
"value":"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7/211255",
"index":true
}
]
},
{
"type":"tx",
"attributes":[
{
"key":"signature",
"value":"Hn4Ugl50quZLQv/btmpWGMDr4F4RX5eeaGMIbc5VzC06a0sH3yRLvcNPyAcODcVjMQ1jbIRM01SYkvu2By+xJw==",
"index":true
}
]
},
{
"type":"message",
"attributes":[
{
"key":"action",
"value":"/cosmos.authz.v1beta1.MsgExec",
"index":true
},
{
"key":"sender",
"value":"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7",
"index":true
},
{
"key":"module",
"value":"authz",
"index":true
}
]
},
{
"type":"coin_spent",
"attributes":[
{
"key":"spender",
"value":"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7",
"index":true
},
{
"key":"amount",
"value":"175000000000000000inj",
"index":true
},
{
"key":"authz_msg_index",
"value":"0",
"index":true
}
]
},
{
"type":"coin_received",
"attributes":[
{
"key":"receiver",
"value":"inj14vnmw2wee3xtrsqfvpcqg35jg9v7j2vdpzx0kk",
"index":true
},
{
"key":"amount",
"value":"175000000000000000inj",
"index":true
},
{
"key":"authz_msg_index",
"value":"0",
"index":true
}
]
},
{
"type":"transfer",
"attributes":[
{
"key":"recipient",
"value":"inj14vnmw2wee3xtrsqfvpcqg35jg9v7j2vdpzx0kk",
"index":true
},
{
"key":"sender",
"value":"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7",
"index":true
},
{
"key":"amount",
"value":"175000000000000000inj",
"index":true
},
{
"key":"authz_msg_index",
"value":"0",
"index":true
}
]
},
{
"type":"message",
"attributes":[
{
"key":"sender",
"value":"inj1v4sm2qehqzmnf32d7syyyspetzyaydyj4r4yv7",
"index":true
},
{
"key":"authz_msg_index",
"value":"0",
"index":true
}
]
}
],
"codespace":"",
"code":0,
"info":""
}
}
code: 0
codespace: ""
data: 0AC1010A302F696E6A6563746976652E65786368616E67652E763162657461312E4D736742617463685570646174654F7264657273128C011202010122423078396638313937363932323364333439646462313738333335303831396437396235373736323363623361613163633462346534326361643638666264393462362242307834656239333035636565663365616264663762653734313338343931633966373738663439613131613164643733613930623761666366323731353263633935
events:
- attributes:
- index: true
key: YWNjX3NlcQ==
value: aW5qMWFzNGpydGE4ODV6M3puMzdhMnozeGs5Y2RkdDhkeXptZnZ3ZW13LzEwODczMTIy
type: tx
- attributes:
- index: true
key: c2lnbmF0dXJl
value: eWtDcmVOVjdEaHF1Z1k5d2gvc25EWFF4VUtibC9ZK3h3Nmw5d3ZhU28zcExSYU9rVlR2b3VuaERmRy9ZYzl0SEplYVd6L1d2am1OekU2MmFJNHBrSHdFPQ==
type: tx
- attributes:
- index: true
key: c3BlbmRlcg==
value: aW5qMWFzNGpydGE4ODV6M3puMzdhMnozeGs5Y2RkdDhkeXptZnZ3ZW13
- index: true
key: YW1vdW50
value: MzY5ODAxMDAwMDAwMDAwaW5q
type: coin_spent
- attributes:
- index: true
key: cmVjZWl2ZXI=
value: aW5qMTd4cGZ2YWttMmFtZzk2MnlsczZmODR6M2tlbGw4YzVsNnM1eWU5
- index: true
key: YW1vdW50
value: MzY5ODAxMDAwMDAwMDAwaW5q
type: coin_received
- attributes:
- index: true
key: cmVjaXBpZW50
value: aW5qMTd4cGZ2YWttMmFtZzk2MnlsczZmODR6M2tlbGw4YzVsNnM1eWU5
- index: true
key: c2VuZGVy
value: aW5qMWFzNGpydGE4ODV6M3puMzdhMnozeGs5Y2RkdDhkeXptZnZ3ZW13
- index: true
key: YW1vdW50
value: MzY5ODAxMDAwMDAwMDAwaW5q
type: transfer
- attributes:
- index: true
key: c2VuZGVy
value: aW5qMWFzNGpydGE4ODV6M3puMzdhMnozeGs5Y2RkdDhkeXptZnZ3ZW13
type: message
- attributes:
- index: true
key: ZmVl
value: MzY5ODAxMDAwMDAwMDAwaW5q
- index: true
key: ZmVlX3BheWVy
value: aW5qMWFzNGpydGE4ODV6M3puMzdhMnozeGs5Y2RkdDhkeXptZnZ3ZW13
type: tx
- attributes:
- index: true
key: YWN0aW9u
value: L2luamVjdGl2ZS5leGNoYW5nZS52MWJldGExLk1zZ0JhdGNoVXBkYXRlT3JkZXJz
type: message
- attributes:
- index: true
key: aXNMaW1pdENhbmNlbA==
value: dHJ1ZQ==
- index: true
key: bGltaXRfb3JkZXI=
value: eyJvcmRlcl9pbmZvIjp7InN1YmFjY291bnRfaWQiOiIweGVjMmIyMWFmYTczZDA1MTE0ZTNlZWE4NTEzNThiODZiNTY3NjkwNWIwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEiLCJmZWVfcmVjaXBpZW50IjoiaW5qMWFzNGpydGE4ODV6M3puMzdhMnozeGs5Y2RkdDhkeXptZnZ3ZW13IiwicHJpY2UiOiI3NzM1MDAwLjAwMDAwMDAwMDAwMDAwMDAwMCIsInF1YW50aXR5IjoiNjQ2LjU2OTAwMDAwMDAwMDAwMDAwMCJ9LCJvcmRlcl90eXBlIjoiU0VMTF9QTyIsIm1hcmdpbiI6IjAuMDAwMDAwMDAwMDAwMDAwMDAwIiwiZmlsbGFibGUiOiI2NDYuNTY5MDAwMDAwMDAwMDAwMDAwIiwidHJpZ2dlcl9wcmljZSI6bnVsbCwib3JkZXJfaGFzaCI6ImhTZUNBOEU1a0krdmEzZUdLMnhWUGJxSlZybzNSUzlPRkJCVHhxMXhtVDg9In0=
- index: true
key: bWFya2V0X2lk
value: IjB4OWI5OTgwMTY3ZWNjMzY0NWZmMWE1NTE3ODg2NjUyZDk0YTA4MjVlNTRhNzdkMjA1N2NiYmUzZWJlZTAxNTk2MyI=
- index: true
key: bWFya2V0X29yZGVyX2NhbmNlbA==
value: bnVsbA==
type: injective.exchange.v1beta1.EventCancelDerivativeOrder
- attributes:
- index: true
key: aXNMaW1pdENhbmNlbA==
value: dHJ1ZQ==
- index: true
key: bGltaXRfb3JkZXI=
value: eyJvcmRlcl9pbmZvIjp7InN1YmFjY291bnRfaWQiOiIweGVjMmIyMWFmYTczZDA1MTE0ZTNlZWE4NTEzNThiODZiNTY3NjkwNWIwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEiLCJmZWVfcmVjaXBpZW50IjoiaW5qMWFzNGpydGE4ODV6M3puMzdhMnozeGs5Y2RkdDhkeXptZnZ3ZW13IiwicHJpY2UiOiI3NjY0MDAwLjAwMDAwMDAwMDAwMDAwMDAwMCIsInF1YW50aXR5IjoiNjQ2LjU2OTAwMDAwMDAwMDAwMDAwMCJ9LCJvcmRlcl90eXBlIjoiQlVZX1BPIiwibWFyZ2luIjoiOTkxMDYwOTYzLjIwMDAwMDAwMDAwMDAwMDAwMCIsImZpbGxhYmxlIjoiNjQ2LjU2OTAwMDAwMDAwMDAwMDAwMCIsInRyaWdnZXJfcHJpY2UiOm51bGwsIm9yZGVyX2hhc2giOiJnYllhaEVIdFhLY0J3RkgvazU4ZmxQdVZlUWRzcGlabjA5NWZia3E0a0dNPSJ9
- index: true
key: bWFya2V0X2lk
value: IjB4OWI5OTgwMTY3ZWNjMzY0NWZmMWE1NTE3ODg2NjUyZDk0YTA4MjVlNTRhNzdkMjA1N2NiYmUzZWJlZTAxNTk2MyI=
- index: true
key: bWFya2V0X29yZGVyX2NhbmNlbA==
value: bnVsbA==
type: injective.exchange.v1beta1.EventCancelDerivativeOrder
- attributes:
- index: true
key: YnV5X29yZGVycw==
value: W10=
- index: true
key: bWFya2V0X2lk
value: IjB4OWI5OTgwMTY3ZWNjMzY0NWZmMWE1NTE3ODg2NjUyZDk0YTA4MjVlNTRhNzdkMjA1N2NiYmUzZWJlZTAxNTk2MyI=
- index: true
key: c2VsbF9vcmRlcnM=
value: W3sib3JkZXJfaW5mbyI6eyJzdWJhY2NvdW50X2lkIjoiMHhlYzJiMjFhZmE3M2QwNTExNGUzZWVhODUxMzU4Yjg2YjU2NzY5MDViMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAxIiwiZmVlX3JlY2lwaWVudCI6ImluajFhczRqcnRhODg1ejN6bjM3YTJ6M3hrOWNkZHQ4ZHl6bWZ2d2VtdyIsInByaWNlIjoiNzczNzAwMC4wMDAwMDAwMDAwMDAwMDAwMDAiLCJxdWFudGl0eSI6IjY0Ni4zMzcwMDAwMDAwMDAwMDAwMDAifSwib3JkZXJfdHlwZSI6IlNFTExfUE8iLCJtYXJnaW4iOiIwLjAwMDAwMDAwMDAwMDAwMDAwMCIsImZpbGxhYmxlIjoiNjQ2LjMzNzAwMDAwMDAwMDAwMDAwMCIsInRyaWdnZXJfcHJpY2UiOm51bGwsIm9yZGVyX2hhc2giOiJuNEdYYVNJOU5KM2JGNE0xQ0JuWG0xZDJJOHM2b2N4TFRrTEsxbys5bExZPSJ9XQ==
type: injective.exchange.v1beta1.EventNewDerivativeOrders
- attributes:
- index: true
key: YnV5X29yZGVycw==
value: W3sib3JkZXJfaW5mbyI6eyJzdWJhY2NvdW50X2lkIjoiMHhlYzJiMjFhZmE3M2QwNTExNGUzZWVhODUxMzU4Yjg2YjU2NzY5MDViMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAxIiwiZmVlX3JlY2lwaWVudCI6ImluajFhczRqcnRhODg1ejN6bjM3YTJ6M3hrOWNkZHQ4ZHl6bWZ2d2VtdyIsInByaWNlIjoiNzY2NjAwMC4wMDAwMDAwMDAwMDAwMDAwMDAiLCJxdWFudGl0eSI6IjY0Ni4zMzcwMDAwMDAwMDAwMDAwMDAifSwib3JkZXJfdHlwZSI6IkJVWV9QTyIsIm1hcmdpbiI6Ijk5MDk2Mzg4OC40MDAwMDAwMDAwMDAwMDAwMDAiLCJmaWxsYWJsZSI6IjY0Ni4zMzcwMDAwMDAwMDAwMDAwMDAiLCJ0cmlnZ2VyX3ByaWNlIjpudWxsLCJvcmRlcl9oYXNoIjoiVHJrd1hPN3o2cjMzdm5RVGhKSEo5M2owbWhHaDNYT3BDM3I4OG5GU3pKVT0ifV0=
- index: true
key: bWFya2V0X2lk
value: IjB4OWI5OTgwMTY3ZWNjMzY0NWZmMWE1NTE3ODg2NjUyZDk0YTA4MjVlNTRhNzdkMjA1N2NiYmUzZWJlZTAxNTk2MyI=
- index: true
key: c2VsbF9vcmRlcnM=
value: W10=
type: injective.exchange.v1beta1.EventNewDerivativeOrders
gas_used: "261983"
gas_wanted: "369801"
height: "32442284"
info: ""
logs:
- events:
- attributes:
- key: isLimitCancel
value: "true"
- key: limit_order
value: '{"order_info":{"subaccount_id":"0xec2b21afa73d05114e3eea851358b86b5676905b000000000000000000000001","fee_recipient":"inj1as4jrta885z3zn37a2z3xk9cddt8dyzmfvwemw","price":"7735000.000000000000000000","quantity":"646.569000000000000000"},"order_type":"SELL_PO","margin":"0.000000000000000000","fillable":"646.569000000000000000","trigger_price":null,"order_hash":"hSeCA8E5kI+va3eGK2xVPbqJVro3RS9OFBBTxq1xmT8="}'
- key: market_id
value: '"0x9b9980167ecc3645ff1a5517886652d94a0825e54a77d2057cbbe3ebee015963"'
- key: market_order_cancel
value: "null"
- key: isLimitCancel
value: "true"
- key: limit_order
value: '{"order_info":{"subaccount_id":"0xec2b21afa73d05114e3eea851358b86b5676905b000000000000000000000001","fee_recipient":"inj1as4jrta885z3zn37a2z3xk9cddt8dyzmfvwemw","price":"7664000.000000000000000000","quantity":"646.569000000000000000"},"order_type":"BUY_PO","margin":"991060963.200000000000000000","fillable":"646.569000000000000000","trigger_price":null,"order_hash":"gbYahEHtXKcBwFH/k58flPuVeQdspiZn095fbkq4kGM="}'
- key: market_id
value: '"0x9b9980167ecc3645ff1a5517886652d94a0825e54a77d2057cbbe3ebee015963"'
- key: market_order_cancel
value: "null"
type: injective.exchange.v1beta1.EventCancelDerivativeOrder
- attributes:
- key: buy_orders
value: '[]'
- key: market_id
value: '"0x9b9980167ecc3645ff1a5517886652d94a0825e54a77d2057cbbe3ebee015963"'
- key: sell_orders
value: '[{"order_info":{"subaccount_id":"0xec2b21afa73d05114e3eea851358b86b5676905b000000000000000000000001","fee_recipient":"inj1as4jrta885z3zn37a2z3xk9cddt8dyzmfvwemw","price":"7737000.000000000000000000","quantity":"646.337000000000000000"},"order_type":"SELL_PO","margin":"0.000000000000000000","fillable":"646.337000000000000000","trigger_price":null,"order_hash":"n4GXaSI9NJ3bF4M1CBnXm1d2I8s6ocxLTkLK1o+9lLY="}]'
- key: buy_orders
value: '[{"order_info":{"subaccount_id":"0xec2b21afa73d05114e3eea851358b86b5676905b000000000000000000000001","fee_recipient":"inj1as4jrta885z3zn37a2z3xk9cddt8dyzmfvwemw","price":"7666000.000000000000000000","quantity":"646.337000000000000000"},"order_type":"BUY_PO","margin":"990963888.400000000000000000","fillable":"646.337000000000000000","trigger_price":null,"order_hash":"TrkwXO7z6r33vnQThJHJ93j0mhGh3XOpC3r88nFSzJU="}]'
- key: market_id
value: '"0x9b9980167ecc3645ff1a5517886652d94a0825e54a77d2057cbbe3ebee015963"'
- key: sell_orders
value: '[]'
type: injective.exchange.v1beta1.EventNewDerivativeOrders
- attributes:
- key: action
value: /injective.exchange.v1beta1.MsgBatchUpdateOrders
type: message
log: ""
msg_index: 0
raw_log: '[{"events":[{"type":"injective.exchange.v1beta1.EventCancelDerivativeOrder","attributes":[{"key":"isLimitCancel","value":"true"},{"key":"limit_order","value":"{\"order_info\":{\"subaccount_id\":\"0xec2b21afa73d05114e3eea851358b86b5676905b000000000000000000000001\",\"fee_recipient\":\"inj1as4jrta885z3zn37a2z3xk9cddt8dyzmfvwemw\",\"price\":\"7735000.000000000000000000\",\"quantity\":\"646.569000000000000000\"},\"order_type\":\"SELL_PO\",\"margin\":\"0.000000000000000000\",\"fillable\":\"646.569000000000000000\",\"trigger_price\":null,\"order_hash\":\"hSeCA8E5kI+va3eGK2xVPbqJVro3RS9OFBBTxq1xmT8=\"}"},{"key":"market_id","value":"\"0x9b9980167ecc3645ff1a5517886652d94a0825e54a77d2057cbbe3ebee015963\""},{"key":"market_order_cancel","value":"null"},{"key":"isLimitCancel","value":"true"},{"key":"limit_order","value":"{\"order_info\":{\"subaccount_id\":\"0xec2b21afa73d05114e3eea851358b86b5676905b000000000000000000000001\",\"fee_recipient\":\"inj1as4jrta885z3zn37a2z3xk9cddt8dyzmfvwemw\",\"price\":\"7664000.000000000000000000\",\"quantity\":\"646.569000000000000000\"},\"order_type\":\"BUY_PO\",\"margin\":\"991060963.200000000000000000\",\"fillable\":\"646.569000000000000000\",\"trigger_price\":null,\"order_hash\":\"gbYahEHtXKcBwFH/k58flPuVeQdspiZn095fbkq4kGM=\"}"},{"key":"market_id","value":"\"0x9b9980167ecc3645ff1a5517886652d94a0825e54a77d2057cbbe3ebee015963\""},{"key":"market_order_cancel","value":"null"}]},{"type":"injective.exchange.v1beta1.EventNewDerivativeOrders","attributes":[{"key":"buy_orders","value":"[]"},{"key":"market_id","value":"\"0x9b9980167ecc3645ff1a5517886652d94a0825e54a77d2057cbbe3ebee015963\""},{"key":"sell_orders","value":"[{\"order_info\":{\"subaccount_id\":\"0xec2b21afa73d05114e3eea851358b86b5676905b000000000000000000000001\",\"fee_recipient\":\"inj1as4jrta885z3zn37a2z3xk9cddt8dyzmfvwemw\",\"price\":\"7737000.000000000000000000\",\"quantity\":\"646.337000000000000000\"},\"order_type\":\"SELL_PO\",\"margin\":\"0.000000000000000000\",\"fillable\":\"646.337000000000000000\",\"trigger_price\":null,\"order_hash\":\"n4GXaSI9NJ3bF4M1CBnXm1d2I8s6ocxLTkLK1o+9lLY=\"}]"},{"key":"buy_orders","value":"[{\"order_info\":{\"subaccount_id\":\"0xec2b21afa73d05114e3eea851358b86b5676905b000000000000000000000001\",\"fee_recipient\":\"inj1as4jrta885z3zn37a2z3xk9cddt8dyzmfvwemw\",\"price\":\"7666000.000000000000000000\",\"quantity\":\"646.337000000000000000\"},\"order_type\":\"BUY_PO\",\"margin\":\"990963888.400000000000000000\",\"fillable\":\"646.337000000000000000\",\"trigger_price\":null,\"order_hash\":\"TrkwXO7z6r33vnQThJHJ93j0mhGh3XOpC3r88nFSzJU=\"}]"},{"key":"market_id","value":"\"0x9b9980167ecc3645ff1a5517886652d94a0825e54a77d2057cbbe3ebee015963\""},{"key":"sell_orders","value":"[]"}]},{"type":"message","attributes":[{"key":"action","value":"/injective.exchange.v1beta1.MsgBatchUpdateOrders"}]}]}]'
timestamp: "2023-05-02T03:04:55Z"
tx:
'@type': /cosmos.tx.v1beta1.Tx
auth_info:
fee:
amount:
- amount: "369801000000000"
denom: inj
gas_limit: "369801"
granter: ""
payer: ""
signer_infos:
- mode_info:
single:
mode: SIGN_MODE_DIRECT
public_key:
'@type': /injective.crypto.v1beta1.ethsecp256k1.PubKey
key: An8DQ7/twFqvUuJxd5rCIkl04BfQocYS2T/A2pnYbFOJ
sequence: "10873122"
body:
extension_options: []
memo: ""
messages:
- '@type': /injective.exchange.v1beta1.MsgBatchUpdateOrders
binary_options_market_ids_to_cancel_all: []
binary_options_orders_to_cancel: []
binary_options_orders_to_create: []
derivative_market_ids_to_cancel_all: []
derivative_orders_to_cancel:
- market_id: 0x9b9980167ecc3645ff1a5517886652d94a0825e54a77d2057cbbe3ebee015963
order_hash: 0x85278203c139908faf6b77862b6c553dba8956ba37452f4e141053c6ad71993f
order_mask: 0
subaccount_id: 0xec2b21afa73d05114e3eea851358b86b5676905b000000000000000000000001
- market_id: 0x9b9980167ecc3645ff1a5517886652d94a0825e54a77d2057cbbe3ebee015963
order_hash: 0x81b61a8441ed5ca701c051ff939f1f94fb9579076ca62667d3de5f6e4ab89063
order_mask: 0
subaccount_id: 0xec2b21afa73d05114e3eea851358b86b5676905b000000000000000000000001
derivative_orders_to_create:
- margin: "0.000000000000000000"
market_id: 0x9b9980167ecc3645ff1a5517886652d94a0825e54a77d2057cbbe3ebee015963
order_info:
fee_recipient: inj1as4jrta885z3zn37a2z3xk9cddt8dyzmfvwemw
price: "7737000.000000000000000000"
quantity: "646.337000000000000000"
subaccount_id: 0xec2b21afa73d05114e3eea851358b86b5676905b000000000000000000000001
order_type: SELL_PO
trigger_price: null
- margin: "990963888.400000000000000000"
market_id: 0x9b9980167ecc3645ff1a5517886652d94a0825e54a77d2057cbbe3ebee015963
order_info:
fee_recipient: inj1as4jrta885z3zn37a2z3xk9cddt8dyzmfvwemw
price: "7666000.000000000000000000"
quantity: "646.337000000000000000"
subaccount_id: 0xec2b21afa73d05114e3eea851358b86b5676905b000000000000000000000001
order_type: BUY_PO
trigger_price: null
sender: inj1as4jrta885z3zn37a2z3xk9cddt8dyzmfvwemw
spot_market_ids_to_cancel_all: []
spot_orders_to_cancel: []
spot_orders_to_create: []
subaccount_id: ""
non_critical_extension_options: []
timeout_height: "0"
signatures:
- ykCreNV7DhqugY9wh/snDXQxUKbl/Y+xw6l9wvaSo3pLRaOkVTvounhDfG/Yc9tHJeaWz/WvjmNzE62aI4pkHwE=
txhash: A2B2B971C690AE7977451D24D6F450AECE6BCCB271E91E32C2563342DDA5254B
Parameter | Type | Description |
---|---|---|
tx | Tx | Transaction details |
tx_resposne | TxResponse | Transaction details |
Tx
Parameter | Type | Description |
---|---|---|
body | TxBody | Body is the processable content of the transaction |
auth_info | AuthInfo | Authorization related content of the transaction (specifically signers, signer modes and fee) |
signatures | Bytes Array Array | List of signatures that matches the length and order of AuthInfo's signer_infos to allow connecting signature meta information like public key and signing mode by position |
TxBody
Parameter | Type | Description |
---|---|---|
messages | Any Array | List of messages to be executed. The required signers of those messages define the number and order of elements in AuthInfo's signer_infos and Tx's signatures. Each required signer address is added to the list only the first time it occurs. By convention, the first required signer (usually from the first message) is referred to as the primary signer and pays the fee for the whole transaction |
memo | String | Memo is any arbitrary note/comment to be added to the transaction |
timeout_height | Integer | The block height after which this transaction will not be processed by the chain |
extension_options | Any Array | These are arbitrary options that can be added by chains when the default options are not sufficient. If any of these are present and can't be handled, the transaction will be rejected |
non_critical_extension_options | Any Array | These are arbitrary options that can be added by chains when the default options are not sufficient. If any of these are present and can't be handled, they will be ignored |
AuthInfo
Parameter | Type | Description |
---|---|---|
signer_infos | SignerInfo Array | Defines the signing modes for the required signers. The number and order of elements must match the required signers from TxBody's messages. The first element is the primary signer and the one which pays the fee |
fee | Fee | Fee is the fee and gas limit for the transaction. The first signer is the primary signer and the one which pays the fee. The fee can be calculated based on the cost of evaluating the body and doing signature verification of the signers. This can be estimated via simulation |
tip | Tip | Tip is the optional tip used for transactions fees paid in another denom (this field is ignored if the chain didn't enable tips, i.e. didn't add the `TipDecorator` in its posthandler) |
SignerInfo
Parameter | Type | Description |
---|---|---|
public_key | Any | Public key of the signer. It is optional for accounts that already exist in state. If unset, the verifier can use the required signer address for this position and lookup the public key |
mode_info | ModeInfo | Describes the signing mode of the signer and is a nested structure to support nested multisig pubkey's |
sequence | Integer | The sequence of the account, which describes the number of committed transactions signed by a given address. It is used to prevent replay attacks |
ModeInfo
Parameter | Type | Description |
---|---|---|
sum | Signing mode | Types that are valid to be assigned to Sum: *ModeInfo_Single_, *ModeInfo_Multi_ |
Fee
Parameter | Type | Description |
---|---|---|
amount | Coin Array | Amount of coins to be paid as a fee |
gas_limit | Integer | Maximum gas that can be used in transaction processing before an out of gas error occurs |
payer | String | If unset, the first signer is responsible for paying the fees. If set, the specified account must pay the fees. The payer must be a tx signer (and thus have signed this field in AuthInfo). Setting this field does *not* change the ordering of required signers for the transaction |
granter | String | If set, the fee payer (either the first signer or the value of the payer field) requests that a fee grant be used to pay fees instead of the fee payer's own balance. If an appropriate fee grant does not exist or the chain does not support fee grants, this will fail |
Coin
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | The token denom | Yes |
amount | String | The amount of tokens | Yes |
Tip
Parameter | Type | Description |
---|---|---|
amount | Coin Array | Amount of coins to be paid as a tip |
tipper | String | Address of the account paying for the tip |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
StreamEventOrderFail
IP rate limit group: chain
Request Example:
import asyncio
import base64
import json
import websockets
from pyinjective.core.network import Network
async def main() -> None:
network = Network.mainnet()
event_filter = (
"tm.event='Tx' AND message.sender='inj1rwv4zn3jptsqs7l8lpa3uvzhs57y8duemete9e' "
"AND message.action='/injective.exchange.v1beta1.MsgBatchUpdateOrders' "
"AND injective.exchange.v1beta1.EventOrderFail.flags EXISTS"
)
query = json.dumps(
{
"jsonrpc": "2.0",
"method": "subscribe",
"id": "0",
"params": {"query": event_filter},
}
)
async with websockets.connect(network.tm_websocket_endpoint) as ws:
await ws.send(query)
while True:
res = await ws.recv()
res = json.loads(res)
result = res["result"]
if result == {}:
continue
failed_order_hashes = json.loads(result["events"]["injective.exchange.v1beta1.EventOrderFail.hashes"][0])
failed_order_codes = json.loads(result["events"]["injective.exchange.v1beta1.EventOrderFail.flags"][0])
dict = {}
for i, order_hash in enumerate(failed_order_hashes):
hash = "0x" + base64.b64decode(order_hash).hex()
dict[hash] = failed_order_codes[i]
print(dict)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
)
func main() {
network := common.LoadNetwork("mainnet", "lb")
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
"",
nil,
)
if err != nil {
panic(err)
}
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
failEventCh := make(chan map[string]uint, 10000)
go chainClient.StreamEventOrderFail("inj1rwv4zn3jptsqs7l8lpa3uvzhs57y8duemete9e", failEventCh)
for {
e := <-failEventCh
fmt.Println(e)
}
}
Response Parameters
Response Example:
{'0x7d6d0d2118488dcaccd57193372e536881f34132241f01c1721ed6aedffec419': 36}
map[0x9db0f6e90d63b151ab0d64f0c6d83f747969f353d8c39a68cca65d046907e92a:59 0xdf7e05e66ab7a47e7a8a1751d4b9360fd80058cd5186162cee6fe124c57ece82:36]
- Auction
Includes the message for placing bids in auctions.
MsgBid
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
# prepare tx msg
msg = composer.MsgBid(sender=address.to_acc_bech32(), round=16250, bid_amount=1)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"fmt"
"os"
"time"
"cosmossdk.io/math"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
auctiontypes "github.com/InjectiveLabs/sdk-go/chain/auction/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
sdktypes "github.com/cosmos/cosmos-sdk/types"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
round := uint64(9355)
bidAmount := sdktypes.Coin{
Denom: "inj", Amount: math.NewInt(1000000000000000000), // 1 INJ
}
msg := &auctiontypes.MsgBid{
Sender: senderAddress.String(),
Round: round,
BidAmount: bidAmount,
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The sender Injective address | Yes |
bid_amount | Coin | Bid amount in INJ tokens | Yes |
round | Integer | The current auction round | Yes |
Coin
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | The token denom | Yes |
amount | String | The amount of tokens | Yes |
Response Parameters
Response Example:
txhash: "F18B1E6E39FAEA646F487C223DAE161482B1A12FC00C20D04A43826B8DD3E40F"
raw_log: "[]"
gas wanted: 105842
gas fee: 0.000052921 INJ
DEBU[0001] broadcastTx with nonce 3508 fn=func1 src="client/chain/chain.go:598"
DEBU[0002] msg batch committed successfully at height 5214789 fn=func1 src="client/chain/chain.go:619" txHash=BD49BD58A263A92465A93FD0E10C5076DA8334A45A60E29A66C2E5961998AB5F
DEBU[0002] nonce incremented to 3509 fn=func1 src="client/chain/chain.go:623"
DEBU[0002] gas wanted: 152112 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.000076056 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
- Authz
Includes all messages and queries related to the Authz module. Authz is an implementation of the Cosmos SDK module, that allows granting arbitrary privileges from one account (the granter) to another account (the grantee). Authorizations must be granted for a particular Msg service method one by one using an implementation of the Authorization interface.
MsgGrant
There are two types of authorization, Generic and Typed. Generic authorization will grant permissions to the grantee to execute exchange-related messages in all markets, typed authorization restricts the privileges to specified markets. Typed authorization is generally more safe since even if the grantee's key is compromised the attacker will only be able to send orders in specified markets - thus prevents them from launching bogus markets on-chain and executing orders on behalf of the granter.
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
grantee_public_address = os.getenv("INJECTIVE_GRANTEE_PUBLIC_ADDRESS")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
# subaccount_id = address.get_subaccount_id(index=0)
# market_ids = ["0x0511ddc4e6586f3bfe1acb2dd905f8b8a82c97e1edaef654b12ca7e6031ca0fa"]
# prepare tx msg
# GENERIC AUTHZ
msg = composer.MsgGrantGeneric(
granter=address.to_acc_bech32(),
grantee=grantee_public_address,
msg_type="/injective.exchange.v1beta1.MsgCreateSpotLimitOrder",
expire_in=31536000, # 1 year
)
# TYPED AUTHZ
# msg = composer.MsgGrantTyped(
# granter = "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku",
# grantee = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
# msg_type = "CreateSpotLimitOrderAuthz",
# expire_in=31536000, # 1 year
# subaccount_id=subaccount_id,
# market_ids=market_ids
# )
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"fmt"
"os"
"time"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
granter := senderAddress.String()
grantee := "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
expireIn := time.Now().AddDate(1, 0, 0) // years months days
// GENERIC AUTHZ
// msgtype := "/injective.exchange.v1beta1.MsgCreateSpotLimitOrder"
// msg := chainClient.BuildGenericAuthz(granter, grantee, msgtype, expireIn)
// TYPED AUTHZ
msg := chainClient.BuildExchangeAuthz(
granter,
grantee,
chainclient.CreateSpotLimitOrderAuthz,
chainClient.DefaultSubaccount(senderAddress).String(),
[]string{"0xe0dc13205fb8b23111d8555a6402681965223135d368eeeb964681f9ff12eb2a"},
expireIn,
)
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
granter | String | The INJ address authorizing a grantee | Yes |
grantee | String | The INJ address being authorized by the granter | Yes |
msg_type | String | The message type being authorized by the granter | Yes |
expire_in | Integer | The expiration time for the authorization | Yes |
Typed Authorization Messages
CreateSpotLimitOrderAuthz
CreateSpotMarketOrderAuthz
BatchCreateSpotLimitOrdersAuthz
CancelSpotOrderAuthz
BatchCancelSpotOrdersAuthz
CreateDerivativeLimitOrderAuthz
CreateDerivativeMarketOrderAuthz
BatchCreateDerivativeLimitOrdersAuthz
CancelDerivativeOrderAuthz
BatchCancelDerivativeOrdersAuthz
BatchUpdateOrdersAuthz
Response Parameters
Response Example:
txhash: "ACD8E18DF357E28821B2931C4138971F805967485AE48FED2A808112F630D7E9"
raw_log: "[]"
gas wanted: 96103
gas fee: 0.0000480515 INJ
DEBU[0001] broadcastTx with nonce 3509 fn=func1 src="client/chain/chain.go:598"
DEBU[0003] msg batch committed successfully at height 5214837 fn=func1 src="client/chain/chain.go:619" txHash=1F1FD519002B85C68CAE5593FDDB11FD749F918D5BBCA5F10E8AF6CFF0C5090A
DEBU[0003] nonce incremented to 3510 fn=func1 src="client/chain/chain.go:623"
DEBU[0003] gas wanted: 117873 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.0000589365 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgExec
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import uuid
from decimal import Decimal
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import Address, PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_GRANTEE_PRIVATE_KEY")
granter_inj_address = os.getenv("INJECTIVE_GRANTER_PUBLIC_ADDRESS")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
# prepare tx msg
market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
grantee = address.to_acc_bech32()
granter_address = Address.from_acc_bech32(granter_inj_address)
granter_subaccount_id = granter_address.get_subaccount_id(index=0)
msg0 = composer.msg_create_spot_limit_order(
sender=granter_inj_address,
market_id=market_id,
subaccount_id=granter_subaccount_id,
fee_recipient=grantee,
price=Decimal("7.523"),
quantity=Decimal("0.01"),
order_type="BUY",
cid=str(uuid.uuid4()),
)
msg = composer.MsgExec(grantee=grantee, msgs=[msg0])
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
sim_res_msgs = sim_res["result"]["msgResponses"]
data = sim_res_msgs[0]
unpacked_msg_res = composer.unpack_msg_exec_response(
underlying_msg_type=msg0.__class__.__name__, msg_exec_response=data
)
print("simulation msg response")
print(unpacked_msg_res)
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"os"
"time"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
"github.com/shopspring/decimal"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
authztypes "github.com/cosmos/cosmos-sdk/x/authz"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
granterAddress, _, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := chainclient.NewMarketsAssistantInitializedFromChain(ctx, exchangeClient)
if err != nil {
panic(err)
}
txFactory := chainclient.NewTxFactory(clientCtx)
txFactory = txFactory.WithGasPrices(client.DefaultGasPriceWithDenom)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionTxFactory(&txFactory),
)
if err != nil {
panic(err)
}
// note that we use grantee keyring to send the msg on behalf of granter here
// sender, subaccount are from granter
granter := granterAddress.String()
grantee := "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
defaultSubaccountID := chainClient.DefaultSubaccount(granterAddress)
marketId := "0x0511ddc4e6586f3bfe1acb2dd905f8b8a82c97e1edaef654b12ca7e6031ca0fa"
amount := decimal.NewFromFloat(2)
price := decimal.NewFromFloat(22.55)
order := chainClient.CreateSpotOrder(
defaultSubaccountID,
&chainclient.SpotOrderData{
OrderType: exchangetypes.OrderType_BUY,
Quantity: amount,
Price: price,
FeeRecipient: senderAddress.String(),
MarketId: marketId,
},
marketsAssistant,
)
// manually pack msg into Any type
msg0 := exchangetypes.MsgCreateSpotLimitOrder{
Sender: granter,
Order: *order,
}
msg0Bytes, _ := msg0.Marshal()
msg0Any := &codectypes.Any{}
msg0Any.TypeUrl = sdk.MsgTypeURL(&msg0)
msg0Any.Value = msg0Bytes
msg := &authztypes.MsgExec{
Grantee: grantee,
Msgs: []*codectypes.Any{msg0Any},
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
grantee | String | The INJ address of the grantee | Yes |
msgs | Array | The messages to be executed on behalf of the granter | Yes |
Response Parameters
Response Example:
---Simulation Response---
[results: "\nB0x7bd1785363eb01c0c9e1642d71645f75d198e70419b303c9e48e39af3e428bcf"
]
---Transaction Response---
txhash: "D8F84A91C189430E2219DBA72BFA64FD567240EAEFFE4296202A1D31835E2EE1"
raw_log: "[]"
gas wanted: 107030
gas fee: 0.000053515 INJ
DEBU[0002] broadcastTx with nonce 1313 fn=func1 src="client/chain/chain.go:598"
DEBU[0004] msg batch committed successfully at height 5214956 fn=func1 src="client/chain/chain.go:619" txHash=6968428F68F3F1380D9A059C964F0C39C943EBBCCD758E8541270DC3B4037A02
DEBU[0004] nonce incremented to 1314 fn=func1 src="client/chain/chain.go:623"
DEBU[0004] gas wanted: 133972 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.000066986 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgRevoke
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
grantee_public_address = os.getenv("INJECTIVE_GRANTEE_PUBLIC_ADDRESS")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
# prepare tx msg
msg = composer.MsgRevoke(
granter=address.to_acc_bech32(),
grantee=grantee_public_address,
msg_type="/injective.exchange.v1beta1.MsgCreateSpotLimitOrder",
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"fmt"
"os"
"time"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
authztypes "github.com/cosmos/cosmos-sdk/x/authz"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
grantee := "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
msgType := "/injective.exchange.v1beta1.MsgCreateSpotLimitOrder"
msg := &authztypes.MsgRevoke{
Granter: senderAddress.String(),
Grantee: grantee,
MsgTypeUrl: msgType,
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
granter | String | The INJ address unauthorizing a grantee | Yes |
grantee | String | The INJ address being unauthorized by the granter | Yes |
msg_type | String | The message type being unauthorized by the granter | Yes |
Response Example:
txhash: "7E89656E1ED2E2A934B0A1D4DD1D4B228C15A50FDAEA0B97A67E9E27E1B22627"
raw_log: "[]"
gas wanted: 86490
gas fee: 0.000043245 INJ
DEBU[0001] broadcastTx with nonce 3511 fn=func1 src="client/chain/chain.go:598"
DEBU[0003] msg batch committed successfully at height 5214972 fn=func1 src="client/chain/chain.go:619" txHash=CB15AC2B2722E5CFAA61234B3668043BA1333DAC728B875A77946EEE11FE48C2
DEBU[0003] nonce incremented to 3512 fn=func1 src="client/chain/chain.go:623"
DEBU[0003] gas wanted: 103153 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.0000515765 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
Grants
Get the details of an authorization between a granter and a grantee.
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
granter = os.getenv("INJECTIVE_GRANTER_PUBLIC_ADDRESS")
grantee = os.getenv("INJECTIVE_GRANTEE_PUBLIC_ADDRESS")
network = Network.testnet()
client = AsyncClient(network)
msg_type_url = "/injective.exchange.v1beta1.MsgCreateDerivativeLimitOrder"
authorizations = await client.fetch_grants(granter=granter, grantee=grantee, msg_type_url=msg_type_url)
print(authorizations)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
authztypes "github.com/cosmos/cosmos-sdk/x/authz"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
granter := "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku"
grantee := "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
msg_type_url := "/injective.exchange.v1beta1.MsgCreateSpotLimitOrder"
req := authztypes.QueryGrantsRequest{
Granter: granter,
Grantee: grantee,
MsgTypeUrl: msg_type_url,
}
ctx := context.Background()
res, err := chainClient.GetAuthzGrants(ctx, req)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
granter | String | The account owner | Yes |
grantee | String | The authorized account | Yes |
msg_type_url | Integer | The authorized message type | No |
Response Parameters
Response Example:
{
"grants":[
{
"authorization":"OrderedDict("[
"(""@type",
"/cosmos.authz.v1beta1.GenericAuthorization"")",
"(""msg",
"/injective.exchange.v1beta1.MsgCreateSpotLimitOrder"")"
]")",
"expiration":"2024-12-07T02:26:01Z"
}
]
}
Parameter | Type | Description |
---|---|---|
grants | Grants | Grants object |
Grants
Parameter | Type | Description |
---|---|---|
authorization | Authorization | Authorization object |
expiration | Expiration | Expiration object |
Authorization
Parameter | Type | Description |
---|---|---|
type_url | String | The authorization type |
value | String | The authorized message |
Expiration
Parameter | Type | Description |
---|---|---|
seconds | String | The expiration time for an authorization |
- Bank
Bank module.
MsgSend
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
# prepare tx msg
msg = composer.MsgSend(
from_address=address.to_acc_bech32(),
to_address="inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
amount=0.000000000000000001,
denom="INJ",
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"fmt"
"os"
"time"
"cosmossdk.io/math"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
sdktypes "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
// initialize grpc client
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
// prepare tx msg
msg := &banktypes.MsgSend{
FromAddress: senderAddress.String(),
ToAddress: "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
Amount: []sdktypes.Coin{{
Denom: "inj", Amount: math.NewInt(1000000000000000000)}, // 1 INJ
},
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
from_address | String | The Injective Chain address of the sender | Yes |
to_address | String | The Injective Chain address of the receiver | Yes |
amount | Integer | The amount of tokens to send | Yes |
denom | String | The token denom | Yes |
Response Parameters
Response Example:
txhash: "52F3AF222FB064E7505FB14D79D703120EBDF8C945B7920F02FE2BB6666F1D50"
raw_log: "[]"
gas wanted: 97455
gas fee: 0.0000487275 INJ
DEBU[0001] broadcastTx with nonce 3490 fn=func1 src="client/chain/chain.go:598"
DEBU[0004] msg batch committed successfully at height 5212593 fn=func1 src="client/chain/chain.go:619" txHash=AD30AE73838AA342072DCC61897AA75548D613D032A3EC9BDD0A5A064C456002
DEBU[0004] nonce incremented to 3491 fn=func1 src="client/chain/chain.go:623"
DEBU[0004] gas wanted: 119871 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.0000599355 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgMultiSend
IP rate limit group: chain
Request Parameters
Request Example:
package main
import (
"fmt"
"os"
"time"
"cosmossdk.io/math"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
sdktypes "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
// initialize grpc client
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
// prepare tx msg
msg := &banktypes.MsgMultiSend{
Inputs: []banktypes.Input{
{
Address: senderAddress.String(),
Coins: []sdktypes.Coin{{
Denom: "inj", Amount: math.NewInt(1000000000000000000)}, // 1 INJ
},
},
{
Address: senderAddress.String(),
Coins: []sdktypes.Coin{{
Denom: "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", Amount: math.NewInt(1000000)}, // 1 USDT
},
},
},
Outputs: []banktypes.Output{
{
Address: "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
Coins: []sdktypes.Coin{{
Denom: "inj", Amount: math.NewInt(1000000000000000000)}, // 1 INJ
},
},
{
Address: "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
Coins: []sdktypes.Coin{{
Denom: "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", Amount: math.NewInt(1000000)}, // 1 USDT
},
},
},
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
Inputs | Input | Inputs | Yes |
Outputs | Output | Outputs | Yes |
Input
Parameter | Type | Description | Required |
---|---|---|---|
address | String | The Injective Chain address of the sender | Yes |
amount | Integer | The amount of tokens to send | Yes |
denom | String | The token denom | Yes |
Output
Parameter | Type | Description | Required |
---|---|---|---|
address | String | The Injective Chain address of the receiver | Yes |
amount | Integer | The amount of tokens to send | Yes |
denom | String | The token denom | Yes |
Response Example:
DEBU[0001] broadcastTx with nonce 30 fn=func1 src="client/chain/chain.go:630"
DEBU[0003] msg batch committed successfully at height 1620903 fn=func1 src="client/chain/chain.go:651" txHash=643F2C0F7FC679609AFE87FC4F3B0F2E81769F75628375BD6F3D27D4C286B240
DEBU[0003] nonce incremented to 31 fn=func1 src="client/chain/chain.go:655"
DEBU[0003] gas wanted: 152844 fn=func1 src="client/chain/chain.go:656"
gas fee: 0.000076422 INJ
QueryAllBalances
Get the bank balance for all denoms.
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
address = "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r"
all_bank_balances = await client.fetch_bank_balances(address=address)
print(all_bank_balances)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
address := "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku"
ctx := context.Background()
res, err := chainClient.GetBankBalances(ctx, address)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
address | String | The Injective Chain address | Yes |
Response Parameters
Response Example:
{
"balances":[
{
"denom":"factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/atom",
"amount":"10000000000"
},
{
"denom":"factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/usdc",
"amount":"10000000000"
},
{
"denom":"factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/weth",
"amount":"5000000000"
},
{
"denom":"factory/inj1aetmaq5pswvfg6nhvgd4lt94qmg23ka3ljgxlm/SHURIKEN",
"amount":"115700000"
},
{
"denom":"factory/inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r/test",
"amount":"1000000"
},
{
"denom":"inj",
"amount":"760662316753211286487"
},
{
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"amount":"9996297948"
}
],
"pagination":{
"total":"7",
"nextKey":""
}
}
{
"balances": [
{
"denom": "ibc/B448C0CA358B958301D328CCDC5D5AD642FC30A6D3AE106FF721DB315F3DDE5C",
"amount": "829149863837"
},
{
"denom": "inj",
"amount": "51142210518226357537"
},
{
"denom": "peggy0x36B3D7ACe7201E28040eFf30e815290D7b37ffaD",
"amount": "4000000000000000000"
},
{
"denom": "share26",
"amount": "1000000000000000000"
}
],
"pagination": {
"total": 4
}
}
Parameter | Type | Description |
---|---|---|
balances | Balances | Balances object |
pagination | Pagination | Pagination object |
Balances
Parameter | Type | Description |
---|---|---|
denom | String | Token denom |
amount | String | Token amount |
Pagination
Parameter | Type | Description |
---|---|---|
total | Integer | Total denoms |
QueryBalance
Get the bank balance for a specific denom.
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
address = "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r"
denom = "inj"
bank_balance = await client.fetch_bank_balance(address=address, denom=denom)
print(bank_balance)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
address := "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku"
denom := "inj"
ctx := context.Background()
res, err := chainClient.GetBankBalance(ctx, address, denom)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
address | String | The Injective Chain address | Yes |
denom | String | The token denom | Yes |
Response Parameters
Response Example:
{
"balance":{
"denom":"inj",
"amount":"760662316753211286487"
}
}
{
"balance": {
"denom": "inj",
"amount": "51142210518226357537"
}
}
Parameter | Type | Description |
---|---|---|
balance | Balance | Balance object |
Balance
Parameter | Type | Description |
---|---|---|
denom | String | Token denom |
amount | String | Token amount |
SpendableBalances
Get the bank spendable balances for a specific address.
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
address = "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r"
spendable_balances = await client.fetch_spendable_balances(address=address)
print(spendable_balances)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/cosmos/cosmos-sdk/types/query"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
address := "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku"
pagination := query.PageRequest{Limit: 10}
ctx := context.Background()
res, err := chainClient.GetBankSpendableBalances(ctx, address, &pagination)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
address | String | Address to query spendable balances for | Yes |
pagination | Paging | Pagination of results | No |
Response Parameters
Response Example:
{
"balances":[
{
"denom":"factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/atom",
"amount":"10000000000"
},
{
"denom":"factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/usdc",
"amount":"10000000000"
},
{
"denom":"factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/weth",
"amount":"5000000000"
},
{
"denom":"factory/inj1aetmaq5pswvfg6nhvgd4lt94qmg23ka3ljgxlm/SHURIKEN",
"amount":"109950000"
},
{
"denom":"factory/inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r/AAA",
"amount":"3000000000"
},
{
"denom":"factory/inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r/ANK",
"amount":"999989999000010"
},
{
"denom":"factory/inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r/APE",
"amount":"999999899000038"
},
{
"denom":"factory/inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r/aaaa",
"amount":"900000928000028"
},
{
"denom":"factory/inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r/test",
"amount":"1000000"
},
{
"denom":"inj",
"amount":"682717353413490977815"
},
{
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"amount":"9996297948"
}
],
"pagination":{
"total":"11",
"nextKey":""
}
}
{
"balances": [
{
"denom": "factory/inj17d34nrgnq5sj24qd6rk4jrnak628wfqxjx9uhz/lpinj1zd8zg8xeerlsrsfzxhpe3xgncrp0txetqye9cl",
"amount": "2000000000000000000"
},
{
"denom": "factory/inj17gkuet8f6pssxd8nycm3qr9d9y699rupv6397z/mitotest1",
"amount": "249999999999999999998"
},
{
"denom": "factory/inj17gkuet8f6pssxd8nycm3qr9d9y699rupv6397z/projx",
"amount": "27877970000000000000"
},
{
"denom": "factory/inj17gkuet8f6pssxd8nycm3qr9d9y699rupv6397z/stinj",
"amount": "103927830000000000000"
},
{
"denom": "factory/inj17q7ds0yh7hhtusff7gz8a5kx2uwxruttlxur96/lpinj1vd0mf8a39xwr9hav2g7e8lmur07utjrjv025kd",
"amount": "29670048440098478542"
},
{
"denom": "factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/aave",
"amount": "110000000000"
},
{
"denom": "factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/atom",
"amount": "20672215991"
},
{
"denom": "factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/crv",
"amount": "110000000000"
},
{
"denom": "factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/cvx",
"amount": "110000000000"
},
{
"denom": "factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/shib",
"amount": "110000000000"
}
],
"pagination": {
"next_key": "ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdGlh"
}
}
Parameter | Type | Description |
---|---|---|
balances | Coin Array | Balance object |
pagination | PageResponse | Pagination of results |
Coin
Parameter | Type | Description |
---|---|---|
denom | String | Token denom |
amount | String | Token amount |
SpendableBalancesByDenom
Get the bank spendable balances for a specific address and denom.
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
address = "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r"
denom = "inj"
spendable_balances = await client.fetch_spendable_balances_by_denom(address=address, denom=denom)
print(spendable_balances)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
address := "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku"
denom := "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"
ctx := context.Background()
res, err := chainClient.GetBankSpendableBalancesByDenom(ctx, address, denom)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
address | String | Address to query spendable balances for | Yes |
denom | String | The token denom | Yes |
Response Parameters
Response Example:
{
"balance":{
"denom":"inj",
"amount":"682717353413490977815"
}
}
{
"balance": {
"denom": "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"amount": "172767664766"
}
}
Parameter | Type | Description |
---|---|---|
balance | Coin | Balance object |
Coin
Parameter | Type | Description |
---|---|---|
denom | String | Token denom |
amount | String | Token amount |
TotalSupply
Get the total supply for all tokens
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
total_supply = await client.fetch_total_supply(
pagination=PaginationOption(limit=10),
)
print(total_supply)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/cosmos/cosmos-sdk/types/query"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
pagination := query.PageRequest{Limit: 10}
ctx := context.Background()
res, err := chainClient.GetBankTotalSupply(ctx, &pagination)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
pagination | Paging | Pagination of results | No |
Response Parameters
Response Example:
{
"supply":[
{
"denom":"factory/inj104y00apw6uu26gthl7cafztdy67hhmwksekdem/position",
"amount":"64120252107"
},
{
"denom":"factory/inj106rseec0xmv5k06aaf8jsnr57ajw76rxa3gpwm/position",
"amount":"192927104"
},
{
"denom":"factory/inj107aqkjc3t5r3l9j4n9lgrma5tm3jav8qgppz6m/position",
"amount":"1921200000000000000000"
},
{
"denom":"factory/inj107skcseta3egagj822d3qdgusx7a7ua7sepmcf/position",
"amount":"52973849072"
},
{
"denom":"factory/inj107srzqksjtdevlpw888vuyrnqmlpjuv64ytm85/position",
"amount":"777131899999"
},
{
"denom":"factory/inj108t3mlej0dph8er6ca2lq5cs9pdgzva5mqsn5p/position",
"amount":"5556700000000000000"
},
{
"denom":"factory/inj109rcepnmg7ewjcc4my3448jm3h0yjdwcl6kmnl/position",
"amount":"642300000000"
},
{
"denom":"factory/inj10ajd3f46mp755wmhgke8w4vcegfjndwfzymf82/position",
"amount":"725247250499"
},
{
"denom":"factory/inj10fz2cj00ee80y76pdzg06dxfamat8nfpr9vl5s/position",
"amount":"4067730000000000000000"
},
{
"denom":"factory/inj10hmmvlqq6rrlf2c2v982d6xqsns4m3sy086r27/position",
"amount":"761148481800"
}
],
"pagination":{
"nextKey":"ZmFjdG9yeS9pbmoxMG52MjB4ZTR4MzI1c3E1NTdkZGNtc3lsYTd6YWo2cG5zc3JmdzkvcG9zaXRpb24=",
"total":"0"
}
}
{
"supply": [
{
"denom": "factory/inj104y00apw6uu26gthl7cafztdy67hhmwksekdem/position",
"amount": "64120252107"
},
{
"denom": "factory/inj106rseec0xmv5k06aaf8jsnr57ajw76rxa3gpwm/position",
"amount": "192927104"
},
{
"denom": "factory/inj107aqkjc3t5r3l9j4n9lgrma5tm3jav8qgppz6m/position",
"amount": "1921200000000000000000"
},
{
"denom": "factory/inj107skcseta3egagj822d3qdgusx7a7ua7sepmcf/position",
"amount": "52973849072"
},
{
"denom": "factory/inj107srzqksjtdevlpw888vuyrnqmlpjuv64ytm85/position",
"amount": "777131899999"
},
{
"denom": "factory/inj108t3mlej0dph8er6ca2lq5cs9pdgzva5mqsn5p/position",
"amount": "5556700000000000000"
},
{
"denom": "factory/inj109rcepnmg7ewjcc4my3448jm3h0yjdwcl6kmnl/position",
"amount": "642300000000"
},
{
"denom": "factory/inj10ajd3f46mp755wmhgke8w4vcegfjndwfzymf82/position",
"amount": "725247250499"
},
{
"denom": "factory/inj10fz2cj00ee80y76pdzg06dxfamat8nfpr9vl5s/position",
"amount": "4067730000000000000000"
},
{
"denom": "factory/inj10hmmvlqq6rrlf2c2v982d6xqsns4m3sy086r27/position",
"amount": "761148481800"
}
],
"pagination": {
"next_key": "ZmFjdG9yeS9pbmoxMG52MjB4ZTR4MzI1c3E1NTdkZGNtc3lsYTd6YWo2cG5zc3JmdzkvcG9zaXRpb24="
}
}
Parameter | Type | Description |
---|---|---|
supply | Coin Array | Array of supply for each token |
pagination | PageResponse | Pagination of results |
Coin
Parameter | Type | Description |
---|---|---|
denom | String | Token denom |
amount | String | Token amount |
SupplyOf
Queries the supply of a single token
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
supply_of = await client.fetch_supply_of(denom="inj")
print(supply_of)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
denom := "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"
ctx := context.Background()
res, err := chainClient.GetBankSupplyOf(ctx, denom)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | Token denom | Yes |
Response Parameters
Response Example:
{'amount': {'denom': 'inj', 'amount': '926435158902805147647209906101604'}}
{
"amount": {
"denom": "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"amount": "999999965050607001998"
}
}
Parameter | Type | Description |
---|---|---|
amount | Coin | Supply for the token |
Coin
Parameter | Type | Description |
---|---|---|
denom | String | Token denom |
amount | String | Token amount |
DenomMetadata
Queries the metadata of a single token
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
denom = "factory/inj107aqkjc3t5r3l9j4n9lgrma5tm3jav8qgppz6m/position"
metadata = await client.fetch_denom_metadata(denom=denom)
print(metadata)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
denom := "factory/inj107aqkjc3t5r3l9j4n9lgrma5tm3jav8qgppz6m/position"
ctx := context.Background()
res, err := chainClient.GetDenomMetadata(ctx, denom)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | Token denom | Yes |
Response Parameters
Response Example:
{
"metadata":{
"denomUnits":[
{
"denom":"factory/inj107aqkjc3t5r3l9j4n9lgrma5tm3jav8qgppz6m/position",
"exponent":0,
"aliases":[
]
}
],
"base":"factory/inj107aqkjc3t5r3l9j4n9lgrma5tm3jav8qgppz6m/position",
"description":"",
"display":"",
"name":"",
"symbol":"",
"uri":"",
"uriHash":""
}
}
{
"metadata": {
"denom_units": [
{
"denom": "factory/inj107aqkjc3t5r3l9j4n9lgrma5tm3jav8qgppz6m/position"
}
],
"base": "factory/inj107aqkjc3t5r3l9j4n9lgrma5tm3jav8qgppz6m/position"
}
}
Parameter | Type | Description |
---|---|---|
metadata | Metadata | Token information |
Metadata
Parameter | Type | Description |
---|---|---|
description | String | Token description |
denom_units | DenomUnit Array | DenomUnits |
base | String | Token denom |
display | String | Token display name |
name | String | Token name |
symbol | String | Token symbol |
uri | String | In general a URI to a document with additional information |
uri_hash | String | SHA256 hash of a document pointed by URI |
DenomsMetadata
Queries the metadata of all tokens
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
denoms = await client.fetch_denoms_metadata(
pagination=PaginationOption(limit=10),
)
print(denoms)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/cosmos/cosmos-sdk/types/query"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
pagination := query.PageRequest{Limit: 10}
ctx := context.Background()
res, err := chainClient.GetDenomsMetadata(ctx, &pagination)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
pagination | Paging | Pagination of results | No |
Response Parameters
Response Example:
{
"metadatas":[
{
"denomUnits":[
{
"denom":"factory/inj104y00apw6uu26gthl7cafztdy67hhmwksekdem/position",
"exponent":0,
"aliases":[
]
}
],
"base":"factory/inj104y00apw6uu26gthl7cafztdy67hhmwksekdem/position",
"description":"",
"display":"",
"name":"",
"symbol":"",
"uri":"",
"uriHash":""
},
{
"denomUnits":[
{
"denom":"factory/inj106rseec0xmv5k06aaf8jsnr57ajw76rxa3gpwm/position",
"exponent":0,
"aliases":[
]
}
],
"base":"factory/inj106rseec0xmv5k06aaf8jsnr57ajw76rxa3gpwm/position",
"description":"",
"display":"",
"name":"",
"symbol":"",
"uri":"",
"uriHash":""
},
{
"denomUnits":[
{
"denom":"factory/inj107aqkjc3t5r3l9j4n9lgrma5tm3jav8qgppz6m/position",
"exponent":0,
"aliases":[
]
}
],
"base":"factory/inj107aqkjc3t5r3l9j4n9lgrma5tm3jav8qgppz6m/position",
"description":"",
"display":"",
"name":"",
"symbol":"",
"uri":"",
"uriHash":""
},
{
"denomUnits":[
{
"denom":"factory/inj107skcseta3egagj822d3qdgusx7a7ua7sepmcf/position",
"exponent":0,
"aliases":[
]
}
],
"base":"factory/inj107skcseta3egagj822d3qdgusx7a7ua7sepmcf/position",
"description":"",
"display":"",
"name":"",
"symbol":"",
"uri":"",
"uriHash":""
},
{
"denomUnits":[
{
"denom":"factory/inj107srzqksjtdevlpw888vuyrnqmlpjuv64ytm85/position",
"exponent":0,
"aliases":[
]
}
],
"base":"factory/inj107srzqksjtdevlpw888vuyrnqmlpjuv64ytm85/position",
"description":"",
"display":"",
"name":"",
"symbol":"",
"uri":"",
"uriHash":""
},
{
"denomUnits":[
{
"denom":"factory/inj108t3mlej0dph8er6ca2lq5cs9pdgzva5mqsn5p/position",
"exponent":0,
"aliases":[
]
}
],
"base":"factory/inj108t3mlej0dph8er6ca2lq5cs9pdgzva5mqsn5p/position",
"description":"",
"display":"",
"name":"",
"symbol":"",
"uri":"",
"uriHash":""
},
{
"denomUnits":[
{
"denom":"factory/inj109rcepnmg7ewjcc4my3448jm3h0yjdwcl6kmnl/position",
"exponent":0,
"aliases":[
]
}
],
"base":"factory/inj109rcepnmg7ewjcc4my3448jm3h0yjdwcl6kmnl/position",
"description":"",
"display":"",
"name":"",
"symbol":"",
"uri":"",
"uriHash":""
},
{
"denomUnits":[
{
"denom":"factory/inj10ajd3f46mp755wmhgke8w4vcegfjndwfzymf82/position",
"exponent":0,
"aliases":[
]
}
],
"base":"factory/inj10ajd3f46mp755wmhgke8w4vcegfjndwfzymf82/position",
"description":"",
"display":"",
"name":"",
"symbol":"",
"uri":"",
"uriHash":""
},
{
"denomUnits":[
{
"denom":"factory/inj10fz2cj00ee80y76pdzg06dxfamat8nfpr9vl5s/position",
"exponent":0,
"aliases":[
]
}
],
"base":"factory/inj10fz2cj00ee80y76pdzg06dxfamat8nfpr9vl5s/position",
"description":"",
"display":"",
"name":"",
"symbol":"",
"uri":"",
"uriHash":""
},
{
"denomUnits":[
{
"denom":"factory/inj10hmmvlqq6rrlf2c2v982d6xqsns4m3sy086r27/position",
"exponent":0,
"aliases":[
]
}
],
"base":"factory/inj10hmmvlqq6rrlf2c2v982d6xqsns4m3sy086r27/position",
"description":"",
"display":"",
"name":"",
"symbol":"",
"uri":"",
"uriHash":""
}
],
"pagination":{
"nextKey":"ZmFjdG9yeS9pbmoxMGptcDZzZ2g0Y2M2enQzZThndzA1d2F2dmVqZ3I1cHc2bThqNzUvYWs=",
"total":"0"
}
}
{
"metadatas": [
{
"denom_units": [
{
"denom": "factory/inj104y00apw6uu26gthl7cafztdy67hhmwksekdem/position"
}
],
"base": "factory/inj104y00apw6uu26gthl7cafztdy67hhmwksekdem/position"
},
{
"denom_units": [
{
"denom": "factory/inj106rseec0xmv5k06aaf8jsnr57ajw76rxa3gpwm/position"
}
],
"base": "factory/inj106rseec0xmv5k06aaf8jsnr57ajw76rxa3gpwm/position"
},
{
"denom_units": [
{
"denom": "factory/inj107aqkjc3t5r3l9j4n9lgrma5tm3jav8qgppz6m/position"
}
],
"base": "factory/inj107aqkjc3t5r3l9j4n9lgrma5tm3jav8qgppz6m/position"
},
{
"denom_units": [
{
"denom": "factory/inj107skcseta3egagj822d3qdgusx7a7ua7sepmcf/position"
}
],
"base": "factory/inj107skcseta3egagj822d3qdgusx7a7ua7sepmcf/position"
},
{
"denom_units": [
{
"denom": "factory/inj107srzqksjtdevlpw888vuyrnqmlpjuv64ytm85/position"
}
],
"base": "factory/inj107srzqksjtdevlpw888vuyrnqmlpjuv64ytm85/position"
},
{
"denom_units": [
{
"denom": "factory/inj108t3mlej0dph8er6ca2lq5cs9pdgzva5mqsn5p/position"
}
],
"base": "factory/inj108t3mlej0dph8er6ca2lq5cs9pdgzva5mqsn5p/position"
},
{
"denom_units": [
{
"denom": "factory/inj109rcepnmg7ewjcc4my3448jm3h0yjdwcl6kmnl/position"
}
],
"base": "factory/inj109rcepnmg7ewjcc4my3448jm3h0yjdwcl6kmnl/position"
},
{
"denom_units": [
{
"denom": "factory/inj10ajd3f46mp755wmhgke8w4vcegfjndwfzymf82/position"
}
],
"base": "factory/inj10ajd3f46mp755wmhgke8w4vcegfjndwfzymf82/position"
},
{
"denom_units": [
{
"denom": "factory/inj10fz2cj00ee80y76pdzg06dxfamat8nfpr9vl5s/position"
}
],
"base": "factory/inj10fz2cj00ee80y76pdzg06dxfamat8nfpr9vl5s/position"
},
{
"denom_units": [
{
"denom": "factory/inj10hmmvlqq6rrlf2c2v982d6xqsns4m3sy086r27/position"
}
],
"base": "factory/inj10hmmvlqq6rrlf2c2v982d6xqsns4m3sy086r27/position"
}
],
"pagination": {
"next_key": "ZmFjdG9yeS9pbmoxMGptcDZzZ2g0Y2M2enQzZThndzA1d2F2dmVqZ3I1cHc2bThqNzUvYWs="
}
}
Parameter | Type | Description |
---|---|---|
metadatas | Metadata Array | Tokens information |
pagination | Pagination | Pagination object |
Metadata
Parameter | Type | Description |
---|---|---|
description | String | Token description |
denom_units | DenomUnit Array | DenomUnits |
base | String | Token denom |
display | String | Token display name |
name | String | Token name |
symbol | String | Token symbol |
uri | String | In general a URI to a document with additional information |
uri_hash | String | SHA256 hash of a document pointed by URI |
DenomsOwners
Queries for all account addresses that own a particular token
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
denom = "inj"
owners = await client.fetch_denom_owners(
denom=denom,
pagination=PaginationOption(limit=10),
)
print(owners)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"github.com/cosmos/cosmos-sdk/types/query"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
denom := "factory/inj107aqkjc3t5r3l9j4n9lgrma5tm3jav8qgppz6m/position"
pagination := query.PageRequest{Limit: 10}
ctx := context.Background()
res, err := chainClient.GetDenomOwners(ctx, denom, &pagination)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | Token denom | Yes |
pagination | Paging | Pagination of results | No |
Response Parameters
Response Example:
{
"denomOwners":[
{
"address":"inj1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqe2hm49",
"balance":{
"denom":"inj",
"amount":"420000000000000010003"
}
},
{
"address":"inj1qqqqqqqpa95pcsnxa3927hlym6t8quhwlgkmqt",
"balance":{
"denom":"inj",
"amount":"10000000000000000"
}
},
{
"address":"inj1qqqqqqzw4rg692t320252whr7gjp4k86lun8hp",
"balance":{
"denom":"inj",
"amount":"143805431033925108"
}
},
{
"address":"inj1qqqqqqr0g47qlr6kqveans58w2raj25j095pad",
"balance":{
"denom":"inj",
"amount":"199999568185205399700"
}
},
{
"address":"inj1qqqqqq4ze7h25mf9w8h8h02h807yj2fxzl27m8",
"balance":{
"denom":"inj",
"amount":"10000"
}
},
{
"address":"inj1qqqqqqhn9sygdmn966q9n77mwmhk56vkkae2d3",
"balance":{
"denom":"inj",
"amount":"260838118080821668174"
}
},
{
"address":"inj1qqqqqr5pwtzk2n8tswusllscjagw3w9k3dyceg",
"balance":{
"denom":"inj",
"amount":"826945326095056784"
}
},
{
"address":"inj1qqqqqrk35e4y5r3aklpeelkkr9hkxq4k4y55c9",
"balance":{
"denom":"inj",
"amount":"49800000000000000"
}
},
{
"address":"inj1qqqqqyyfzemqpsjjtrdzn5hzept7c95f8zyhmn",
"balance":{
"denom":"inj",
"amount":"599500010155805818137328"
}
},
{
"address":"inj1qqqqqy2thegwe8473jk5u6th93uc488n4ltucm",
"balance":{
"denom":"inj",
"amount":"40027858757349727870"
}
}
],
"pagination":{
"nextKey":"FAAAADLLRNDsOnihjI3alQcdNB0a",
"total":"0"
}
}
{
"denom_owners": [
{
"address": "inj15e2qkdv5kf0w79f34t0c0w3j7arhxe4gy6juwf",
"balance": {
"denom": "factory/inj107aqkjc3t5r3l9j4n9lgrma5tm3jav8qgppz6m/position",
"amount": "1921200000000000000000"
}
}
],
"pagination": {}
}
Parameter | Type | Description |
---|---|---|
denom_owners | DenomOwner Array | Token owners |
pagination | Pagination | Pagination object |
DenomOwner
Parameter | Type | Description |
---|---|---|
address | String | Account address |
balance | Coin | Token amount |
Coin
Parameter | Type | Description |
---|---|---|
denom | String | Token denom |
amount | String | Token amount |
SendEnabled
This query only returns denominations that have specific SendEnabled settings. Any denomination that does not have a specific setting will use the default params.default_send_enabled, and will not be returned by this query.
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
denom = "inj"
enabled = await client.fetch_send_enabled(
denoms=[denom],
pagination=PaginationOption(limit=10),
)
print(enabled)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"github.com/cosmos/cosmos-sdk/types/query"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
denoms := []string{"factory/inj107aqkjc3t5r3l9j4n9lgrma5tm3jav8qgppz6m/position"}
pagination := query.PageRequest{Limit: 10}
ctx := context.Background()
res, err := chainClient.GetBankSendEnabled(ctx, denoms, &pagination)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
denom | String Array | Token denoms | No |
pagination | Paging | Pagination of results | No |
Response Parameters
Response Example:
Parameter | Type | Description |
---|---|---|
send_enabled | SendEnabled Array | SendEnabled information |
pagination | Pagination | Pagination object |
SendEnabled
Parameter | Type | Description |
---|---|---|
denom | String | Token denom |
enabled | Bool | True or False |
- Chain Stream
Chain Stream is a gRPC service that allows clients to receive low-latency updates from the Injective Chain. This API is exposed directly from a dedicated server running on a chain node and provides the fastest way to receive events data (like trades, orders, balances, etc.). Under the hood, a stream message is computed by the chain node immediately after the event is emitted and is sent to the client via a gRPC stream once the block is committed.
Stream Request
Its possible to specify multiple filters to customize the stream.
A filter can be specified with a list of values, generally MarketIds, SubaccountIds and Accounts address.
A filter can also be omitted, in this case the stream will return all the events for the specified type.
In addition each filter supports a *
wildcard to match all possible values.
import asyncio
from typing import Any, Dict
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.composer import Composer
from pyinjective.core.network import Network
async def chain_stream_event_processor(event: Dict[str, Any]):
print(event)
def stream_error_processor(exception: RpcError):
print(f"There was an error listening to chain stream updates ({exception})")
def stream_closed_processor():
print("The chain stream updates stream has been closed")
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
composer = Composer(network=network.string())
subaccount_id = "0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000"
inj_usdt_market = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
inj_usdt_perp_market = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
bank_balances_filter = composer.chain_stream_bank_balances_filter(
accounts=["inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"]
)
subaccount_deposits_filter = composer.chain_stream_subaccount_deposits_filter(subaccount_ids=[subaccount_id])
spot_trades_filter = composer.chain_stream_trades_filter(subaccount_ids=["*"], market_ids=[inj_usdt_market])
derivative_trades_filter = composer.chain_stream_trades_filter(
subaccount_ids=["*"], market_ids=[inj_usdt_perp_market]
)
spot_orders_filter = composer.chain_stream_orders_filter(
subaccount_ids=[subaccount_id], market_ids=[inj_usdt_market]
)
derivative_orders_filter = composer.chain_stream_orders_filter(
subaccount_ids=[subaccount_id], market_ids=[inj_usdt_perp_market]
)
spot_orderbooks_filter = composer.chain_stream_orderbooks_filter(market_ids=[inj_usdt_market])
derivative_orderbooks_filter = composer.chain_stream_orderbooks_filter(market_ids=[inj_usdt_perp_market])
positions_filter = composer.chain_stream_positions_filter(
subaccount_ids=[subaccount_id], market_ids=[inj_usdt_perp_market]
)
oracle_price_filter = composer.chain_stream_oracle_price_filter(symbols=["INJ", "USDT"])
task = asyncio.get_event_loop().create_task(
client.listen_chain_stream_updates(
callback=chain_stream_event_processor,
on_end_callback=stream_closed_processor,
on_status_callback=stream_error_processor,
bank_balances_filter=bank_balances_filter,
subaccount_deposits_filter=subaccount_deposits_filter,
spot_trades_filter=spot_trades_filter,
derivative_trades_filter=derivative_trades_filter,
spot_orders_filter=spot_orders_filter,
derivative_orders_filter=derivative_orders_filter,
spot_orderbooks_filter=spot_orderbooks_filter,
derivative_orderbooks_filter=derivative_orderbooks_filter,
positions_filter=positions_filter,
oracle_price_filter=oracle_price_filter,
)
)
await asyncio.sleep(delay=60)
task.cancel()
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
chainStreamModule "github.com/InjectiveLabs/sdk-go/chain/stream/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
"",
nil,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
subaccountId := "0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000"
injUsdtMarket := "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
injUsdtPerpMarket := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
req := chainStreamModule.StreamRequest{
BankBalancesFilter: &chainStreamModule.BankBalancesFilter{
Accounts: []string{"*"},
},
SpotOrdersFilter: &chainStreamModule.OrdersFilter{
MarketIds: []string{injUsdtMarket},
SubaccountIds: []string{subaccountId},
},
DerivativeOrdersFilter: &chainStreamModule.OrdersFilter{
MarketIds: []string{injUsdtPerpMarket},
SubaccountIds: []string{subaccountId},
},
SpotTradesFilter: &chainStreamModule.TradesFilter{
MarketIds: []string{injUsdtMarket},
SubaccountIds: []string{"*"},
},
SubaccountDepositsFilter: &chainStreamModule.SubaccountDepositsFilter{
SubaccountIds: []string{subaccountId},
},
DerivativeOrderbooksFilter: &chainStreamModule.OrderbookFilter{
MarketIds: []string{injUsdtPerpMarket},
},
SpotOrderbooksFilter: &chainStreamModule.OrderbookFilter{
MarketIds: []string{injUsdtMarket},
},
PositionsFilter: &chainStreamModule.PositionsFilter{
SubaccountIds: []string{subaccountId},
MarketIds: []string{injUsdtPerpMarket},
},
DerivativeTradesFilter: &chainStreamModule.TradesFilter{
SubaccountIds: []string{"*"},
MarketIds: []string{injUsdtPerpMarket},
},
OraclePriceFilter: &chainStreamModule.OraclePriceFilter{
Symbol: []string{"INJ", "USDT"},
},
}
ctx := context.Background()
stream, err := chainClient.ChainStream(ctx, req)
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
return
default:
res, err := stream.Recv()
if err != nil {
panic(err)
return
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
}
}
Request parameters
Parameter | Type | Description | Required |
---|---|---|---|
BankBalancesFilter | BankBalancesFilter | Filter for bank balances events | No |
SpotOrdersFilter | OrdersFilter | Filter for spot orders events | No |
DerivativeOrdersFilter | OrdersFilter | Filter for derivative orders events | No |
SpotTradesFilter | TradesFilter | Filter for spot trades events | No |
SubaccountDepositsFilter | SubaccountDepositsFilter | Filter for subaccount deposits events | No |
DerivativeOrderbooksFilter | OrderbookFilter | Filter for derivative order books events | No |
SpotOrderbooksFilter | OrderbookFilter | Filter for spot order books events | No |
PositionsFilter | PositionsFilter | Filter for positions events | No |
DerivativeTradesFilter | TradesFilter | Filter for derivative trades events | No |
OraclePriceFilter | OraclePriceFilter | Filter for oracle price events | No |
BankBalancesFilter
Structure for filtering bank balances.
Parameter | Type | Description | Required |
---|---|---|---|
Accounts | String Array | List of account addresses. | No |
SubaccountDepositsFilter
Structure for filtering subaccount deposits.
Parameter | Type | Description | Required |
---|---|---|---|
SubaccountIds | String Array | List of subaccount IDs. | No |
TradesFilter
Structure for filtering trades.
Parameter | Type | Description | Required |
---|---|---|---|
SubaccountIds | String Array | List of subaccount IDs. | No |
MarketIds | String Array | List of market IDs. | No |
OrdersFilter
Structure for filtering orders.
Parameter | Type | Description | Required |
---|---|---|---|
SubaccountIds | String Array | List of subaccount IDs. | No |
MarketIds | String Array | List of market IDs. | No |
OrderbookFilter
Structure for filtering orderbook.
Parameter | Type | Description | Required |
---|---|---|---|
MarketIds | String Array | List of market IDs. | No |
PositionsFilter
Structure for filtering positions.
Parameter | Type | Description | Required |
---|---|---|---|
SubaccountIds | String Array | List of subaccount IDs. | No |
MarketIds | String Array | List of market IDs. | No |
OraclePriceFilter
Structure for filtering oracle prices.
Parameter | Type | Description | Required |
---|---|---|---|
Symbol | String Array | List of symbols. | No |
StreamResponse
The stream response is a stream of events that are sent to the client. Each message contains a list of events that are filtered by the request parameters and it's identified by the block height.
Response parameters
Response structure for the data stream.
Parameter | Type | Description | Required |
---|---|---|---|
BlockHeight | Integer | The current block height. | |
BlockTime | Integer | The current block timestamp | |
BankBalances | BankBalance Array | List of bank balances. | |
SubaccountDeposits | SubaccountDeposits Array | List of subaccount deposits. | |
SpotTrades | SpotTrade Array | List of spot trades. | |
DerivativeTrades | DerivativeTrade Array | List of derivative trades. | |
SpotOrders | SpotOrder Array | List of spot orders. | |
DerivativeOrders | DerivativeOrder Array | List of derivative orders. | |
SpotOrderbookUpdates | OrderbookUpdate Array | List of spot orderbook updates. | |
DerivativeOrderbookUpdates | OrderbookUpdate Array | List of derivative orderbook updates. | |
Positions | Position Array | List of positions. | |
OraclePrices | OraclePrice Array | List of oracle prices. |
BankBalance
Structure for bank balances.
Parameter | Type | Description | Required |
---|---|---|---|
Account | String | The account name. | |
Balances | Coins | The list of available balances. |
SubaccountDeposits
Structure for subaccount deposits.
Parameter | Type | Description | Required |
---|---|---|---|
SubaccountId | String | The subaccount ID. | |
Deposits | Deposit Array | List of deposits. |
SpotTrade
Structure for spot trades.
Parameter | Type | Description | Required |
---|---|---|---|
MarketId | String | The market ID. | |
IsBuy | bool | True if it is a buy, False if it is a sell. | |
ExecutionType | String | The execution type. | |
Quantity | Dec | The quantity of the trade. | |
Price | Dec | The price of the trade. | |
SubaccountId | String | The subaccount ID that executed the trade. | |
Fee | Dec | The fee of the trade. | |
OrderHash | String | The hash of the order. | |
FeeRecipientAddress | String | The fee recipient address. | |
Cid | String | Identifier for the order specified by the user | |
TradeId | String | Unique identifier to differentiate between trades |
DerivativeTrade
Structure for derivative trades.
Parameter | Type | Description | Required |
---|---|---|---|
MarketId | String | The market ID. | |
IsBuy | bool | True if it is a buy, False if it is a sell. | |
ExecutionType | String | The execution type. | |
SubaccountId | String | The subaccount ID that executed the trade. | |
PositionDelta | PositionDelta | The position delta. | |
Payout | Dec | The payout of the trade. | |
Fee | Dec | The fee of the trade. | |
OrderHash | String | The hash of the order. | |
FeeRecipientAddress | String | The fee recipient address. | |
Cid | String | Identifier for the order specified by the user | |
TradeId | String | Unique identifier to differentiate between trades |
SpotOrder
Structure for spot orders.
Parameter | Type | Description | Required |
---|---|---|---|
MarketId | String | The market ID. | |
Order | SpotLimitOrder | The spot order. |
DerivativeOrder
Structure for derivative orders.
Parameter | Type | Description | Required |
---|---|---|---|
MarketId | String | The market ID. | |
Order | DerivativeLimitOrder | The derivative order. | |
IsMarket | bool | True if it is a market order, False if it is a limit order. |
OrderbookUpdate
Structure for orderbook updates.
Parameter | Type | Description | Required |
---|---|---|---|
Seq | Integer | The sequence number. | |
Orderbook | Orderbook | The updated orderbook. |
Position
Structure for positions.
Parameter | Type | Description | Required |
---|---|---|---|
MarketId | String | The market ID. | |
SubaccountId | String | The subaccount ID. | |
IsLong | bool | True if it is a long position, False if it is short. | |
Quantity | Dec | The quantity of the position. | |
EntryPrice | Dec | The entry price of the position. | |
Margin | Dec | The margin of the position. | |
CumulativeFundingEntry | Dec | The cumulative funding entry of the position. |
OraclePrice
Structure for oracle prices.
Parameter | Type | Description | Required |
---|---|---|---|
Symbol | String | The symbol of the price. | Yes |
Price | Dec | The oracle price. | Yes |
Type | String | The price type. |
SubaccountDeposit
Structure for subaccount deposits.
Parameter | Type | Description | Required |
---|---|---|---|
Denom | String | The denomination of the deposit. | |
Deposit | Deposit | The deposit details. |
Deposit
Structure for deposit details.
Parameter | Type | Description | Required |
---|---|---|---|
AvailableBalance | Dec | The available balance in the deposit. | |
TotalBalance | Dec | The total balance in the deposit. |
SpotLimitOrder
Structure for spot limit orders.
Parameter | Type | Description | Required |
---|---|---|---|
OrderInfo | OrderInfo | Information about the order. | |
OrderType | OrderType | The order type. | |
Fillable | Dec | The remaining fillable quantity. | |
TriggerPrice | Dec (optional) | The trigger price for stop/take orders. | |
OrderHash | []byte (optional) | The hash of the order. |
DerivativeLimitOrder
Structure for derivative limit orders.
Parameter | Type | Description | Required |
---|---|---|---|
OrderInfo | OrderInfo | Information about the order. | |
OrderType | OrderType | The order type. | |
Margin | Dec | The margin used by the order. | |
Fillable | Dec | The remaining fillable quantity. | |
TriggerPrice | Dec (optional) | The trigger price for stop/take orders. | |
OrderHash | []byte (optional) | The hash of the order. |
OrderInfo
Structure for order information.
Parameter | Type | Description | Required |
---|---|---|---|
SubaccountId | String | The subaccount ID of the order creator. | |
FeeRecipient | String | The fee recipient address for the order. | |
Price | Dec | The price of the order. | |
Quantity | Dec | The quantity of the order. | |
Cid | String | Identifier for the order specified by the user |
OrderType
Any of the possible order types
Orderbook
Structure for the orderbook.
Parameter | Type | Description | Required |
---|---|---|---|
MarketId | String | The market ID. | |
BuyLevels | Level Array | List of buy levels. | |
SellLevels | Level Array | List of sell levels. |
Level
Structure for the orderbook levels.
Parameter | Type | Description | Required |
---|---|---|---|
P | Dec | The price of the level. | |
Q | Dec | The quantity of the level. |
- Chain Exchange
Includes all the messages and queries related to exchange accounts, orders and trades
SubaccountDeposits
Retrieves a subaccount's deposits
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
deposits = await client.fetch_subaccount_deposits(subaccount_id=subaccount_id)
print(deposits)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
subaccountId := chainClient.Subaccount(senderAddress, 0)
ctx := context.Background()
res, err := chainClient.FetchSubaccountDeposits(ctx, subaccountId.Hex())
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | The subaccount ID | No |
subaccount | Subaccount | The subaccount info | No |
Subaccount
Parameter | Type | Description | Required |
---|---|---|---|
trader | String | The subaccount trader address | No |
subaccount_nonce | Integer | The subaccount nonce number | No |
Response Parameters
Response Example:
{
"deposits":{
"factory/inj17gkuet8f6pssxd8nycm3qr9d9y699rupv6397z/demo":{
"availableBalance":"0",
"totalBalance":"0"
},
"factory/inj17gkuet8f6pssxd8nycm3qr9d9y699rupv6397z/stinj":{
"availableBalance":"0",
"totalBalance":"0"
},
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/Talis-3":{
"availableBalance":"0",
"totalBalance":"0"
},
"inj":{
"availableBalance":"0",
"totalBalance":"22458000000000000000000000000000000000"
},
"peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7":{
"availableBalance":"0",
"totalBalance":"0"
},
"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5":{
"availableBalance":"342932031115126491",
"totalBalance":"324904824830342932031115126449"
},
"factory/inj17vytdwqczqz72j65saukplrktd4gyfme5agf6c/atom":{
"availableBalance":"0",
"totalBalance":"0"
}
}
}
Parameter | Type | Description |
---|---|---|
deposits | Map String to Deposit | Map with the token denom as key, and a deposit information as value |
Deposit
Parameter | Type | Description |
---|---|---|
available_balance | Decimal | Deposit available balance |
total_balance | Decimal | Deposit total balance |
SubaccountDeposit
Retrieves a subaccount's deposit
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
deposit = await client.fetch_subaccount_deposit(subaccount_id=subaccount_id, denom="inj")
print(deposit)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
subaccountId := chainClient.Subaccount(senderAddress, 0)
denom := "inj"
ctx := context.Background()
res, err := chainClient.FetchSubaccountDeposit(ctx, subaccountId.Hex(), denom)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | The subaccount ID | Yes |
denom | String | The token denom | Yes |
Response Parameters
Response Example:
{
"deposits":{
"availableBalance":"0",
"totalBalance":"22458000000000000000000000000000000000"
}
}
Parameter | Type | Description |
---|---|---|
deposits | Deposit | The subaccount's deposits for the specified token |
Deposit
Parameter | Type | Description |
---|---|---|
available_balance | Decimal | Deposit available balance |
total_balance | Decimal | Deposit total balance |
ExchangeBalances
Retrieves the balances for all accounts registered in the exchange module
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
balances = await client.fetch_exchange_balances()
print(balances)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchExchangeBalances(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
No parameters
Response Parameters
Response Example:
{
"balances":{
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"deposits":{
"availableBalance":"0",
"totalBalance":"0"
},
"subaccountId":"0x0000000001e9681c4266ec4aaf5fe4de967072ee000000000000000000000000"
}
}
Parameter | Type | Description |
---|---|---|
deposits | Deposit | The subaccount's deposits for the specified token |
Balance
Parameter | Type | Description |
---|---|---|
subaccount_id | String | The subaccount ID |
denom | String | The token denom |
deposits | Deposit | The token deposit details |
Deposit
Parameter | Type | Description |
---|---|---|
available_balance | Decimal | Deposit available balance |
total_balance | Decimal | Deposit total balance |
AggregateVolume
Retrieves the aggregate volumes for the specified account or subaccount
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
subaccount_id = address.get_subaccount_id(index=0)
volume = await client.fetch_aggregate_volume(account=address.to_acc_bech32())
print(volume)
volume = await client.fetch_aggregate_volume(account=subaccount_id)
print(volume)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
subaccountId := chainClient.Subaccount(senderAddress, 0)
res, err := chainClient.FetchAggregateVolume(ctx, senderAddress.String())
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
res, err = chainClient.FetchAggregateVolume(ctx, subaccountId.Hex())
if err != nil {
fmt.Println(err)
}
str, _ = json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
account | String | Account address or subaccount id | Yes |
Response Parameters
Response Example:
{
"aggregateVolumes":[
{
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"volume":{
"makerVolume":"1689236673987000000000000000000",
"takerVolume":"501627449819312000000000000000"
}
},
{
"marketId":"0x141e3c92ed55107067ceb60ee412b86256cedef67b1227d6367b4cdf30c55a74",
"volume":{
"makerVolume":"67687000000000000000000000000",
"takerVolume":"5387728000000000000000000000"
}
},
{
"marketId":"0x14f82598b92674598af196770a45e1b808a4ef3aa86eb9ca09aff1aeab33ac46",
"volume":{
"makerVolume":"10648800000000000000000000",
"takerVolume":"21548000000000000000000000"
}
}
]
}
Parameter | Type | Description |
---|---|---|
aggregated_volumes | MarketVolume Array | Volume information. If an address is specified, then the aggregate_volumes will aggregate the volumes across all subaccounts for the address |
MarketVolume
Parameter | Type | Description |
---|---|---|
market_id | String | The market ID |
volume | VolumeRecord | The volume for a particular market |
VolumeRecord
Parameter | Type | Description |
---|---|---|
maker_volume | Decimal | The maker volume |
taker_volume | Decimal | The taker volume |
AggregateVolumes
Retrieves the aggregate volumes for specified accounts
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
volume = await client.fetch_aggregate_volumes(
accounts=[address.to_acc_bech32()],
market_ids=["0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"],
)
print(volume)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
accounts := []string{senderAddress.String()}
marketIds := []string{"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"}
res, err := chainClient.FetchAggregateVolumes(ctx, accounts, marketIds)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
accounts | String Array | List of account addresses and/or subaccount IDs to query for | No |
market_ids | String Array | List of market IDs to query for | No |
Response Parameters
Response Example:
{
"aggregateAccountVolumes":[
{
"account":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"marketVolumes":[
{
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"volume":{
"makerVolume":"1689236673987000000000000000000",
"takerVolume":"501627449819312000000000000000"
}
}
]
}
],
"aggregateMarketVolumes":[
{
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"volume":{
"makerVolume":"3070484904498656000000000000000000",
"takerVolume":"3073070717217233353000000000000000"
}
}
]
}
Parameter | Type | Description |
---|---|---|
aggregated_account_volumes | AggregateAccountVolumeRecord Array | The aggregate volume records for the accounts specified |
aggregated_market_volumes | MarketVolume Array | The aggregate volumes for the markets specified |
AggregateAccountVolumeRecord
Parameter | Type | Description |
---|---|---|
account | String | Account the volume belongs to |
market_volumes | MarketVolume Array | The aggregate volumes for each market |
MarketVolume
Parameter | Type | Description |
---|---|---|
market_id | String | The market ID |
volume | VolumeRecord | The volume for a particular market |
VolumeRecord
Parameter | Type | Description |
---|---|---|
maker_volume | Decimal | The maker volume |
taker_volume | Decimal | The taker volume |
AggregateMarketVolume
Retrieves the aggregate volume for the specified market
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
volume = await client.fetch_aggregate_market_volume(market_id=market_id)
print(volume)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
res, err := chainClient.FetchAggregateMarketVolume(ctx, marketId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The market ID | Yes |
Response Parameters
Response Example:
{
"volume":{
"makerVolume":"3070574313724656000000000000000000",
"takerVolume":"3073160126443233353000000000000000"
}
}
Parameter | Type | Description |
---|---|---|
volume | VolumeRecord | The aggregated market volume information |
VolumeRecord
Parameter | Type | Description |
---|---|---|
maker_volume | Decimal | The maker volume |
taker_volume | Decimal | The taker volume |
AggregateMarketVolumes
Retrieves the aggregate market volumes for specified markets
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
volume = await client.fetch_aggregate_market_volumes(
market_ids=["0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"],
)
print(volume)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketIds := []string{"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"}
res, err := chainClient.FetchAggregateMarketVolumes(ctx, marketIds)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_ids | String Array | List of market IDs to query volume for | No |
Response Parameters
Response Example:
{
"volumes":[
{
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"volume":{
"makerVolume":"3070590556798408000000000000000000",
"takerVolume":"3073176369516985353000000000000000"
}
}
]
}
Parameter | Type | Description |
---|---|---|
volumes | MarketVolume Array | The markets volume information |
MarketVolume
Parameter | Type | Description |
---|---|---|
market_id | String | The market ID |
volume | VolumeRecord | The volume for a particular market |
VolumeRecord
Parameter | Type | Description |
---|---|---|
maker_volume | Decimal | The maker volume |
taker_volume | Decimal | The taker volume |
DenomDecimal
Retrieves the number of decimals used for a denom
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
deposits = await client.fetch_denom_decimal(denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5")
print(deposits)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
denom := "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"
res, err := chainClient.FetchDenomDecimal(ctx, denom)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | The asset denom | Yes |
Response Parameters
Response Example:
{
"decimal":"6"
}
Parameter | Type | Description |
---|---|---|
decimal | Integer | Number of decimals used for the asset |
DenomDecimals
Retrieves the denom decimals for multiple denoms
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
deposits = await client.fetch_denom_decimals(denoms=["inj", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"])
print(deposits)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
denoms := []string{"inj", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"}
res, err := chainClient.FetchDenomDecimals(ctx, denoms)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
denoms | String Array | List of asset denoms | No |
Response Parameters
Response Example:
{
"denomDecimals":[
{
"denom":"inj",
"decimals":"0"
},
{
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"decimals":"6"
}
]
}
Parameter | Type | Description |
---|---|---|
denom_decimals | DenomDecimals Array | List of decimals for the queried denoms |
DenomDecimals
Parameter | Type | Description |
---|---|---|
denom | String | The asset denom |
decimals | Integer | Number of decimals |
SubaccountOrders
Retrieves subaccount's orders
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
orders = await client.fetch_chain_subaccount_orders(
subaccount_id=subaccount_id,
market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
)
print(orders)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
subaccountId := chainClient.Subaccount(senderAddress, 0)
res, err := chainClient.FetchChainSubaccountOrders(ctx, subaccountId.Hex(), marketId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | The subaccount ID | Yes |
market_id | String | Market ID to request for | Yes |
Response Parameters
Response Example:
{
"buyOrders":[
],
"sellOrders":[
]
}
Parameter | Type | Description |
---|---|---|
buy_orders | SubaccountOrderData Array | Buy orders info |
sell_orders | SubaccountOrderData Array | Sell orders info |
SubaccountOrderData
Parameter | Type | Description |
---|---|---|
order | SubaccountOrder | Order info |
order_hash | Bytes | Order hash |
SubaccountOrder
Parameter | Type | Description |
---|---|---|
price | Decimal | Order price |
quantity | Decimal | The amount of the order quantity remaining fillable |
is_reduce_only | Boolean | True if the order is a reduce only order |
cid | String | The client order ID provided by the creator |
SubaccountTradeNonce
Retrieves a subaccount's trade nonce
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
nonce = await client.fetch_subaccount_trade_nonce(
subaccount_id=subaccount_id,
)
print(nonce)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
subaccountId := chainClient.Subaccount(senderAddress, 0)
res, err := chainClient.FetchSubaccountTradeNonce(ctx, subaccountId.Hex())
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | The subaccount ID to query for | Yes |
Response Parameters
Response Example:
{
"nonce":30226
}
Parameter | Type | Description |
---|---|---|
nonce | Integer | The nonce number |
SubaccountOrderMetadata
Retrieves subaccount's order metadata
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
metadata = await client.fetch_subaccount_order_metadata(
subaccount_id=subaccount_id,
)
print(metadata)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
subaccountId := chainClient.Subaccount(senderAddress, 0)
res, err := chainClient.FetchSubaccountOrderMetadata(ctx, subaccountId.Hex())
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | The subaccount ID to query for | Yes |
Response Parameters
Response Example:
{
"metadata":[
{
"metadata":{
"aggregateReduceOnlyQuantity":"0",
"aggregateVanillaQuantity":"0",
"vanillaLimitOrderCount":0,
"reduceOnlyLimitOrderCount":0,
"vanillaConditionalOrderCount":0,
"reduceOnlyConditionalOrderCount":0
},
"marketId":"0x141e3c92ed55107067ceb60ee412b86256cedef67b1227d6367b4cdf30c55a74",
"isBuy":true
},
{
"metadata":{
"aggregateReduceOnlyQuantity":"0",
"aggregateVanillaQuantity":"0",
"vanillaLimitOrderCount":0,
"reduceOnlyLimitOrderCount":0,
"vanillaConditionalOrderCount":0,
"reduceOnlyConditionalOrderCount":0
},
"marketId":"0x141e3c92ed55107067ceb60ee412b86256cedef67b1227d6367b4cdf30c55a74",
"isBuy":false
}
]
}
Parameter | Type | Description |
---|---|---|
metadata | SubaccountOrderbookMetadataWithMarket Array | List of subaccount's orderbook metadata information |
SubaccountOrderbookMetadataWithMarket
Parameter | Type | Description |
---|---|---|
metadata | SubaccountOrderbookMetadata | Orderbook metadata |
market_id | String | The orderbook's market ID |
is_buy | Boolean | True for buy. False for sell |
SubaccountOrderbookMetadata
Parameter | Type | Description |
---|---|---|
vanilla_limit_order_count | Integer | Number of vanilla limit orders |
reduce_only_limit_order_count | Integer | Number of reduce only limit orders |
aggregate_reduce_only_quantity | Decimal | Aggregate fillable quantity of the subaccount's reduce-only limit orders in the given direction |
aggregate_vanilla_quantity | Decimal | Aggregate fillable quantity of the subaccount's vanilla limit orders in the given direction |
vanilla_conditional_order_count | Integer | Number of vanilla conditional orders |
reduce_only_conditional_order_count | Integer | Number of reduce only conditional orders |
TradeRewardPoints
Retrieves the account and total trade rewards points
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
points = await client.fetch_trade_reward_points(
accounts=[address.to_acc_bech32()],
)
print(points)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
accounts := []string{senderAddress.String()}
res, err := chainClient.FetchTradeRewardPoints(ctx, accounts)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
accounts | String List | List of account addresses to query for | No |
pending_pool_timestamp | Integer | Rewards pool timestamp | No |
Response Parameters
Response Example:
{
"accountTradeRewardPoints":[
"0"
]
}
Parameter | Type | Description |
---|---|---|
account_trade_reward_points | Decimal | Number of points |
PendingTradeRewardPoints
Retrieves the pending account and total trade rewards points
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
points = await client.fetch_pending_trade_reward_points(
accounts=[address.to_acc_bech32()],
)
print(points)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
accounts := []string{senderAddress.String()}
res, err := chainClient.FetchPendingTradeRewardPoints(ctx, accounts)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
accounts | String List | List of account addresses to query for | No |
pending_pool_timestamp | Integer | Rewards pool timestamp | No |
Response Parameters
Response Example:
{
"accountTradeRewardPoints":[
"0"
]
}
Parameter | Type | Description |
---|---|---|
account_trade_reward_points | Decimal | Number of points |
TradeRewardCampaign
Retrieves the trade reward campaign
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
campaign = await client.fetch_trade_reward_campaign()
print(campaign)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchTradeRewardCampaign(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
No parameters
Response Parameters
Response Example:
{
"totalTradeRewardPoints":"22845565536709999999999999999855",
"tradingRewardPoolCampaignSchedule":[
],
"pendingTradingRewardPoolCampaignSchedule":[
],
"pendingTotalTradeRewardPoints":[
]
}
Parameter | Type | Description |
---|---|---|
trading_reward_campaign_info | TradingRewardCampaignInfo | Campaign information |
trading_reward_pool_campaign_schedule | CampaignRewardPool Array | Campaign schedules |
total_trade_reward_points | Decimal | Trade reward points |
pending_trading_reward_pool_campaign_schedule | CampaignRewardPool Array | Pending campaigns schedules |
pending_total_trade_reward_points | Decimal Array | Pending campaigns points |
TradingRewardCampaignInfo
Parameter | Type | Description |
---|---|---|
campaign_duration_seconds | Integer | Campaign duration in seconds |
quote_denoms | String Array | The trading fee quote denoms which will be counted for the rewards |
trading_reward_boost_info | TradingRewardCampaignBoostInfo | Boost information |
disqualified_market_ids | String Array | List of disqualified marked IDs |
CampaignRewardPool
Parameter | Type | Description |
---|---|---|
start_timestamp | Integer | Campaign start timestamp in seconds |
max_campaign_rewards | Decimal Array | Maximum reward amounts to be disbursed at the end of the campaign |
TradingRewardCampaignBoostInfo
Parameter | Type | Description |
---|---|---|
boosted_spot_market_ids | String Array | List of spot market IDs |
spot_market_multipliers | PointsMultiplier Array | List of boost information for each spot market |
boosted_derivative_market_ids | String Array | List of derivative market IDs |
derivative_market_multipliers | PointsMultiplier Array | List of bood information for each derivative market |
PointsMultiplier
Parameter | Type | Description |
---|---|---|
maker_points_multiplier | Decimal | Multiplier for maker trades |
taker_points_multiplier | Decimal | Multiplier for taker trades |
FeeDiscountAccountInfo
Retrieves the account's fee discount info
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
fee_discount = await client.fetch_fee_discount_account_info(
account=address.to_acc_bech32(),
)
print(fee_discount)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchFeeDiscountAccountInfo(ctx, senderAddress.String())
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
account | String | Account address to query for | Yes |
Response Parameters
Response Example:
{
"accountInfo":{
"makerDiscountRate":"0",
"takerDiscountRate":"0",
"stakedAmount":"1008990017144791",
"volume":"63626657729000000000000000000"
},
"tierLevel":"0"
}
Parameter | Type | Description |
---|---|---|
tier_level | Integer | Fee discount tier |
account_info | FeeDiscountTierInfo | Fee discount tier info |
account_ttl | FeeDiscountTierTTL | Fee discount tier TTL |
FeeDiscountTierInfo
Parameter | Type | Description |
---|---|---|
maker_discount_rate | Decimal | Maker trades' discount rate |
taker_discount_rate | Decimal | Taker trades' discount rate |
staked_amount | Decimal | Staked smount to reach this discount tier |
volume | Decimal | Volume to reach this discount tier |
FeeDiscountTierTTL
Parameter | Type | Description |
---|---|---|
tier | Integer | Tier number |
ttl_timestamp | Decimal | Tier TTL |
FeeDiscountSchedule
Retrieves the fee discount schedule
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
schedule = await client.fetch_fee_discount_schedule()
print(schedule)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchFeeDiscountSchedule(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
No parameters
Response Parameters
Response Example:
{
"feeDiscountSchedule":{
"bucketCount":"28",
"bucketDuration":"86400",
"quoteDenoms":[
"peggy0xf9152067989BDc8783fF586624124C05A529A5D1",
"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"
],
"tierInfos":[
{
"makerDiscountRate":"75000000000000000",
"takerDiscountRate":"75000000000000000",
"stakedAmount":"25000000000000000000",
"volume":"50000000000000000000000000"
},
{
"makerDiscountRate":"125000000000000000",
"takerDiscountRate":"125000000000000000",
"stakedAmount":"100000000000000000000",
"volume":"100000000000000000000000000"
},
{
"makerDiscountRate":"200000000000000000",
"takerDiscountRate":"200000000000000000",
"stakedAmount":"250000000000000000000",
"volume":"200000000000000000000000000"
},
{
"makerDiscountRate":"300000000000000000",
"takerDiscountRate":"300000000000000000",
"stakedAmount":"750000000000000000000",
"volume":"500000000000000000000000000"
},
{
"makerDiscountRate":"400000000000000000",
"takerDiscountRate":"400000000000000000",
"stakedAmount":"2000000000000000000000",
"volume":"1500000000000000000000000000"
},
{
"makerDiscountRate":"500000000000000000",
"takerDiscountRate":"500000000000000000",
"stakedAmount":"5000000000000000000000",
"volume":"3500000000000000000000000000"
},
{
"makerDiscountRate":"600000000000000000",
"takerDiscountRate":"600000000000000000",
"stakedAmount":"12500000000000000000000",
"volume":"8000000000000000000000000000"
},
{
"makerDiscountRate":"700000000000000000",
"takerDiscountRate":"700000000000000000",
"stakedAmount":"30000000000000000000000",
"volume":"20000000000000000000000000000"
},
{
"makerDiscountRate":"800000000000000000",
"takerDiscountRate":"800000000000000000",
"stakedAmount":"750000000000000000000000",
"volume":"30000000000000000000000000000"
}
],
"disqualifiedMarketIds":[
"0x8b1a4d3e8f6b559e30e40922ee3662dd78edf7042330d4d620d188699d1a9715"
]
}
}
Parameter | Type | Description |
---|---|---|
fee_discount_schedule | FeeDiscountSchedule | Fee discount schedule |
FeeDiscountSchedule
Parameter | Type | Description |
---|---|---|
bucket_count | Integer | Bucket count |
bucket_duration | Integer | Duration in seconds |
quote_denoms | String Array | The trading fee quote denoms which will be counted for the fee paid contribution |
tier_infos | FeeDiscountTierInfo Array | The fee discount tiers |
disqualified_market_ids | String Array | The marketIDs which are disqualified from contributing to the fee paid amount |
FeeDiscountTierInfo
Parameter | Type | Description |
---|---|---|
maker_discount_rate | Decimal | Maker trades' discount rate |
taker_discount_rate | Decimal | Taker trades' discount rate |
staked_amount | Decimal | Staked smount to reach this discount tier |
volume | Decimal | Volume to reach this discount tier |
BalanceMismatches
Retrieves mismatches between available vs. total balance
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
mismatches = await client.fetch_balance_mismatches(dust_factor=1)
print(mismatches)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchBalanceMismatches(ctx, 1)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
dust_factor | Integer | Difference treshold to query with | Yes |
Response Parameters
Response Example:
{
"balanceMismatches":[
{
"subaccountId":"0x05fa91c2776ac40473285b75e3d795870b94e5e2000000000000000000000000",
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"available":"870155637577815628",
"total":"870155637577800218",
"balanceHold":"0",
"expectedTotal":"870155637577815628",
"difference":"15410"
},
{
"subaccountId":"0x0ec17dde18a517442b7d580f53d8dc705af13ea8000000000000000000000000",
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"available":"933130554975740524",
"total":"933130554975739895",
"balanceHold":"0",
"expectedTotal":"933130554975740524",
"difference":"629"
},
{
"subaccountId":"0x16aef18dbaa341952f1af1795cb49960f68dfee3000000000000000000000000",
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"available":"761588657963815176",
"total":"75225000761588657963815176",
"balanceHold":"0",
"expectedTotal":"761588657963815176",
"difference":"-75225000000000000000000000"
},
{
"subaccountId":"0x2968698c6b9ed6d44b667a0b1f312a3b5d94ded7000000000000000000000000",
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"available":"219272509577750671",
"total":"79887563548606272509577750670",
"balanceHold":"79887563548387000000000000000",
"expectedTotal":"79887563548606272509577750671",
"difference":"1"
},
{
"subaccountId":"0x48237ce2f2d88aebef5eec7b7a228e4b13fd6eb5000000000000000000000002",
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"available":"4207036229489676145196048627",
"total":"4207036229489676145196048624",
"balanceHold":"0",
"expectedTotal":"4207036229489676145196048627",
"difference":"3"
},
{
"subaccountId":"0x643de64bde8ae72b8f0acfe88abd444df6b723fd000000000000000000000000",
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"available":"436283710291691073",
"total":"436283710291693025",
"balanceHold":"0",
"expectedTotal":"436283710291691073",
"difference":"-1952"
},
{
"subaccountId":"0x6590d14d9e9c1d964f8c83bddc8a092f4a2d1284000000000000000000000000",
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"available":"546950183781755834",
"total":"546950183781756580",
"balanceHold":"0",
"expectedTotal":"546950183781755834",
"difference":"-746"
},
{
"subaccountId":"0x7619f89a2172c6705aac7482f3adbf0601ea140e000000000000000000000000",
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"available":"42406272780554925",
"total":"42406272780556044",
"balanceHold":"0",
"expectedTotal":"42406272780554925",
"difference":"-1119"
},
{
"subaccountId":"0x8efbdeee271d02e1931a015233b4c1e84631a8f1000000000000000000000000",
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"available":"703396215678687048",
"total":"703396215678689667",
"balanceHold":"0",
"expectedTotal":"703396215678687048",
"difference":"-2619"
},
{
"subaccountId":"0xbb4afcb3b0e2a95d91f0eaaf9acefefa00d70a6e000000000000000000000000",
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"available":"893202463407432010",
"total":"893202463407432298",
"balanceHold":"0",
"expectedTotal":"893202463407432010",
"difference":"-288"
},
{
"subaccountId":"0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000",
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"available":"342932031115126491",
"total":"324904900060342932031115126449",
"balanceHold":"324904900060000000000000000000",
"expectedTotal":"324904900060342932031115126491",
"difference":"42"
},
{
"subaccountId":"0xc877ce74d053ada17c0c41d1203b19b44ac4d790000000000000000000000000",
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"available":"770209411929225026",
"total":"770209411929224682",
"balanceHold":"0",
"expectedTotal":"770209411929225026",
"difference":"344"
},
{
"subaccountId":"0xfc48d223d93b6da8817ae50deb15c98babaa67ae000000000000000000000000",
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"available":"841670909697500242",
"total":"841670909697500243",
"balanceHold":"0",
"expectedTotal":"841670909697500242",
"difference":"-1"
}
]
}
Parameter | Type | Description |
---|---|---|
balance_mismatches | BalanceMismatch Array | List of balance mismatches |
BalanceMismatch
Parameter | Type | Description |
---|---|---|
subaccount_id | String | The subaccount ID the balance belongs to |
denom | String | The token denom |
available | Decimal | The available balance |
total | Decimal | The total balance |
balance_hold | Decimal | The balance on hold |
expected_total | Decimal | The expected total balance |
difference | Decimal | Balance difference |
BalanceWithBalanceHolds
Retrieves available and total balances with balance holds
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
balance = await client.fetch_balance_with_balance_holds()
print(balance)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchBalanceWithBalanceHolds(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
No parameters
Response Parameters
Response Example:
{
"balanceWithBalanceHolds":[
{
"subaccountId":"0x0000000001e9681c4266ec4aaf5fe4de967072ee000000000000000000000000",
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"available":"0",
"total":"0",
"balanceHold":"0"
},
{
"subaccountId":"0x00000002f32c0886ee65d68059fbdb76ef6a6996000000000000000000000000",
"denom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"available":"361169802053915059",
"total":"361169802053915059",
"balanceHold":"0"
}
]
}
Parameter | Type | Description |
---|---|---|
balance_with_balance_holds | BalanceWithMarginHold Array | List of balances with hold |
BalanceWithMarginHold
Parameter | Type | Description |
---|---|---|
subaccount_id | String | The subaccount ID the balance belongs to |
denom | String | The token denom |
available | Decimal | The available balance |
total | Decimal | The total balance |
balance_hold | Decimal | The balance on hold |
FeeDiscountTierStatistics
Retrieves fee discount tier stats
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
statistics = await client.fetch_fee_discount_tier_statistics()
print(statistics)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchFeeDiscountTierStatistics(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
No parameters
Response Parameters
Response Example:
{
"statistics":[
{
"count":"104",
"tier":"0"
},
{
"tier":"1",
"count":"0"
},
{
"tier":"2",
"count":"1"
},
{
"tier":"3",
"count":"1"
},
{
"tier":"4",
"count":"0"
},
{
"tier":"5",
"count":"0"
},
{
"tier":"6",
"count":"0"
},
{
"tier":"7",
"count":"0"
},
{
"tier":"8",
"count":"0"
}
]
}
Parameter | Type | Description |
---|---|---|
statistics | TierStatistic Array | List of tier statistics |
TierStatistic
Parameter | Type | Description |
---|---|---|
tier | Integer | Tier number |
count | Integer | The tier count |
MitoVaultInfos
Retrieves market making pool info
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
infos = await client.fetch_mito_vault_infos()
print(infos)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchMitoVaultInfos(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
No parameters
Response Parameters
Response Example:
{
"masterAddresses":[
"inj1qg5ega6dykkxc307y25pecuufrjkxkag6xhp6y"
],
"spotAddresses":[
"inj1wddvh8vnn6rmyhp59qvr5jmpu3nllkgsyzr4m6"
],
"derivativeAddresses":[
],
"cw20Addresses":[
]
}
Parameter | Type | Description |
---|---|---|
master_addresses | String Array | List of master addresses |
derivative_addresses | String Array | List of derivative addresses |
spot_addresses | String Array | List of spot addresses |
cw20_addresses | String Array | List of cw20 contract addresses |
QueryMarketIDFromVault
Returns the market ID for a given vault subaccount ID
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
market_id = await client.fetch_market_id_from_vault(vault_address="inj1qg5ega6dykkxc307y25pecuufrjkxkag6xhp6y")
print(market_id)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
vaultAddress := "inj1qg5ega6dykkxc307y25pecuufrjkxkag6xhp6y"
res, err := chainClient.FetchMarketIDFromVault(ctx, vaultAddress)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
vault_address | String | The vault address to query for | Yes |
Response Parameters
Response Example:
Parameter | Type | Description |
---|---|---|
market_id | String | The vault's market ID |
HistoricalTradeRecords
Retrieves historical trade records for a given market ID
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
records = await client.fetch_historical_trade_records(
market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
)
print(records)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
res, err := chainClient.FetchHistoricalTradeRecords(ctx, marketId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The market ID to query for | Yes |
Response Parameters
Response Example:
{
"tradeRecords":[
{
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"latestTradeRecords":[
{
"timestamp":"1709641326",
"price":"42249000",
"quantity":"15368000000000000000000000000000000000"
},
{
"timestamp":"1709641446",
"price":"42080000",
"quantity":"15415000000000000000000000000000000000"
}
]
}
]
}
Parameter | Type | Description |
---|---|---|
trade_records | TradeRecords Array | List of trade records |
TradeRecords
Parameter | Type | Description |
---|---|---|
market_id | String | The market ID |
latest_trade_records | TradeRecord Array | List of trade records |
TradeRecord
Parameter | Type | Description |
---|---|---|
timestamp | Integer | Trade timestamp |
price | Decimal | Trade price |
quantity | Decimal | Trade quantity |
IsOptedOutOfRewards
Retrieves if the account is opted out of rewards
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
is_opted_out = await client.fetch_is_opted_out_of_rewards(
account=address.to_acc_bech32(),
)
print(is_opted_out)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchIsOptedOutOfRewards(ctx, senderAddress.String())
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
account | String | The account's address to query for | Yes |
Response Parameters
Response Example:
{
"isOptedOut":true
}
Parameter | Type | Description |
---|---|---|
is_opted_out | Boolean | Opted out state for the account |
OptedOutOfRewardsAccounts
Retrieves all accounts opted out of rewards
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
opted_out = await client.fetch_opted_out_of_rewards_accounts()
print(opted_out)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchOptedOutOfRewardsAccounts(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
No parameters
Response Parameters
Response Example:
{
"accounts":[
"inj1qqqqpgj4strcnlgzsaae2tey7dhk6enu8fc5zd",
"inj1fwpyx9k4x5yzm63wmrpg4ekngmv2qjd0yddqaq",
"inj1tz65vxc7a4acf6gd3fhq23mrquvjhgrtwwr7fz",
"inj1wefqjmt5xkn7t769kl4kay2ncvx7we0nnephl2",
"inj1n47c74gv6jwnzzsmqhd7h5msdnx2gncpjk4yh4",
"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
"inj1clw20s2uxeyxtam6f7m84vgae92s9eh7vygagt"
]
}
Parameter | Type | Description |
---|---|---|
accounts | String Array | List of opted out accounts |
MarketVolatility
Computes the volatility for spot and derivative markets trading history
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
trade_grouping_sec = 10
max_age = 0
include_raw_history = True
include_metadata = True
volatility = await client.fetch_market_volatility(
market_id=market_id,
trade_grouping_sec=trade_grouping_sec,
max_age=max_age,
include_raw_history=include_raw_history,
include_metadata=include_metadata,
)
print(volatility)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/chain/exchange/types"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
tradeHistoryOptions := types.TradeHistoryOptions{
TradeGroupingSec: 10,
MaxAge: 0,
IncludeRawHistory: true,
IncludeMetadata: true,
}
res, err := chainClient.FetchMarketVolatility(ctx, marketId, &tradeHistoryOptions)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The market ID to query for | Yes |
trade_history_options | TradeHistoryOptions | Extra query options | No |
TradeHistoryOptions
Parameter | Type | Description |
---|---|---|
trade_grouping_sec | Integer | 0 means use the chain's default grouping |
max_age | Integer | Restricts the trade records oldest age in seconds from the current block time to consider. A value of 0 means use all the records present on the chain |
include_raw_history | Boolean | If True, the raw underlying data used for the computation is included in the response |
include_metadata | Boolean | If True, metadata on the computation is included in the response |
Response Parameters
Response Example:
{
"volatility":"0",
"historyMetadata":{
"groupCount":2,
"recordsSampleSize":2,
"mean":"42109967",
"twap":"42080000",
"firstTimestamp":"1709644088",
"lastTimestamp":"1709644207",
"minPrice":"42080000",
"maxPrice":"42110000",
"medianPrice":"42095000"
},
"rawHistory":[
{
"timestamp":"1709644088",
"price":"42110000",
"quantity":"15330000000000000000000000000000000000"
},
{
"timestamp":"1709644207",
"price":"42080000",
"quantity":"17000000000000000000000000000000000"
}
]
}
Parameter | Type | Description |
---|---|---|
volatility | Decimal | Market's volatility |
history_metadata | MetadataStatistics | Market's volatility |
raw_history | TradeRecord Array | List of trade records |
MetadataStatistics
Parameter | Type | Description |
---|---|---|
group_count | Integer | Refers to the number of groups used. Equals records_sample_size if no grouping is used |
records_sample_size | Integer | Refers to the total number of records used |
mean | Decimal | Refers to the arithmetic mean. For trades, the mean is the VWAP computed over the grouped trade records ∑ (price * quantity) / ∑ quantity For oracle prices, the mean is computed over the price records ∑ (price) / prices_count |
twap | Decimal | Refers to the time-weighted average price which equals ∑ (price_i * ∆t_i) / ∑ ∆t_i where ∆t_i = t_i - t_{i-1} |
first_timestamp | Integer | The timestamp of the oldest record considered |
last_timestamp | Integer | The timestamp of the youngest record considered |
min_price | Decimal | Refers to the smallest individual raw price considered |
max_price | Decimal | Refers to the largest individual raw price considered |
median_price | Decimal | Refers to the median individual raw price considered |
TradeRecord
Parameter | Type | Description |
---|---|---|
timestamp | Integer | Trade timestamp |
price | Decimal | Trade price |
quantity | Decimal | Trade quantity |
MarketAtomicExecutionFeeMultiplier
Retrieves the atomic execution fee multiplier
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
multiplier = await client.fetch_market_atomic_execution_fee_multiplier(
market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
)
print(multiplier)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
res, err := chainClient.FetchMarketAtomicExecutionFeeMultiplier(ctx, marketId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The market ID to query for | Yes |
Response Parameters
Response Example:
{
"multiplier":"2000000000000000000"
}
Parameter | Type | Description |
---|---|---|
multiplier | Decimal | The multiplier value |
MsgRewardsOptOut
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
# prepare tx msg
msg = composer.msg_rewards_opt_out(sender=address.to_acc_bech32())
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"fmt"
"os"
"time"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
msg := &exchangetypes.MsgRewardsOptOut{
Sender: senderAddress.String(),
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The sender's address | Yes |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgAuthorizeStakeGrants
Message to grant stakes to grantees.
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
from decimal import Decimal
import dotenv
from pyinjective.async_client import AsyncClient
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
await client.initialize_tokens_from_chain_denoms()
composer = await client.composer()
await client.sync_timeout_height()
message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
network=network,
private_key=configured_private_key,
)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
# prepare tx msg
grant_authorization = composer.create_grant_authorization(
grantee="inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
amount=Decimal("1"),
)
message = composer.msg_authorize_stake_grants(sender=address.to_acc_bech32(), grants=[grant_authorization])
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"encoding/json"
"fmt"
"os"
"cosmossdk.io/math"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
grantAuthorization := &exchangetypes.GrantAuthorization{
Grantee: "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
Amount: math.NewIntWithDecimal(1, 18),
}
msg := &exchangetypes.MsgAuthorizeStakeGrants{
Sender: senderAddress.String(),
Grants: []*exchangetypes.GrantAuthorization{grantAuthorization},
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.AsyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | Injective address of the stake granter | Yes |
grants | GrantAuthorization Array | List of grants assigned to the grantees | Yes |
GrantAuthorization
Parameter | Type | Description |
---|---|---|
grantee | String | Grantee's Injective address |
amount | Integer | Amount of stake granted (INJ in chain format) |
Response Parameters
Response Example:
txhash: "5AF048ADCE6AF753256F03AF2404A5B78C4C3E7E42A91F0B5C9994372E8AC2FE"
raw_log: "[]"
gas wanted: 106585
gas fee: 0.0000532925 INJ
DEBU[0001] broadcastTx with nonce 3503 fn=func1 src="client/chain/chain.go:598"
DEBU[0002] msg batch committed successfully at height 5214406 fn=func1 src="client/chain/chain.go:619"
txHash=31FDA89C3122322C0559B5766CDF892FD0AA12469017CF8BF88B53441464ECC4
DEBU[0002] nonce incremented to 3504 fn=func1 src="client/chain/chain.go:623"
DEBU[0002] gas wanted: 133614 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.000066807 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgActivateStakeGrant
Message for grantees to claim stake grants.
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective.async_client import AsyncClient
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
await client.initialize_tokens_from_chain_denoms()
composer = await client.composer()
await client.sync_timeout_height()
message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
network=network,
private_key=configured_private_key,
)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
# prepare tx msg
message = composer.msg_activate_stake_grant(
sender=address.to_acc_bech32(), granter="inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
msg := &exchangetypes.MsgActivateStakeGrant{
Sender: senderAddress.String(),
Granter: "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r",
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.AsyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | Injective address of the stake grantee | Yes |
granter | String | Injective address of the stake granter | Yes |
GrantAuthorization
Parameter | Type | Description |
---|---|---|
grantee | String | Grantee's Injective address |
amount | Integer | Amount of stake granted (INJ in chain format) |
Response Parameters
Response Example:
txhash: "5AF048ADCE6AF753256F03AF2404A5B78C4C3E7E42A91F0B5C9994372E8AC2FE"
raw_log: "[]"
gas wanted: 106585
gas fee: 0.0000532925 INJ
DEBU[0001] broadcastTx with nonce 3503 fn=func1 src="client/chain/chain.go:598"
DEBU[0002] msg batch committed successfully at height 5214406 fn=func1 src="client/chain/chain.go:619"
txHash=31FDA89C3122322C0559B5766CDF892FD0AA12469017CF8BF88B53441464ECC4
DEBU[0002] nonce incremented to 3504 fn=func1 src="client/chain/chain.go:623"
DEBU[0002] gas wanted: 133614 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.000066807 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
- Chain Exchange for Derivatives
Includes all messages related to derivative markets.
DerivativeMidPriceAndTOB
Retrieves a derivative market's mid-price
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
prices = await client.fetch_derivative_mid_price_and_tob(
market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
)
print(prices)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
res, err := chainClient.FetchDerivativeMidPriceAndTOB(ctx, marketId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | Market ID to request for | Yes |
Response Parameters
Response Example:
{
"midPrice":"36928150000000000000000000",
"bestBuyPrice":"36891200000000000000000000",
"bestSellPrice":"36965100000000000000000000"
}
Parameter | Type | Description |
---|---|---|
mid_price | Decimal | Market's mid price |
best_buy_price | Decimal | Market's bet bid price |
best_sell_price | Decimal | Market's bet ask price |
DerivativeOrderbook
Retrieves a derivative market's orderbook by marketID
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
pagination = PaginationOption(limit=2)
orderbook = await client.fetch_chain_derivative_orderbook(
market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
pagination=pagination,
)
print(orderbook)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"cosmossdk.io/math"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
limit := uint64(2)
limitCumulativeNotional := math.LegacyDec{}
res, err := chainClient.FetchChainDerivativeOrderbook(ctx, marketId, limit, limitCumulativeNotional)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | Market ID to request for | Yes |
limit | Integer | Max number of order book entries to return per side | No |
limit_cumulative_notional | Decimal | Limit the number of entries to return per side based on the cumulative notional | No |
Response Parameters
Response Example:
{
"buysPriceLevel":[
{
"p":"36891200000000000000000000",
"q":"3253632000000000000000"
},
{
"p":"36860900000000000000000000",
"q":"500000000000000000"
}
],
"sellsPriceLevel":[
{
"p":"36965100000000000000000000",
"q":"60344815000000000000000"
},
{
"p":"37057500000000000000000000",
"q":"60194349800000000000000"
}
]
}
Parameter | Type | Description |
---|---|---|
buys_price_level | Level Array | Bid side entries |
sells_price_level | Level Array | Ask side entries |
Level
Parameter | Type | Description |
---|---|---|
p | Decimal | Price |
q | Decimal | Quantity |
TraderDerivativeOrders
Retrieves a trader's derivative orders
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
orders = await client.fetch_chain_trader_derivative_orders(
market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
subaccount_id=subaccount_id,
)
print(orders)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
subaccountId := chainClient.Subaccount(senderAddress, 0)
res, err := chainClient.FetchChainTraderDerivativeOrders(ctx, marketId, subaccountId.Hex())
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | Market ID to request for | Yes |
subaccount_id | String | Trader's subaccount ID | Yes |
Response Parameters
Response Example:
{
"orders":[
]
}
Parameter | Type | Description |
---|---|---|
orders | TrimmedDerivativeLimitOrder Array | Orders info |
TrimmedDerivativeLimitOrder
Parameter | Type | Description |
---|---|---|
price | Decimal | Order price |
quantity | Decimal | Order quantity |
margin | Decimal | Order margin |
fillable | Decimal | The remaining fillable amount of the order |
is_buy | Boolean | True if the order is a buy order |
order_hash | String | The order hash |
cid | String | The client order ID provided by the creator |
AccountAddressDerivativeOrders
Retrieves all account address' derivative orders
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
orders = await client.fetch_chain_account_address_derivative_orders(
market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
account_address=address.to_acc_bech32(),
)
print(orders)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
res, err := chainClient.FetchChainAccountAddressDerivativeOrders(ctx, marketId, senderAddress.String())
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | Market ID to request for | Yes |
account_address | String | Trader's account address | Yes |
Response Parameters
Response Example:
{
"orders":[
]
}
Parameter | Type | Description |
---|---|---|
orders | TrimmedDerivativeLimitOrder Array | Orders info |
TrimmedDerivativeLimitOrder
Parameter | Type | Description |
---|---|---|
price | Decimal | Order price |
quantity | Decimal | Order quantity |
margin | Decimal | Order margin |
fillable | Decimal | The remaining fillable amount of the order |
is_buy | Boolean | True if the order is a buy order |
order_hash | String | The order hash |
cid | String | The client order ID provided by the creator |
DerivativeOrdersByHashes
Retrieves a trader's derivative orders
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
orders = await client.fetch_chain_derivative_orders_by_hashes(
market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
subaccount_id=subaccount_id,
order_hashes=["0x57a01cd26f1e2080860af3264e865d7c9c034a701e30946d01c1dc7a303cf2c1"],
)
print(orders)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
subaccountId := chainClient.Subaccount(senderAddress, 0)
orderHashes := []string{"0x57a01cd26f1e2080860af3264e865d7c9c034a701e30946d01c1dc7a303cf2c1"}
res, err := chainClient.FetchChainDerivativeOrdersByHashes(ctx, marketId, subaccountId.Hex(), orderHashes)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | Market ID to request for | Yes |
subaccount_id | String | Trader's subaccount ID | Yes |
order_hashes | String Array | List of order hashes to retrieve information for | Yes |
Response Parameters
Response Example:
{
"orders":[
]
}
Parameter | Type | Description |
---|---|---|
orders | TrimmedDerivativeLimitOrder Array | Orders info |
TrimmedDerivativeLimitOrder
Parameter | Type | Description |
---|---|---|
price | Decimal | Order price |
quantity | Decimal | Order quantity |
margin | Decimal | Order margin |
fillable | Decimal | The remaining fillable amount of the order |
is_buy | Boolean | True if the order is a buy order |
order_hash | String | The order hash |
cid | String | The client order ID provided by the creator |
TraderDerivativeTransientOrders
Retrieves a trader's transient derivative orders
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
orders = await client.fetch_chain_trader_derivative_transient_orders(
market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
subaccount_id=subaccount_id,
)
print(orders)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
subaccountId := chainClient.Subaccount(senderAddress, 0)
res, err := chainClient.FetchChainTraderDerivativeTransientOrders(ctx, marketId, subaccountId.Hex())
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | Market ID to request for | Yes |
subaccount_id | String | Trader's subaccount ID | Yes |
Response Parameters
Response Example:
{
"orders":[
]
}
Parameter | Type | Description |
---|---|---|
orders | TrimmedDerivativeLimitOrder Array | Orders info |
TrimmedDerivativeLimitOrder
Parameter | Type | Description |
---|---|---|
price | Decimal | Order price |
quantity | Decimal | Order quantity |
margin | Decimal | Order margin |
fillable | Decimal | The remaining fillable amount of the order |
is_buy | Boolean | True if the order is a buy order |
order_hash | String | The order hash |
cid | String | The client order ID provided by the creator |
DerivativeMarkets
Retrieves a list of derivative markets
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
derivative_markets = await client.fetch_chain_derivative_markets(
status="Active",
market_ids=["0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"],
)
print(derivative_markets)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
status := "Active"
marketIds := []string{"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"}
withMidPriceAndTob := true
res, err := chainClient.FetchChainDerivativeMarkets(ctx, status, marketIds, withMidPriceAndTob)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
status | String | Market status | No |
market_ids | String Array | List of market IDs | No |
with_mid_price_and_tob | Boolean | Flag to activate/deactivate the inclusion of the markets mid price and top of the book buy and sell orders | No |
Response Parameters
Response Example:
{
"markets":[
{
"market":{
"ticker":"INJ/USDT PERP",
"oracleBase":"0x2d9315a88f3019f8efa88dfe9c0f0843712da0bac814461e27733f6b83eb51b3",
"oracleQuote":"0x1fc18861232290221461220bd4e2acd1dcdfbc89c84092c93c18bdc7756c1588",
"oracleType":"Pyth",
"oracleScaleFactor":6,
"quoteDenom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"initialMarginRatio":"50000000000000000",
"maintenanceMarginRatio":"20000000000000000",
"makerFeeRate":"-100000000000000",
"takerFeeRate":"1000000000000000",
"relayerFeeShareRate":"400000000000000000",
"isPerpetual":true,
"status":"Active",
"minPriceTickSize":"100000000000000000000",
"minQuantityTickSize":"100000000000000"
},
"perpetualInfo":{
"marketInfo":{
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"hourlyFundingRateCap":"625000000000000",
"hourlyInterestRate":"4166660000000",
"nextFundingTimestamp":"1709546400",
"fundingInterval":"3600"
},
"fundingInfo":{
"cumulativeFunding":"-44519773449439313111470",
"cumulativePrice":"0",
"lastTimestamp":"1709542800"
}
},
"markPrice":"39829277195482383939000000"
}
]
}
Parameter | Type | Description |
---|---|---|
markets | FullDerivativeMarket Array | Markets information |
FullDerivativeMarket
Parameter | Type | Description |
---|---|---|
market | DerivativeMarket | Market basic information |
info | PerpetualMarketState or ExpiryFuturesMarketInfo | Specific information for the perpetual or expiry futures market |
mark_price | Decimal | The market mark price |
mid_price_and_tob | MidPriceAndTOB | The mid price for this market and the best ask and bid orders |
DerivativeMarket
Parameter | Type | Description |
---|---|---|
ticker | String | Name of the pair in format AAA/BBB, where AAA is base asset, BBB is quote asset |
oracle_base | String | Oracle base token |
oracle_quote | String | Oracle quote token |
oracle_type | OracleType | The oracle type |
oracle_scale_factor | Integer | The oracle number of scale decimals |
quote_denom | String | Coin denom used for the quote asset |
market_id | String | The market ID |
initial_margin_ratio | Decimal | The max initial margin ratio a position is allowed to have in the market |
maintenance_margin_ratio | Decimal | The max maintenance margin ratio a position is allowed to have in the market |
maker_fee_rate | Decimal | Fee percentage makers pay when trading |
taker_fee_rate | Decimal | Fee percentage takers pay when trading |
relayer_fee_share_rate | Decimal | Percentage of the transaction fee shared with the relayer in a derivative market |
is_perpetual | Boolean | True if the market is a perpetual market. False if the market is an expiry futures market |
status | MarketStatus | Status of the market |
min_price_tick_size | Decimal | Minimum tick size that the price required for orders in the market |
min_quantity_tick_size | Decimal | Minimum tick size of the quantity required for orders in the market |
min_notional | Decimal | Minimum notional (in quote asset) required for orders in the market |
admin | String | Current market admin's address |
admin_permissions | Integer | Level of admin permissions (the permission number is a result of adding up all individual permissions numbers) |
OracleType
Code | Name |
---|---|
0 | Unspecified |
1 | Band |
2 | PriceFeed |
3 | Coinbase |
4 | Chainlink |
5 | Razor |
6 | Dia |
7 | API3 |
8 | Uma |
9 | Pyth |
10 | BandIBC |
11 | Provider |
MarketStatus
Code | Name |
---|---|
0 | Unspecified |
1 | Active |
2 | Paused |
3 | Demolished |
4 | Expired |
PerpetualMarketState
Parameter | Type | Description |
---|---|---|
market_info | PerpetualMarketInfo | Perpetual market information |
funding_info | PerpetualMarketFunding | Market funding information |
PerpetualMarketInfo
Parameter | Type | Description |
---|---|---|
market_id | String | The market ID |
hourly_funding_rate_cap | Decimal | Maximum absolute value of the hourly funding rate |
hourly_interest_rate | Decimal | The hourly interest rate |
next_funding_timestamp | Integer | The next funding timestamp in seconds |
funding_interval | Integer | The next funding interval in seconds |
PerpetualMarketFunding
Parameter | Type | Description |
---|---|---|
cumulative_funding | Decimal | The market's cumulative funding |
cumulative_price | Decimal | The cumulative price for the current hour up to the last timestamp |
last_timestamp | Integer | Last funding timestamp in seconds |
ExpiryFuturesMarketInfo
Parameter | Type | Description |
---|---|---|
market_id | String | The market ID |
expiration_timestamp | Integer | The market's expiration time in seconds |
twap_start_timestamp | Integer | Defines the start time of the TWAP calculation window |
expiration_twap_start_price_cumulative | Decimal | Defines the cumulative price for the start of the TWAP window |
settlement_price | Decimal | The settlement price |
AdminPermission
Code | Name |
---|---|
1 | Ticker Permission |
2 | Min Price Tick Size Permission |
4 | Min Quantity Tick Size Permission |
8 | Min Notional Permission |
16 | Initial Margin Ratio Permission |
32 | Maintenance Margin Ratio Permission |
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
res, err := chainClient.FetchChainDerivativeMarket(ctx, marketId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The marke ID to query for | Yes |
Response Parameters
Response Example:
{
"market":{
"market":{
"ticker":"INJ/USDT PERP",
"oracleBase":"0x2d9315a88f3019f8efa88dfe9c0f0843712da0bac814461e27733f6b83eb51b3",
"oracleQuote":"0x1fc18861232290221461220bd4e2acd1dcdfbc89c84092c93c18bdc7756c1588",
"oracleType":"Pyth",
"oracleScaleFactor":6,
"quoteDenom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"initialMarginRatio":"50000000000000000",
"maintenanceMarginRatio":"20000000000000000",
"makerFeeRate":"-100000000000000",
"takerFeeRate":"1000000000000000",
"relayerFeeShareRate":"400000000000000000",
"isPerpetual":true,
"status":"Active",
"minPriceTickSize":"100000000000000000000",
"minQuantityTickSize":"100000000000000"
},
"perpetualInfo":{
"marketInfo":{
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"hourlyFundingRateCap":"625000000000000",
"hourlyInterestRate":"4166660000000",
"nextFundingTimestamp":"1709553600",
"fundingInterval":"3600"
},
"fundingInfo":{
"cumulativeFunding":"-44192284639015238855564",
"cumulativePrice":"0",
"lastTimestamp":"1709550000"
}
},
"markPrice":"39011901904676818317000000"
}
}
Parameter | Type | Description |
---|---|---|
market | FullDerivativeMarket | Market information |
FullDerivativeMarket
Parameter | Type | Description |
---|---|---|
market | DerivativeMarket | Market basic information |
info | PerpetualMarketState or ExpiryFuturesMarketInfo | Specific information for the perpetual or expiry futures market |
mark_price | Decimal | The market mark price |
mid_price_and_tob | MidPriceAndTOB | The mid price for this market and the best ask and bid orders |
DerivativeMarket
Parameter | Type | Description |
---|---|---|
ticker | String | Name of the pair in format AAA/BBB, where AAA is base asset, BBB is quote asset |
oracle_base | String | Oracle base token |
oracle_quote | String | Oracle quote token |
oracle_type | OracleType | The oracle type |
oracle_scale_factor | Integer | The oracle number of scale decimals |
quote_denom | String | Coin denom used for the quote asset |
market_id | String | The market ID |
initial_margin_ratio | Decimal | The max initial margin ratio a position is allowed to have in the market |
maintenance_margin_ratio | Decimal | The max maintenance margin ratio a position is allowed to have in the market |
maker_fee_rate | Decimal | Fee percentage makers pay when trading |
taker_fee_rate | Decimal | Fee percentage takers pay when trading |
relayer_fee_share_rate | Decimal | Percentage of the transaction fee shared with the relayer in a derivative market |
is_perpetual | Boolean | True if the market is a perpetual market. False if the market is an expiry futures market |
status | MarketStatus | Status of the market |
min_price_tick_size | Decimal | Minimum tick size that the price required for orders in the market |
min_quantity_tick_size | Decimal | Minimum tick size of the quantity required for orders in the market |
min_notional | Decimal | Minimum notional (in quote asset) required for orders in the market |
admin | String | Current market admin's address |
admin_permissions | Integer | Level of admin permissions (the permission number is a result of adding up all individual permissions numbers) |
OracleType
Code | Name |
---|---|
0 | Unspecified |
1 | Band |
2 | PriceFeed |
3 | Coinbase |
4 | Chainlink |
5 | Razor |
6 | Dia |
7 | API3 |
8 | Uma |
9 | Pyth |
10 | BandIBC |
11 | Provider |
MarketStatus
Code | Name |
---|---|
0 | Unspecified |
1 | Active |
2 | Paused |
3 | Demolished |
4 | Expired |
PerpetualMarketState
Parameter | Type | Description |
---|---|---|
market_info | PerpetualMarketInfo | Perpetual market information |
funding_info | PerpetualMarketFunding | Market funding information |
PerpetualMarketInfo
Parameter | Type | Description |
---|---|---|
market_id | String | The market ID |
hourly_funding_rate_cap | Decimal | Maximum absolute value of the hourly funding rate |
hourly_interest_rate | Decimal | The hourly interest rate |
next_funding_timestamp | Integer | The next funding timestamp in seconds |
funding_interval | Integer | The next funding interval in seconds |
PerpetualMarketFunding
Parameter | Type | Description |
---|---|---|
cumulative_funding | Decimal | The market's cumulative funding |
cumulative_price | Decimal | The cumulative price for the current hour up to the last timestamp |
last_timestamp | Integer | Last funding timestamp in seconds |
ExpiryFuturesMarketInfo
Parameter | Type | Description |
---|---|---|
market_id | String | The market ID |
expiration_timestamp | Integer | The market's expiration time in seconds |
twap_start_timestamp | Integer | Defines the start time of the TWAP calculation window |
expiration_twap_start_price_cumulative | Decimal | Defines the cumulative price for the start of the TWAP window |
settlement_price | Decimal | The settlement price |
AdminPermission
Code | Name |
---|---|
1 | Ticker Permission |
2 | Min Price Tick Size Permission |
4 | Min Quantity Tick Size Permission |
8 | Min Notional Permission |
16 | Initial Margin Ratio Permission |
32 | Maintenance Margin Ratio Permission |
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
res, err := chainClient.FetchDerivativeMarketAddress(ctx, marketId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The marke ID to query for | Yes |
Response Parameters
Response Example:
{
"address":"inj1zlh5sqevkfphtwnu9cul8p89vseme2eqt0snn9",
"subaccountId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20000000000000000000000000"
}
Parameter | Type | Description |
---|---|---|
address | String | The market's address |
subaccount_id | String | The market's subaccount ID |
Positions
Retrieves the entire exchange module's positions
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
positions = await client.fetch_chain_positions()
print(positions)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchChainPositions(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
No parameters
Response Parameters
Response Example:
{
"state":[
{
"subaccountId":"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
"marketId":"0x0f03542809143c7e5d3c22f56bc6e51eb2c8bab5009161b58f6f468432dfa196",
"position":{
"isLong":true,
"quantity":"258750000000000000000",
"entryPrice":"24100496718773416724721614",
"margin":"6777476791762608353694085318",
"cumulativeFundingEntry":"50154448152800501378128"
}
},
{
"subaccountId":"0xd28d1e9bc2d5a00e5e17f82fa6d4a7b0f4f034de000000000000000000000000",
"marketId":"0x0f03542809143c7e5d3c22f56bc6e51eb2c8bab5009161b58f6f468432dfa196",
"position":{
"quantity":"258750000000000000000",
"entryPrice":"23962425204761235933835394",
"margin":"6044298532028028581333461495",
"cumulativeFundingEntry":"50154448152800501378128",
"isLong":false
}
}
]
}
Parameter | Type | Description |
---|---|---|
state | DerivativePosition Array | List of derivative positions |
DerivativePosition
Parameter | Type | Description |
---|---|---|
subaccount_id | String | Subaccount ID the position belongs to |
market_id | String | ID of the position's market |
position | Position | Position information |
Position
Parameter | Type | Description |
---|---|---|
is_long | Boolean | True if the position is long. False if the position is short |
quantity | Decimal | The position's amount |
entry_price | Decimal | The order execution price when the position was created |
margin | Decimal | The position's current margin amount |
cumulative_funding_entry | Decimal | The cummulative funding |
SubaccountPositions
Retrieves subaccount's positions
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
positions = await client.fetch_chain_subaccount_positions(
subaccount_id=subaccount_id,
)
print(positions)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
subaccountId := chainClient.Subaccount(senderAddress, 0)
res, err := chainClient.FetchChainSubaccountPositions(ctx, subaccountId.Hex())
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | The subaccount ID to query for | Yes |
Response Parameters
Response Example:
{
"state":[
{
"subaccountId":"0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000",
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"position":{
"quantity":"3340193358036765108",
"entryPrice":"36571100000000000000000000",
"margin":"122195236794397342072018650",
"cumulativeFundingEntry":"-252598128590449182271444",
"isLong":false
}
},
{
"subaccountId":"0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000",
"marketId":"0x95698a9d8ba11660f44d7001d8c6fb191552ece5d9141a05c5d9128711cdc2e0",
"position":{
"isLong":true,
"quantity":"135686990000000000000000",
"entryPrice":"22530000000000000000000000",
"margin":"636295890792648990477285777577",
"cumulativeFundingEntry":"547604913674998202455064"
}
},
{
"subaccountId":"0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000",
"marketId":"0xba9c96a1a9cc226cfe6bd9bca3a433e396569d1955393f38f2ee728cfda7ec58",
"position":{
"quantity":"49610000000000000000",
"entryPrice":"132668911285488007767214817",
"margin":"6506890715472807452489590330",
"cumulativeFundingEntry":"1853558761901071670120617",
"isLong":false
}
},
{
"subaccountId":"0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000",
"marketId":"0xd97d0da6f6c11710ef06315971250e4e9aed4b7d4cd02059c9477ec8cf243782",
"position":{
"quantity":"1000000000000000000",
"entryPrice":"10700000000000000000000000",
"margin":"10646500000000000000000000",
"cumulativeFundingEntry":"452362068840099307543671",
"isLong":false
}
},
{
"subaccountId":"0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000",
"marketId":"0xe185b08a7ccd830a94060edd5e457d30f429aa6f0757f75a8b93aa611780cfac",
"position":{
"quantity":"71000000000000000000",
"entryPrice":"1282490277777777777777778",
"margin":"87823626715436695150716328",
"cumulativeFundingEntry":"4419299319189937712262",
"isLong":false
}
}
]
}
Parameter | Type | Description |
---|---|---|
state | DerivativePosition Array | List of derivative positions |
DerivativePosition
Parameter | Type | Description |
---|---|---|
subaccount_id | String | Subaccount ID the position belongs to |
market_id | String | ID of the position's market |
position | Position | Position information |
Position
Parameter | Type | Description |
---|---|---|
is_long | Boolean | True if the position is long. False if the position is short |
quantity | Decimal | The position's amount |
entry_price | Decimal | The order execution price when the position was created |
margin | Decimal | The position's current margin amount |
cumulative_funding_entry | Decimal | The cummulative funding |
SubaccountPositionInMarket
Retrieves subaccount's position in market
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
position = await client.fetch_chain_subaccount_position_in_market(
subaccount_id=subaccount_id,
market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
)
print(position)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
subaccountId := chainClient.Subaccount(senderAddress, 0)
marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
res, err := chainClient.FetchChainSubaccountPositionInMarket(ctx, subaccountId.Hex(), marketId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | The subaccount ID to query for | Yes |
market_id | String | The market ID to query for | Yes |
Response Parameters
Response Example:
{
"state":{
"quantity":"3340193358036765108",
"entryPrice":"36571100000000000000000000",
"margin":"122195236794397342072018650",
"cumulativeFundingEntry":"-252598128590449182271444",
"isLong":false
}
}
Parameter | Type | Description |
---|---|---|
state | Position | Position information |
Position
Parameter | Type | Description |
---|---|---|
is_long | Boolean | True if the position is long. False if the position is short |
quantity | Decimal | The position's amount |
entry_price | Decimal | The order execution price when the position was created |
margin | Decimal | The position's current margin amount |
cumulative_funding_entry | Decimal | The cummulative funding |
SubaccountEffectivePositionInMarket
Retrieves subaccount's position in market
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
position = await client.fetch_chain_subaccount_effective_position_in_market(
subaccount_id=subaccount_id,
market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
)
print(position)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
subaccountId := chainClient.Subaccount(senderAddress, 0)
marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
res, err := chainClient.FetchChainSubaccountEffectivePositionInMarket(ctx, subaccountId.Hex(), marketId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | The subaccount ID to query for | Yes |
market_id | String | The market ID to query for | Yes |
Response Parameters
Response Example:
{
"state":{
"quantity":"3340193358036765108",
"entryPrice":"36571100000000000000000000",
"effectiveMargin":"115186707927789961723454140",
"isLong":false
}
}
Parameter | Type | Description |
---|---|---|
state | EffectivePosition | Effective position information |
EffectivePosition
Parameter | Type | Description |
---|---|---|
is_effective_position_long | Boolean | True if the position is long. False if the position is short |
quantity | Decimal | The position's amount |
entry_price | Decimal | The order execution price when the position was created |
effective_margin | Decimal | The position's current margin amount |
PerpetualMarketInfo
Retrieves perpetual market's info
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
market_info = await client.fetch_chain_perpetual_market_info(
market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
)
print(market_info)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
res, err := chainClient.FetchChainPerpetualMarketInfo(ctx, marketId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The market ID to query for | Yes |
Response Parameters
Response Example:
{
"info":{
"marketId":"0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
"hourlyFundingRateCap":"625000000000000",
"hourlyInterestRate":"4166660000000",
"nextFundingTimestamp":"1709560800",
"fundingInterval":"3600"
}
}
Parameter | Type | Description |
---|---|---|
info | PerpetualMarketInfo | Perpetual market information |
PerpetualMarketInfo
Parameter | Type | Description |
---|---|---|
market_id | String | The market ID |
hourly_funding_rate_cap | Decimal | Maximum absolute value of the hourly funding rate |
hourly_interest_rate | Decimal | The hourly interest rate |
next_funding_timestamp | Integer | The next funding timestamp in seconds |
funding_interval | Integer | The next funding interval in seconds |
ExpiryFuturesMarketInfo
Retrieves expiry market's info
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
market_info = await client.fetch_chain_expiry_futures_market_info(
market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
)
print(market_info)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
res, err := chainClient.FetchChainExpiryFuturesMarketInfo(ctx, marketId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The market ID to query for | Yes |
Response Parameters
Response Example:
Parameter | Type | Description |
---|---|---|
info | ExpiryFuturesMarketInfo | Expiry futures market information |
ExpiryFuturesMarketInfo
Parameter | Type | Description |
---|---|---|
market_id | String | The market ID |
expiration_timestamp | Integer | The market's expiration time in seconds |
twap_start_timestamp | Integer | Defines the start time of the TWAP calculation window |
expiration_twap_start_price_cumulative | Decimal | Defines the cumulative price for the start of the TWAP window |
settlement_price | Decimal | The settlement price |
PerpetualMarketFunding
Retrieves perpetual market funding
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
funding = await client.fetch_chain_perpetual_market_funding(
market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
)
print(funding)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
res, err := chainClient.FetchChainPerpetualMarketFunding(ctx, marketId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The market ID to query for | Yes |
Response Parameters
Response Example:
{
"state":{
"cumulativeFunding":"-43868182364823854683390",
"cumulativePrice":"0",
"lastTimestamp":"1709557200"
}
}
Parameter | Type | Description |
---|---|---|
state | PerpetualMarketFunding | Market funding information |
PerpetualMarketFunding
Parameter | Type | Description |
---|---|---|
cumulative_funding | Decimal | The market's cumulative funding |
cumulative_price | Decimal | The cumulative price for the current hour up to the last timestamp |
last_timestamp | Integer | Last funding timestamp in seconds |
TraderDerivativeConditionalOrders
Retrieves a trader's derivative conditional orders
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
orders = await client.fetch_trader_derivative_conditional_orders(
subaccount_id=subaccount_id,
market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
)
print(orders)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
subaccountId := chainClient.Subaccount(senderAddress, 0)
res, err := chainClient.FetchTraderDerivativeConditionalOrders(ctx, subaccountId.Hex(), marketId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | Trader subaccount ID | No |
market_id | String | The market ID to query for | No |
Response Parameters
Response Example:
{
"orders":[
]
}
Parameter | Type | Description |
---|---|---|
orders | TrimmedDerivativeConditionalOrder Array | List of conditional orders |
TrimmedDerivativeConditionalOrder
Parameter | Type | Description |
---|---|---|
price | Decimal | The order price |
quantity | Decimal | The order quantity |
margin | Decimal | The order margin |
trigger_price | OracleType | Price to trigger the order |
is_buy | Boolean | True if the order is a buy order. False otherwise. |
is_limit | Boolean | True if the order is a limit order. False otherwise. |
order_hash | String | The order hash |
cid | String | The client order ID provided by the creator |
MsgInstantPerpetualMarketLaunch
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
from decimal import Decimal
import dotenv
from pyinjective.async_client import AsyncClient
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
await client.initialize_tokens_from_chain_denoms()
composer = await client.composer()
await client.sync_timeout_height()
message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
network=network,
private_key=configured_private_key,
)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
# prepare tx msg
message = composer.msg_instant_perpetual_market_launch(
sender=address.to_acc_bech32(),
ticker="INJ/USDC PERP",
quote_denom="USDC",
oracle_base="INJ",
oracle_quote="USDC",
oracle_scale_factor=6,
oracle_type="Band",
maker_fee_rate=Decimal("-0.0001"),
taker_fee_rate=Decimal("0.001"),
initial_margin_ratio=Decimal("0.33"),
maintenance_margin_ratio=Decimal("0.095"),
min_price_tick_size=Decimal("0.001"),
min_quantity_tick_size=Decimal("0.01"),
min_notional=Decimal("1"),
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"cosmossdk.io/math"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
oracletypes "github.com/InjectiveLabs/sdk-go/chain/oracle/types"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := chainclient.NewMarketsAssistantInitializedFromChain(ctx, exchangeClient)
if err != nil {
panic(err)
}
quoteToken := marketsAssistant.AllTokens()["USDC"]
minPriceTickSize := math.LegacyMustNewDecFromStr("0.01")
minQuantityTickSize := math.LegacyMustNewDecFromStr("0.001")
chainMinPriceTickSize := minPriceTickSize.Mul(math.LegacyNewDecFromIntWithPrec(math.NewInt(1), int64(quoteToken.Decimals)))
chainMinQuantityTickSize := minQuantityTickSize
msg := &exchangetypes.MsgInstantPerpetualMarketLaunch{
Sender: senderAddress.String(),
Ticker: "INJ/USDC PERP",
QuoteDenom: quoteToken.Denom,
OracleBase: "INJ",
OracleQuote: "USDC",
OracleScaleFactor: 6,
OracleType: oracletypes.OracleType_Band,
MakerFeeRate: math.LegacyMustNewDecFromStr("-0.0001"),
TakerFeeRate: math.LegacyMustNewDecFromStr("0.001"),
InitialMarginRatio: math.LegacyMustNewDecFromStr("0.33"),
MaintenanceMarginRatio: math.LegacyMustNewDecFromStr("0.095"),
MinPriceTickSize: chainMinPriceTickSize,
MinQuantityTickSize: chainMinQuantityTickSize,
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.AsyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The market launch requestor address | Yes |
ticker | String | Ticker for the perpetual market | Yes |
quote_denom | String | Quote tocken denom | Yes |
oracle_base | String | Oracle base currency | Yes |
oracle_quote | String | Oracle quote currency | Yes |
oracle_scale_factor | Integer | Scale factor for oracle prices | Yes |
oracle_type | OracleType | The oracle type | Yes |
maker_fee_rate | Decimal | Defines the trade fee rate for makers on the perpetual market | Yes |
taker_fee_rate | Decimal | Defines the trade fee rate for takers on the perpetual market | Yes |
initial_margin_ratio | Decimal | Defines the initial margin ratio for the perpetual market | Yes |
maintenance_margin_ratio | Decimal | Defines the maintenance margin ratio for the perpetual market | Yes |
min_price_tick_size | Decimal | Defines the minimum tick size of the order's price | Yes |
min_quantity_tick_size | Decimal | Defines the minimum tick size of the order's quantity | Yes |
min_notional | Decimal | Defines the minimum notional (in quote asset) required for orders in the market | Yes |
OracleType
Code | Name |
---|---|
0 | Unspecified |
1 | Band |
2 | PriceFeed |
3 | Coinbase |
4 | Chainlink |
5 | Razor |
6 | Dia |
7 | API3 |
8 | Uma |
9 | Pyth |
10 | BandIBC |
11 | Provider |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgInstantExpiryFuturesMarketLaunch
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
from decimal import Decimal
import dotenv
from pyinjective.async_client import AsyncClient
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
await client.initialize_tokens_from_chain_denoms()
composer = await client.composer()
await client.sync_timeout_height()
message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
network=network,
private_key=configured_private_key,
)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
# prepare tx msg
message = composer.msg_instant_expiry_futures_market_launch(
sender=address.to_acc_bech32(),
ticker="INJ/USDC FUT",
quote_denom="USDC",
oracle_base="INJ",
oracle_quote="USDC",
oracle_scale_factor=6,
oracle_type="Band",
expiry=2000000000,
maker_fee_rate=Decimal("-0.0001"),
taker_fee_rate=Decimal("0.001"),
initial_margin_ratio=Decimal("0.33"),
maintenance_margin_ratio=Decimal("0.095"),
min_price_tick_size=Decimal("0.001"),
min_quantity_tick_size=Decimal("0.01"),
min_notional=Decimal("1"),
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"cosmossdk.io/math"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
oracletypes "github.com/InjectiveLabs/sdk-go/chain/oracle/types"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := chainclient.NewMarketsAssistantInitializedFromChain(ctx, exchangeClient)
if err != nil {
panic(err)
}
quoteToken := marketsAssistant.AllTokens()["USDC"]
minPriceTickSize := math.LegacyMustNewDecFromStr("0.01")
minQuantityTickSize := math.LegacyMustNewDecFromStr("0.001")
chainMinPriceTickSize := minPriceTickSize.Mul(math.LegacyNewDecFromIntWithPrec(math.NewInt(1), int64(quoteToken.Decimals)))
chainMinQuantityTickSize := minQuantityTickSize
msg := &exchangetypes.MsgInstantExpiryFuturesMarketLaunch{
Sender: senderAddress.String(),
Ticker: "INJ/USDC FUT",
QuoteDenom: quoteToken.Denom,
OracleBase: "INJ",
OracleQuote: "USDC",
OracleScaleFactor: 6,
OracleType: oracletypes.OracleType_Band,
Expiry: 2000000000,
MakerFeeRate: math.LegacyMustNewDecFromStr("-0.0001"),
TakerFeeRate: math.LegacyMustNewDecFromStr("0.001"),
InitialMarginRatio: math.LegacyMustNewDecFromStr("0.33"),
MaintenanceMarginRatio: math.LegacyMustNewDecFromStr("0.095"),
MinPriceTickSize: chainMinPriceTickSize,
MinQuantityTickSize: chainMinQuantityTickSize,
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.AsyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The market launch requestor address | Yes |
ticker | String | Ticker for the expiry futures market | Yes |
quote_denom | String | Quote tocken denom | Yes |
oracle_base | String | Oracle base currency | Yes |
oracle_quote | String | Oracle quote currency | Yes |
oracle_type | OracleType | The oracle type | Yes |
oracle_scale_factor | Integer | Scale factor for oracle prices | Yes |
expiry | Integer | Expiration time of the market | Yes |
maker_fee_rate | Decimal | Defines the trade fee rate for makers on the perpetual market | Yes |
taker_fee_rate | Decimal | Defines the trade fee rate for takers on the perpetual market | Yes |
initial_margin_ratio | Decimal | Defines the initial margin ratio for the perpetual market | Yes |
maintenance_margin_ratio | Decimal | Defines the maintenance margin ratio for the perpetual market | Yes |
min_price_tick_size | Decimal | Defines the minimum tick size of the order's price | Yes |
min_quantity_tick_size | Decimal | Defines the minimum tick size of the order's quantity | Yes |
min_notional | Decimal | Defines the minimum notional (in quote asset) required for orders in the market | Yes |
OracleType
Code | Name |
---|---|
0 | Unspecified |
1 | Band |
2 | PriceFeed |
3 | Coinbase |
4 | Chainlink |
5 | Razor |
6 | Dia |
7 | API3 |
8 | Uma |
9 | Pyth |
10 | BandIBC |
11 | Provider |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgCreateDerivativeLimitOrder
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import uuid
from decimal import Decimal
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
# prepare trade info
market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
# prepare tx msg
msg = composer.msg_create_derivative_limit_order(
sender=address.to_acc_bech32(),
market_id=market_id,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal(50000),
quantity=Decimal(0.1),
margin=composer.calculate_margin(
quantity=Decimal(0.1), price=Decimal(50000), leverage=Decimal(1), is_reduce_only=False
),
order_type="SELL",
cid=str(uuid.uuid4()),
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
sim_res_msg = sim_res["result"]["msgResponses"]
print("---Simulation Response---")
print(sim_res_msg)
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print("---Transaction Response---")
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"os"
"time"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
"github.com/google/uuid"
"github.com/InjectiveLabs/sdk-go/client/common"
"github.com/shopspring/decimal"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := chainclient.NewMarketsAssistantInitializedFromChain(ctx, exchangeClient)
if err != nil {
panic(err)
}
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
defaultSubaccountID := chainClient.DefaultSubaccount(senderAddress)
marketId := "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"
amount := decimal.NewFromFloat(0.001)
price := decimal.RequireFromString("31000") //31,000
leverage := decimal.RequireFromString("2.5")
order := chainClient.CreateDerivativeOrder(
defaultSubaccountID,
&chainclient.DerivativeOrderData{
OrderType: exchangetypes.OrderType_BUY, //BUY SELL BUY_PO SELL_PO
Quantity: amount,
Price: price,
Leverage: leverage,
FeeRecipient: senderAddress.String(),
MarketId: marketId,
IsReduceOnly: true,
Cid: uuid.NewString(),
},
marketsAssistant,
)
msg := new(exchangetypes.MsgCreateDerivativeLimitOrder)
msg.Sender = senderAddress.String()
msg.Order = exchangetypes.DerivativeOrder(*order)
simRes, err := chainClient.SimulateMsg(clientCtx, msg)
if err != nil {
panic(err)
}
msgCreateDerivativeLimitOrderResponse := exchangetypes.MsgCreateDerivativeLimitOrderResponse{}
err = msgCreateDerivativeLimitOrderResponse.Unmarshal(simRes.Result.MsgResponses[0].Value)
if err != nil {
panic(err)
}
fmt.Println("simulated order hash", msgCreateDerivativeLimitOrderResponse.OrderHash)
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The message sender's address | Yes |
order | DerivativeOrder | Order's parameters | Yes |
DerivativeOrder
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The unique ID of the market | Yes |
order_info | OrderInfo | Order's information | Yes |
order_type | OrderType | The order type | Yes |
margin | Decimal | The margin amount used by the order | Yes |
trigger_price | Decimal | The trigger price used by stop/take orders | No |
OrderInfo
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | Subaccount ID that created the order | Yes |
fee_recipient | String | Address that will receive fees for the order | No |
price | Decimal | Price of the order | Yes |
quantity | Decimal | Quantity of the order | Yes |
cid | String | Client order ID. An optional identifier for the order set by the creator | No |
OrderType
Code | Name |
---|---|
0 | UNSPECIFIED |
1 | BUY |
2 | SELL |
3 | STOP_BUY |
4 | STOP_SELL |
5 | TAKE_BUY |
6 | TAKE_SELL |
7 | BUY_PO |
8 | SELL_PO |
9 | BUY_ATOMIC |
10 | SELL_ATOMIC |
Response Parameters
Response Example:
---Simulation Response---
[order_hash: "0x224e7312eb28955507142e9f761c5ba90165e05688583bffe9281dbe8f3e3083"
]
---Transaction Response---
txhash: "34138C7F4EB05EEBFC7AD81CE187BE13BF12348CB7973388007BE7505F257B14"
raw_log: "[]"
gas wanted: 124365
gas fee: 0.0000621825 INJ
simulated order hash 0x25233ede1fee09310d549241647edcf94cf5378749593b55c27148a80ce655c1
DEBU[0001] broadcastTx with nonce 3495 fn=func1 src="client/chain/chain.go:598"
DEBU[0003] msg batch committed successfully at height 5213085 fn=func1 src="client/chain/chain.go:619" txHash=47644A4BD75A97BF4B0D436821F564976C60C272DD25F966DA88216C2229A32A
DEBU[0003] nonce incremented to 3496 fn=func1 src="client/chain/chain.go:623"
DEBU[0003] gas wanted: 171439 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.0000857195 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgCreateDerivativeMarketOrder
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import uuid
from decimal import Decimal
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
# prepare trade info
market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
# prepare tx msg
msg = composer.msg_create_derivative_market_order(
sender=address.to_acc_bech32(),
market_id=market_id,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal(50000),
quantity=Decimal(0.1),
margin=composer.calculate_margin(
quantity=Decimal(0.1), price=Decimal(50000), leverage=Decimal(1), is_reduce_only=False
),
order_type="BUY",
cid=str(uuid.uuid4()),
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
sim_res_msg = sim_res["result"]["msgResponses"]
print("---Simulation Response---")
print(sim_res_msg)
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print("---Transaction Response---")
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"os"
"time"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
"github.com/google/uuid"
"github.com/InjectiveLabs/sdk-go/client/common"
"github.com/shopspring/decimal"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
fmt.Println(err)
return
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := chainclient.NewMarketsAssistantInitializedFromChain(ctx, exchangeClient)
if err != nil {
panic(err)
}
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
defaultSubaccountID := chainClient.DefaultSubaccount(senderAddress)
marketId := "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"
amount := decimal.NewFromFloat(0.01)
price := decimal.RequireFromString("33000") //33,000
leverage := decimal.RequireFromString("2.5")
order := chainClient.CreateDerivativeOrder(
defaultSubaccountID,
&chainclient.DerivativeOrderData{
OrderType: exchangetypes.OrderType_SELL, //BUY SELL
Quantity: amount,
Price: price,
Leverage: leverage,
FeeRecipient: senderAddress.String(),
MarketId: marketId,
IsReduceOnly: true,
Cid: uuid.NewString(),
},
marketsAssistant,
)
msg := new(exchangetypes.MsgCreateDerivativeMarketOrder)
msg.Sender = senderAddress.String()
msg.Order = exchangetypes.DerivativeOrder(*order)
simRes, err := chainClient.SimulateMsg(clientCtx, msg)
if err != nil {
panic(err)
}
msgCreateDerivativeMarketOrderResponse := exchangetypes.MsgCreateDerivativeMarketOrderResponse{}
err = msgCreateDerivativeMarketOrderResponse.Unmarshal(simRes.Result.MsgResponses[0].Value)
if err != nil {
panic(err)
}
fmt.Println("simulated order hash", msgCreateDerivativeMarketOrderResponse.OrderHash)
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
return
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The message sender's address | Yes |
order | DerivativeOrder | Order's parameters | Yes |
DerivativeOrder
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The unique ID of the market | Yes |
order_info | OrderInfo | Order's information | Yes |
order_type | OrderType | The order type | Yes |
margin | Decimal | The margin amount used by the order | Yes |
trigger_price | Decimal | The trigger price used by stop/take orders | No |
OrderInfo
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | Subaccount ID that created the order | Yes |
fee_recipient | String | Address that will receive fees for the order | No |
price | Decimal | Price of the order | Yes |
quantity | Decimal | Quantity of the order | Yes |
cid | String | Client order ID. An optional identifier for the order set by the creator | No |
OrderType
Code | Name |
---|---|
0 | UNSPECIFIED |
1 | BUY |
2 | SELL |
3 | STOP_BUY |
4 | STOP_SELL |
5 | TAKE_BUY |
6 | TAKE_SELL |
7 | BUY_PO |
8 | SELL_PO |
9 | BUY_ATOMIC |
10 | SELL_ATOMIC |
Response Parameters
Response Example:
---Simulation Response---
[order_hash: "0xcd0e33273d3a5688ef35cf3d857bd37df4a6b7a0698fdc46d77bbaeb79ffbbe4"
]
---Transaction Response---
txhash: "A4B30567DE6AB33F076858B6ED99BE757C084A2A217CEC98054DCEA5B8A0875D"
raw_log: "[]"
gas wanted: 110924
gas fee: 0.000055462 INJ
simulated order hash 0x2df7d24f919f833138b50f0b01ac200ec2e7bdc679fb144d152487fc23d6cfd0
DEBU[0001] broadcastTx with nonce 3496 fn=func1 src="client/chain/chain.go:598"
DEBU[0003] msg batch committed successfully at height 5213175 fn=func1 src="client/chain/chain.go:619" txHash=613A5264D460E9AA34ADD89987994A15A9AE5BF62BA8FFD53E3AA490F5AE0A6E
DEBU[0003] nonce incremented to 3497 fn=func1 src="client/chain/chain.go:623"
DEBU[0003] gas wanted: 139962 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.000069981 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgCancelDerivativeOrder
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
# prepare trade info
market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
order_hash = "0x667ee6f37f6d06bf473f4e1434e92ac98ff43c785405e2a511a0843daeca2de9"
# prepare tx msg
msg = composer.msg_cancel_derivative_order(
sender=address.to_acc_bech32(), market_id=market_id, subaccount_id=subaccount_id, order_hash=order_hash
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"fmt"
"os"
"time"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
msg := &exchangetypes.MsgCancelDerivativeOrder{
Sender: senderAddress.String(),
MarketId: "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
SubaccountId: "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
OrderHash: "0x8cf97e586c0d84cd7864ccc8916b886557120d84fc97a21ae193b67882835ec5",
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The message sender's address | Yes |
market_id | String | The unique ID of the order's market | Yes |
subaccount_id | String | The subaccount ID the order belongs to | Yes |
order_hash | String | The order hash (either order_hash or cid have to be provided) | No |
order_mask | OrderMask | The order mask that specifies the order type | No |
cid | String | The client order ID provided by the creator (either order_hash or cid have to be provided) | No |
OrderMask
Code | Name |
---|---|
0 | OrderMask_UNUSED |
1 | OrderMask_ANY |
2 | OrderMask_REGULAR |
4 | OrderMask_CONDITIONAL |
8 | OrderMask_BUY_OR_HIGHER |
16 | OrderMask_SELL_OR_LOWER |
32 | OrderMask_MARKET |
64 | OrderMask_LIMIT |
Response Parameters
Response Example:
---Simulation Response---
[success: true
success: false
]
---Transaction Response---
txhash: "862F4ABD2A75BD15B9BCEDB914653743F11CDB19583FB9018EB5A78B8D4ED264"
raw_log: "[]"
gas wanted: 118158
gas fee: 0.000059079 INJ
DEBU[0001] broadcastTx with nonce 3497 fn=func1 src="client/chain/chain.go:598"
DEBU[0003] msg batch committed successfully at height 5213261 fn=func1 src="client/chain/chain.go:619" txHash=71016DBB5723031C8DBF6B05A498DE5390BC91FE226E23E3F70497B584E6EB3B
DEBU[0003] nonce incremented to 3498 fn=func1 src="client/chain/chain.go:623"
DEBU[0003] gas wanted: 141373 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.0000706865 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgBatchUpdateOrders
MsgBatchUpdateOrders allows for the atomic cancellation and creation of spot and derivative limit orders, along with a new order cancellation mode. Upon execution, order cancellations (if any) occur first, followed by order creations (if any).
Users can cancel all limit orders in a given spot or derivative market for a given subaccountID by specifying the associated marketID in the SpotMarketIdsToCancelAll and DerivativeMarketIdsToCancelAll. Users can also cancel individual limit orders in SpotOrdersToCancel or DerivativeOrdersToCancel, but must ensure that marketIDs in these individual order cancellations are not already provided in the SpotMarketIdsToCancelAll or DerivativeMarketIdsToCancelAll.
Further note that if no marketIDs are provided in the SpotMarketIdsToCancelAll or DerivativeMarketIdsToCancelAll, then the SubaccountID in the Msg should be left empty.
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import uuid
from decimal import Decimal
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
# prepare trade info
fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
derivative_market_id_create = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
spot_market_id_create = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
derivative_market_id_cancel = "0xd5e4b12b19ecf176e4e14b42944731c27677819d2ed93be4104ad7025529c7ff"
derivative_market_id_cancel_2 = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
spot_market_id_cancel = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
spot_market_id_cancel_2 = "0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0"
derivative_orders_to_cancel = [
composer.order_data(
market_id=derivative_market_id_cancel,
subaccount_id=subaccount_id,
order_hash="0x48690013c382d5dbaff9989db04629a16a5818d7524e027d517ccc89fd068103",
),
composer.order_data(
market_id=derivative_market_id_cancel_2,
subaccount_id=subaccount_id,
order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5",
),
]
spot_orders_to_cancel = [
composer.order_data(
market_id=spot_market_id_cancel,
subaccount_id=subaccount_id,
cid="0e5c3ad5-2cc4-4a2a-bbe5-b12697739163",
),
composer.order_data(
market_id=spot_market_id_cancel_2,
subaccount_id=subaccount_id,
order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2",
),
]
derivative_orders_to_create = [
composer.derivative_order(
market_id=derivative_market_id_create,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal(25000),
quantity=Decimal(0.1),
margin=composer.calculate_margin(
quantity=Decimal(0.1), price=Decimal(25000), leverage=Decimal(1), is_reduce_only=False
),
order_type="BUY",
cid=str(uuid.uuid4()),
),
composer.derivative_order(
market_id=derivative_market_id_create,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal(50000),
quantity=Decimal(0.01),
margin=composer.calculate_margin(
quantity=Decimal(0.01), price=Decimal(50000), leverage=Decimal(1), is_reduce_only=False
),
order_type="SELL",
cid=str(uuid.uuid4()),
),
]
spot_orders_to_create = [
composer.spot_order(
market_id=spot_market_id_create,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal("3"),
quantity=Decimal("55"),
order_type="BUY",
cid=str(uuid.uuid4()),
),
composer.spot_order(
market_id=spot_market_id_create,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal("300"),
quantity=Decimal("55"),
order_type="SELL",
cid=str(uuid.uuid4()),
),
]
# prepare tx msg
msg = composer.msg_batch_update_orders(
sender=address.to_acc_bech32(),
derivative_orders_to_create=derivative_orders_to_create,
spot_orders_to_create=spot_orders_to_create,
derivative_orders_to_cancel=derivative_orders_to_cancel,
spot_orders_to_cancel=spot_orders_to_cancel,
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
sim_res_msg = sim_res["result"]["msgResponses"]
print("---Simulation Response---")
print(sim_res_msg)
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print("---Transaction Response---")
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"os"
"time"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
"github.com/google/uuid"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
"github.com/shopspring/decimal"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
fmt.Println(err)
return
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := chainclient.NewMarketsAssistantInitializedFromChain(ctx, exchangeClient)
if err != nil {
panic(err)
}
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
fmt.Println(err)
return
}
defaultSubaccountID := chainClient.DefaultSubaccount(senderAddress)
smarketId := "0x0511ddc4e6586f3bfe1acb2dd905f8b8a82c97e1edaef654b12ca7e6031ca0fa"
samount := decimal.NewFromFloat(2)
sprice := decimal.NewFromFloat(22.5)
smarketIds := []string{"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"}
spot_order := chainClient.CreateSpotOrder(
defaultSubaccountID,
&chainclient.SpotOrderData{
OrderType: exchangetypes.OrderType_BUY, //BUY SELL BUY_PO SELL_PO
Quantity: samount,
Price: sprice,
FeeRecipient: senderAddress.String(),
MarketId: smarketId,
Cid: uuid.NewString(),
},
marketsAssistant,
)
dmarketId := "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"
damount := decimal.NewFromFloat(0.01)
dprice := decimal.RequireFromString("31000") //31,000
dleverage := decimal.RequireFromString("2")
dmarketIds := []string{"0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"}
derivative_order := chainClient.CreateDerivativeOrder(
defaultSubaccountID,
&chainclient.DerivativeOrderData{
OrderType: exchangetypes.OrderType_BUY, //BUY SELL BUY_PO SELL_PO
Quantity: damount,
Price: dprice,
Leverage: dleverage,
FeeRecipient: senderAddress.String(),
MarketId: dmarketId,
IsReduceOnly: false,
Cid: uuid.NewString(),
},
marketsAssistant,
)
msg := new(exchangetypes.MsgBatchUpdateOrders)
msg.Sender = senderAddress.String()
msg.SubaccountId = defaultSubaccountID.Hex()
msg.SpotOrdersToCreate = []*exchangetypes.SpotOrder{spot_order}
msg.DerivativeOrdersToCreate = []*exchangetypes.DerivativeOrder{derivative_order}
msg.SpotMarketIdsToCancelAll = smarketIds
msg.DerivativeMarketIdsToCancelAll = dmarketIds
simRes, err := chainClient.SimulateMsg(clientCtx, msg)
if err != nil {
fmt.Println(err)
return
}
MsgBatchUpdateOrdersResponse := exchangetypes.MsgBatchUpdateOrdersResponse{}
MsgBatchUpdateOrdersResponse.Unmarshal(simRes.Result.MsgResponses[0].Value)
fmt.Println("simulated spot order hashes", MsgBatchUpdateOrdersResponse.SpotOrderHashes)
fmt.Println("simulated derivative order hashes", MsgBatchUpdateOrdersResponse.DerivativeOrderHashes)
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
return
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The message sender's address | Yes |
subaccount_id | String | The subaccount ID is only used for the spot_market_ids_to_cancel_all and derivative_market_ids_to_cancel_all | No |
spot_market_ids_to_cancel_all | String Array | List of unique market IDs to cancel all subaccount_id orders | No |
derivative_market_ids_to_cancel_all | String Array | List of unique market IDs to cancel all subaccount_id orders | No |
spot_orders_to_cancel | OrderData Array | List of spot orders to be cancelled | No |
derivative_orders_to_cancel | OrderData Array | List of derivative orders to be cancelled | No |
spot_orders_to_create | SpotOrder Array | List of spot orders to be created | No |
derivative_orders_to_create | DerivativeOrder Array | List of derivative orders to be created | No |
binary_options_orders_to_cancel | OrderData Array | List of binary options orders to be cancelled | No |
binary_options_market_ids_to_cancel_all | String Array | List of unique market IDs to cancel all subaccount_id orders | No |
binary_options_orders_to_create | DerivativeOrder Array | List of binary options orders to be created | No |
OrderData
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The order's market ID | Yes |
subaccount_id | String | Subaccount ID that created the order | Yes |
order_hash | String | The order hash (either the order_hash or the cid should be provided) | No |
order_mask | OrderMask | The order mask that specifies the order type | No |
cid | String | The order's client order ID (either the order_hash or the cid should be provided) | No |
SpotOrder
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The unique ID of the market | Yes |
order_info | OrderInfo | Order's information | Yes |
order_type | OrderType | The order type | Yes |
trigger_price | Decimal | The trigger price used by stop/take orders | No |
DerivativeOrder
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The unique ID of the market | Yes |
order_info | OrderInfo | Order's information | Yes |
order_type | OrderType | The order type | Yes |
margin | Decimal | The margin amount used by the order | Yes |
trigger_price | Decimal | The trigger price used by stop/take orders | No |
OrderMask
Code | Name |
---|---|
0 | OrderMask_UNUSED |
1 | OrderMask_ANY |
2 | OrderMask_REGULAR |
4 | OrderMask_CONDITIONAL |
8 | OrderMask_BUY_OR_HIGHER |
16 | OrderMask_SELL_OR_LOWER |
32 | OrderMask_MARKET |
64 | OrderMask_LIMIT |
OrderInfo
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | Subaccount ID that created the order | Yes |
fee_recipient | String | Address that will receive fees for the order | No |
price | Decimal | Price of the order | Yes |
quantity | Decimal | Quantity of the order | Yes |
cid | String | Client order ID. An optional identifier for the order set by the creator | No |
OrderType
Code | Name |
---|---|
0 | UNSPECIFIED |
1 | BUY |
2 | SELL |
3 | STOP_BUY |
4 | STOP_SELL |
5 | TAKE_BUY |
6 | TAKE_SELL |
7 | BUY_PO |
8 | SELL_PO |
9 | BUY_ATOMIC |
10 | SELL_ATOMIC |
Response Parameters
Response Example:
---Simulation Response---
[spot_cancel_success: false
spot_cancel_success: false
derivative_cancel_success: false
derivative_cancel_success: false
spot_order_hashes: "0x3f5b5de6ec72b250c58e0a83408dbc1990cee369999036e3469e19b80fa9002e"
spot_order_hashes: "0x7d8580354e120b038967a180f73bc3aba0f49db9b6d2cb5c4cec85e8cab3e218"
derivative_order_hashes: "0x920a4ea4144c46d1e1084ca5807e4f5608639ce00f97139d5b44e628d487e15e"
derivative_order_hashes: "0x11d75d0c2ce8a07f352523be2e3456212c623397d0fc1a2f688b97a15c04372c"
]
---Transaction Response---
txhash: "4E29226884DCA22E127471588F39E0BB03D314E1AA27ECD810D24C4078D52DED"
raw_log: "[]"
gas wanted: 271213
gas fee: 0.0001356065 INJ
simulated spot order hashes [0xd9f30c7e700202615c2775d630b9fb276572d883fa480b6394abbddcb79c8109]
simulated derivative order hashes [0xb2bea3b15c204699a9ee945ca49650001560518d1e54266adac580aa061fedd4]
DEBU[0001] broadcastTx with nonce 3507 fn=func1 src="client/chain/chain.go:598"
DEBU[0003] msg batch committed successfully at height 5214679 fn=func1 src="client/chain/chain.go:619" txHash=CF53E0B31B9E28E0D6D8F763ECEC2D91E38481321EA24AC86F6A8774C658AF44
DEBU[0003] nonce incremented to 3508 fn=func1 src="client/chain/chain.go:623"
DEBU[0003] gas wanted: 659092 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.000329546 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgLiquidatePosition
This message is sent to the chain when a particular position has reached the liquidation price, to liquidate that position.
To detect the liquidable positions please use the Indexer endpoint called LiquidablePositions
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import uuid
from decimal import Decimal
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
# prepare trade info
market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
cid = str(uuid.uuid4())
order = composer.derivative_order(
market_id=market_id,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal(39.01), # This should be the liquidation price
quantity=Decimal(0.147),
margin=composer.calculate_margin(
quantity=Decimal(0.147), price=Decimal(39.01), leverage=Decimal(1), is_reduce_only=False
),
order_type="SELL",
cid=cid,
)
# prepare tx msg
msg = composer.msg_liquidate_position(
sender=address.to_acc_bech32(),
subaccount_id="0x156df4d5bc8e7dd9191433e54bd6a11eeb390921000000000000000000000000",
market_id=market_id,
order=order,
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
sim_res_msg = sim_res["result"]["msgResponses"]
print("---Simulation Response---")
print(sim_res_msg)
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print("---Transaction Response---")
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
print(f"\n\ncid: {cid}")
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
"github.com/google/uuid"
"github.com/InjectiveLabs/sdk-go/client/common"
"github.com/shopspring/decimal"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := chainclient.NewMarketsAssistantInitializedFromChain(ctx, exchangeClient)
if err != nil {
panic(err)
}
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
defaultSubaccountID := chainClient.DefaultSubaccount(senderAddress)
marketId := "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
amount := decimal.NewFromFloat(0.147)
price := decimal.RequireFromString("39.01")
leverage := decimal.RequireFromString("1")
order := chainClient.CreateDerivativeOrder(
defaultSubaccountID,
&chainclient.DerivativeOrderData{
OrderType: exchangetypes.OrderType_SELL,
Quantity: amount,
Price: price,
Leverage: leverage,
FeeRecipient: senderAddress.String(),
MarketId: marketId,
Cid: uuid.NewString(),
},
marketsAssistant,
)
msg := &exchangetypes.MsgLiquidatePosition{
Sender: senderAddress.String(),
SubaccountId: "0x156df4d5bc8e7dd9191433e54bd6a11eeb390921000000000000000000000000",
MarketId: marketId,
Order: order,
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.AsyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The message sender's address | Yes |
subaccount_id | String | The subaccount ID to create the order | Yes |
market_id | String | The order's unique market ID | Yes |
order | DerivativeOrder | Order's parameters | Yes |
DerivativeOrder
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The unique ID of the market | Yes |
order_info | OrderInfo | Order's information | Yes |
order_type | OrderType | The order type | Yes |
margin | Decimal | The margin amount used by the order | Yes |
trigger_price | Decimal | The trigger price used by stop/take orders | No |
OrderInfo
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | Subaccount ID that created the order | Yes |
fee_recipient | String | Address that will receive fees for the order | No |
price | Decimal | Price of the order | Yes |
quantity | Decimal | Quantity of the order | Yes |
cid | String | Client order ID. An optional identifier for the order set by the creator | No |
OrderType
Code | Name |
---|---|
0 | UNSPECIFIED |
1 | BUY |
2 | SELL |
3 | STOP_BUY |
4 | STOP_SELL |
5 | TAKE_BUY |
6 | TAKE_SELL |
7 | BUY_PO |
8 | SELL_PO |
9 | BUY_ATOMIC |
10 | SELL_ATOMIC |
<!-- MARKDOWN-AUTO-DOCS:END -->|
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgIncreasePositionMargin
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
from decimal import Decimal
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
# prepare trade info
market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
# prepare tx msg
msg = composer.msg_increase_position_margin(
sender=address.to_acc_bech32(),
market_id=market_id,
source_subaccount_id=subaccount_id,
destination_subaccount_id=subaccount_id,
amount=Decimal(2),
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"fmt"
"os"
"time"
"cosmossdk.io/math"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
msg := &exchangetypes.MsgIncreasePositionMargin{
Sender: senderAddress.String(),
MarketId: "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce",
SourceSubaccountId: "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
DestinationSubaccountId: "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
Amount: math.LegacyMustNewDecFromStr("100000000"), //100 USDT
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The sender's address | Yes |
source_subaccount_id | String | Subaccount ID from where the funds are deducted | Yes |
destination_subaccount_id | String | Subaccount ID the funds are deposited into | Yes |
market_id | String | The position's unique market ID | Yes |
amount | Decimal | The amount of margin to add to the position | Yes |
Response Parameters
Response Example:
txhash: "5AF048ADCE6AF753256F03AF2404A5B78C4C3E7E42A91F0B5C9994372E8AC2FE"
raw_log: "[]"
gas wanted: 106585
gas fee: 0.0000532925 INJ
DEBU[0001] broadcastTx with nonce 3503 fn=func1 src="client/chain/chain.go:598"
DEBU[0002] msg batch committed successfully at height 5214406 fn=func1 src="client/chain/chain.go:619"
txHash=31FDA89C3122322C0559B5766CDF892FD0AA12469017CF8BF88B53441464ECC4
DEBU[0002] nonce incremented to 3504 fn=func1 src="client/chain/chain.go:623"
DEBU[0002] gas wanted: 133614 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.000066807 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgDecreasePositionMargin
Message to reduce the margin assigned to a particular position
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
from decimal import Decimal
import dotenv
from pyinjective.async_client import AsyncClient
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
network=network,
private_key=configured_private_key,
)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
# prepare trade info
market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
# prepare tx msg
msg = composer.msg_decrease_position_margin(
sender=address.to_acc_bech32(),
market_id=market_id,
source_subaccount_id=subaccount_id,
destination_subaccount_id=subaccount_id,
amount=Decimal(2),
)
# broadcast the transaction
result = await message_broadcaster.broadcast([msg])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"encoding/json"
"fmt"
"os"
"cosmossdk.io/math"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
defaultSubaccountID := chainClient.DefaultSubaccount(senderAddress)
msg := &exchangetypes.MsgDecreasePositionMargin{
Sender: senderAddress.String(),
MarketId: "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
SourceSubaccountId: defaultSubaccountID.String(),
DestinationSubaccountId: defaultSubaccountID.String(),
Amount: math.LegacyMustNewDecFromStr("100000000"), //100 USDT
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.AsyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The sender's address | Yes |
source_subaccount_id | String | Subaccount ID the position belongs to | Yes |
destination_subaccount_id | String | Subaccount ID the funds are deposited into | Yes |
market_id | String | The position's unique market ID | Yes |
amount | Decimal | The amount of margin to remove from the position | Yes |
Response Parameters
Response Example:
txhash: "5AF048ADCE6AF753256F03AF2404A5B78C4C3E7E42A91F0B5C9994372E8AC2FE"
raw_log: "[]"
gas wanted: 106585
gas fee: 0.0000532925 INJ
DEBU[0001] broadcastTx with nonce 3503 fn=func1 src="client/chain/chain.go:598"
DEBU[0002] msg batch committed successfully at height 5214406 fn=func1 src="client/chain/chain.go:619"
txHash=31FDA89C3122322C0559B5766CDF892FD0AA12469017CF8BF88B53441464ECC4
DEBU[0002] nonce incremented to 3504 fn=func1 src="client/chain/chain.go:623"
DEBU[0002] gas wanted: 133614 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.000066807 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgUpdateDerivativeMarket
Modifies certain market fields. It can only be sent by the market's admin.
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
from decimal import Decimal
import dotenv
from pyinjective.async_client import AsyncClient
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
await client.initialize_tokens_from_chain_denoms()
composer = await client.composer()
await client.sync_timeout_height()
message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
network=network,
private_key=configured_private_key,
)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
# prepare tx msg
message = composer.msg_update_derivative_market(
admin=address.to_acc_bech32(),
market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
new_ticker="INJ/USDT PERP 2",
new_min_price_tick_size=Decimal("1"),
new_min_quantity_tick_size=Decimal("1"),
new_min_notional=Decimal("2"),
new_initial_margin_ratio=Decimal("0.40"),
new_maintenance_margin_ratio=Decimal("0.085"),
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"cosmossdk.io/math"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := chainclient.NewMarketsAssistantInitializedFromChain(ctx, exchangeClient)
if err != nil {
panic(err)
}
quoteToken := marketsAssistant.AllTokens()["USDT"]
minPriceTickSize := math.LegacyMustNewDecFromStr("0.1")
minQuantityTickSize := math.LegacyMustNewDecFromStr("0.1")
minNotional := math.LegacyMustNewDecFromStr("2")
chainMinPriceTickSize := minPriceTickSize.Mul(math.LegacyNewDecFromIntWithPrec(math.NewInt(1), int64(quoteToken.Decimals)))
chainMinQuantityTickSize := minQuantityTickSize
chainMinNotional := minNotional.Mul(math.LegacyNewDecFromIntWithPrec(math.NewInt(1), int64(quoteToken.Decimals)))
msg := &exchangetypes.MsgUpdateDerivativeMarket{
Admin: senderAddress.String(),
MarketId: "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
NewTicker: "INJ/USDT PERP 2",
NewMinPriceTickSize: chainMinPriceTickSize,
NewMinQuantityTickSize: chainMinQuantityTickSize,
NewMinNotional: chainMinNotional,
NewInitialMarginRatio: math.LegacyMustNewDecFromStr("0.4"),
NewMaintenanceMarginRatio: math.LegacyMustNewDecFromStr("0.085"),
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.AsyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
admin | String | The market's admin address (has to be the message broadcaster) | Yes |
market_id | String | The market's unique ID | Yes |
new_ticker | String | New ticker for the perpetual market | No |
new_min_price_tick_size | Decimal | Defines the minimum tick size of the order's price | No |
new_min_quantity_tick_size | Decimal | Defines the minimum tick size of the order's quantity | No |
new_min_notional | Decimal | Defines the minimum notional (in quote asset) required for orders in the market | No |
new_initial_margin_ratio | Decimal | Defines the initial margin ratio for the perpetual market | No |
new_maintenance_margin_ratio | Decimal | Defines the maintenance margin ratio for the perpetual market | No |
Response Parameters
Response Example:
txhash: "5AF048ADCE6AF753256F03AF2404A5B78C4C3E7E42A91F0B5C9994372E8AC2FE"
raw_log: "[]"
gas wanted: 106585
gas fee: 0.0000532925 INJ
DEBU[0001] broadcastTx with nonce 3503 fn=func1 src="client/chain/chain.go:598"
DEBU[0002] msg batch committed successfully at height 5214406 fn=func1 src="client/chain/chain.go:619"
txHash=31FDA89C3122322C0559B5766CDF892FD0AA12469017CF8BF88B53441464ECC4
DEBU[0002] nonce incremented to 3504 fn=func1 src="client/chain/chain.go:623"
DEBU[0002] gas wanted: 133614 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.000066807 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
LocalOrderHashComputation
This function computes order hashes locally for SpotOrder and DerivativeOrder. For more information, see the note below.
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import uuid
from decimal import Decimal
import dotenv
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.orderhash import OrderHashManager
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
subaccount_id_2 = address.get_subaccount_id(index=1)
order_hash_manager = OrderHashManager(address=address, network=network, subaccount_indexes=[0, 1, 2, 7])
# prepare trade info
spot_market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
deriv_market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
spot_orders = [
composer.spot_order(
market_id=spot_market_id,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal("0.524"),
quantity=Decimal("0.01"),
order_type="BUY",
cid=str(uuid.uuid4()),
),
composer.spot_order(
market_id=spot_market_id,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal("27.92"),
quantity=Decimal("0.01"),
order_type="SELL",
cid=str(uuid.uuid4()),
),
]
derivative_orders = [
composer.derivative_order(
market_id=deriv_market_id,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal(10500),
quantity=Decimal(0.01),
margin=composer.calculate_margin(
quantity=Decimal(0.01), price=Decimal(10500), leverage=Decimal(2), is_reduce_only=False
),
order_type="BUY",
cid=str(uuid.uuid4()),
),
composer.derivative_order(
market_id=deriv_market_id,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal(65111),
quantity=Decimal(0.01),
margin=composer.calculate_margin(
quantity=Decimal(0.01), price=Decimal(65111), leverage=Decimal(2), is_reduce_only=False
),
order_type="SELL",
cid=str(uuid.uuid4()),
),
]
# prepare tx msg
spot_msg = composer.msg_batch_create_spot_limit_orders(sender=address.to_acc_bech32(), orders=spot_orders)
deriv_msg = composer.msg_batch_create_derivative_limit_orders(
sender=address.to_acc_bech32(), orders=derivative_orders
)
# compute order hashes
order_hashes = order_hash_manager.compute_order_hashes(
spot_orders=spot_orders, derivative_orders=derivative_orders, subaccount_index=0
)
print("computed spot order hashes", order_hashes.spot)
print("computed derivative order hashes", order_hashes.derivative)
# build tx 1
tx = (
Transaction()
.with_messages(spot_msg, deriv_msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
gas_price = GAS_PRICE
base_gas = 85000
gas_limit = base_gas + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
# compute order hashes
order_hashes = order_hash_manager.compute_order_hashes(
spot_orders=spot_orders, derivative_orders=derivative_orders, subaccount_index=0
)
print("computed spot order hashes", order_hashes.spot)
print("computed derivative order hashes", order_hashes.derivative)
# build tx 2
tx = (
Transaction()
.with_messages(spot_msg, deriv_msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
gas_price = GAS_PRICE
base_gas = 85000
gas_limit = base_gas + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
spot_orders = [
composer.spot_order(
market_id=spot_market_id,
subaccount_id=subaccount_id_2,
fee_recipient=fee_recipient,
price=Decimal("1.524"),
quantity=Decimal("0.01"),
order_type="BUY_PO",
cid=str(uuid.uuid4()),
),
composer.spot_order(
market_id=spot_market_id,
subaccount_id=subaccount_id_2,
fee_recipient=fee_recipient,
price=Decimal("27.92"),
quantity=Decimal("0.01"),
order_type="SELL_PO",
cid=str(uuid.uuid4()),
),
]
derivative_orders = [
composer.derivative_order(
market_id=deriv_market_id,
subaccount_id=subaccount_id_2,
fee_recipient=fee_recipient,
price=Decimal(25111),
quantity=Decimal(0.01),
margin=composer.calculate_margin(
quantity=Decimal(0.01), price=Decimal(25111), leverage=Decimal("1.5"), is_reduce_only=False
),
order_type="BUY",
cid=str(uuid.uuid4()),
),
composer.derivative_order(
market_id=deriv_market_id,
subaccount_id=subaccount_id_2,
fee_recipient=fee_recipient,
price=Decimal(65111),
quantity=Decimal(0.01),
margin=composer.calculate_margin(
quantity=Decimal(0.01), price=Decimal(25111), leverage=Decimal(2), is_reduce_only=False
),
order_type="SELL",
cid=str(uuid.uuid4()),
),
]
# prepare tx msg
spot_msg = composer.msg_batch_create_spot_limit_orders(sender=address.to_acc_bech32(), orders=spot_orders)
deriv_msg = composer.msg_batch_create_derivative_limit_orders(
sender=address.to_acc_bech32(), orders=derivative_orders
)
# compute order hashes
order_hashes = order_hash_manager.compute_order_hashes(
spot_orders=spot_orders, derivative_orders=derivative_orders, subaccount_index=1
)
print("computed spot order hashes", order_hashes.spot)
print("computed derivative order hashes", order_hashes.derivative)
# build tx 3
tx = (
Transaction()
.with_messages(spot_msg, deriv_msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
gas_price = GAS_PRICE
base_gas = 85000
gas_limit = base_gas + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"os"
"time"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
"github.com/google/uuid"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"github.com/shopspring/decimal"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
// initialize grpc client
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := chainclient.NewMarketsAssistantInitializedFromChain(ctx, exchangeClient)
if err != nil {
panic(err)
}
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
// prepare tx msg
defaultSubaccountID := chainClient.Subaccount(senderAddress, 1)
spotOrder := chainClient.CreateSpotOrder(
defaultSubaccountID,
&chainclient.SpotOrderData{
OrderType: exchangetypes.OrderType_BUY,
Quantity: decimal.NewFromFloat(2),
Price: decimal.NewFromFloat(22.55),
FeeRecipient: senderAddress.String(),
MarketId: "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
Cid: uuid.NewString(),
},
marketsAssistant,
)
derivativeOrder := chainClient.CreateDerivativeOrder(
defaultSubaccountID,
&chainclient.DerivativeOrderData{
OrderType: exchangetypes.OrderType_BUY,
Quantity: decimal.NewFromFloat(2),
Price: decimal.RequireFromString("31"),
Leverage: decimal.RequireFromString("2.5"),
FeeRecipient: senderAddress.String(),
MarketId: "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
Cid: uuid.NewString(),
},
marketsAssistant,
)
msg := new(exchangetypes.MsgBatchCreateSpotLimitOrders)
msg.Sender = senderAddress.String()
msg.Orders = []exchangetypes.SpotOrder{*spotOrder}
msg1 := new(exchangetypes.MsgBatchCreateDerivativeLimitOrders)
msg1.Sender = senderAddress.String()
msg1.Orders = []exchangetypes.DerivativeOrder{*derivativeOrder, *derivativeOrder}
// compute local order hashes
orderHashes, err := chainClient.ComputeOrderHashes(msg.Orders, msg1.Orders, defaultSubaccountID)
if err != nil {
fmt.Println(err)
}
fmt.Println("computed spot order hashes: ", orderHashes.Spot)
fmt.Println("computed derivative order hashes: ", orderHashes.Derivative)
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg, msg1)
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Response Parameters
Response Example:
computed spot order hashes ['0xa2d59cca00bade680a552f02deeb43464df21c73649191d64c6436313b311cba', '0xab78219e6c494373262a310d73660198c7a4c91196c0f6bb8808c81d8fb54a11']
computed derivative order hashes ['0x38d432c011f4a62c6b109615718b26332e7400a86f5e6f44e74a8833b7eed992', '0x66a921d83e6931513df9076c91a920e5e943837e2b836ad370b5cf53a1ed742c']
txhash: "604757CD9024FFF2DDCFEED6FC070E435AC09A829DB2E81AD4AD65B33E987A8B"
raw_log: "[]"
gas wanted: 196604
gas fee: 0.000098302 INJ
computed spot order hashes: [0x0103ca50d0d033e6b8528acf28a3beb3fd8bac20949fc1ba60a2da06c53ad94f]
computed derivative order hashes: [0x15334a7a0f1c2f98b9369f79b9a62a1f357d3e63b46a8895a4cec0ca375ddbbb 0xc26c8f74f56eade275e518f73597dd8954041bfbae3951ed4d7efeb0d060edbd]
DEBU[0001] broadcastTx with nonce 3488 fn=func1 src="client/chain/chain.go:598"
DEBU[0003] msg batch committed successfully at height 5212331 fn=func1 src="client/chain/chain.go:619" txHash=19D8D81BB1DF59889E00EAA600A01079BA719F00A4A43CCC1B56580A1BBD6455
DEBU[0003] nonce incremented to 3489 fn=func1 src="client/chain/chain.go:623"
DEBU[0003] gas wanted: 271044 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.000135522 INJ
Note on LocalOrderHashComputation for HFTs/API Traders
LocalOrderHashComputation
returns a locally computed transaction hash for spot and derivative orders, which is useful when the user needs the transaction hash faster than orders can be streamed through StreamOrdersHistory
(there is extra latency since the order must be included by a block, and the block must be indexed by the Indexer). While the hash can also be obtained through transaction simulation, the process adds a layer of latency and can only be used for one transaction per block (simulation relies on a nonce based on the state machine which does not change until the transaction is included in a block).
On Injective, subaccount nonces are used to calculate order hashes. The subaccount nonce is incremented with each order so that order hashes remain unique.
For strategies employing high frequency trading, order hashes should be calculated locally before transactions are broadcasted. This is possible as long as the subaccount nonce is cached/tracked locally instead of queried from the chain. Similarly, the account sequence (like nonce on Ethereum) should be cached if more than one transaction per block is desired. The LocalOrderHashComputation
implementation can be found here. Refer to the above API example for usage.
There are two caveats to be mindful of when taking this approach:
1. Gas must be manually calculated instead of fetched from simulation
- To avoid latency issues from simulation, it's best to completely omit simulation for fetching gas and order hash.
- To calculate gas, a constant value should be set for the base transaction object. The tx object consists of a constant set of attributes such as memo, sequence, etc., so gas should be the same as long as the amount of data being transmitted remains constant (i.e. gas may change if the memo size is very large). The gas can then be increased per order creation/cancellation.
- These constants can be found through simulating a transaction with a single order and a separate transaction with two orders, then solving the linear equations to obtain the base gas and the per-order gas amounts.
class GasLimitConstant:
base = 65e3
extra = 20e3
derivative_order = 45e3
derivative_cancel = 55e3
- An extra 20,000 buffer can be added to the gas calculation to ensure the transaction is not rejected during execution on the validator node. Transactions often require a bit more gas depending on the operations; for example, a post-only order could cross the order book and get cancelled, which would cost a different amount of gas than if that order was posted in the book as a limit order. See example on right:
- Note: In cosmos-sdk v0.46, a gas refund capability was added through the PostHandler functionality. In theory, this means that gas constants can be set much higher such that transactions never fail; however, because v0.46 was not compatible with CosmWasm during the last chain upgrade, the refund capability is not implemented on Injective. This may change in the future, but as of now, gas is paid in its entirety as set.
2. In the event a transaction fails, the account sequence and subaccount nonce must both be refreshed
- If the client receives a sequence mismatch error (code 32), a refresh in sequence and subaccount nonce will likely resolve the error.
res = await self.client.broadcast_tx_sync_mode(tx_raw_bytes)
if res.code == 32:
await client.fetch_account(address.to_acc_bech32())
- To refresh the cached account sequence, updated account data can be fetched using the client. See example on right, using the Python client:
- To refresh the cached subaccount nonce, the
OrderHashManager
can be reinitialized since the subaccount nonce is fetched from the chain during init.
- Chain Exchange for Spot
Includes all messages related to spot markets.
SpotMarkets
Retrieves a list of spot markets
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
spot_markets = await client.fetch_chain_spot_markets(
status="Active",
market_ids=["0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"],
)
print(spot_markets)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
status := "Active"
marketIds := []string{"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"}
res, err := chainClient.FetchChainSpotMarkets(ctx, status, marketIds)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
status | String | Market status | No |
market_ids | String Array | List of market IDs | No |
Response Parameters
Response Example:
{
"markets":[
{
"ticker":"INJ/USDT",
"baseDenom":"inj",
"quoteDenom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"makerFeeRate":"-100000000000000",
"takerFeeRate":"1000000000000000",
"relayerFeeShareRate":"400000000000000000",
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"status":"Active",
"minPriceTickSize":"1000",
"minQuantityTickSize":"1000000000000000000000000000000000"
}
]
}
Parameter | Type | Description |
---|---|---|
markets | SpotMarket Array | List of markets |
SpotMarket
Parameter | Type | Description |
---|---|---|
ticker | String | Name of the pair in format AAA/BBB, where AAA is base asset, BBB is quote asset |
base_denom | String | Coin denom used for the base asset |
quote_denom | String | Coin denom used for the quote asset |
maker_fee_rate | Decimal | Fee percentage makers pay when trading |
taker_fee_rate | Decimal | Fee percentage takers pay when trading |
relayer_fee_share_rate | Decimal | Percentage of the transaction fee shared with the relayer in a derivative market |
market_id | String | The market ID |
status | MarketStatus | Status of the market |
min_price_tick_size | Decimal | Minimum tick size that the price required for orders in the market |
min_quantity_tick_size | Decimal | Minimum tick size of the quantity required for orders in the market |
min_notional | Decimal | Minimum notional (in quote asset) required for orders in the market |
admin | String | Current market admin's address |
admin_permissions | Integer | Level of admin permissions (the permission number is a result of adding up all individual permissions numbers) |
MarketStatus
Code | Name |
---|---|
0 | Unspecified |
1 | Active |
2 | Paused |
3 | Demolished |
4 | Expired |
AdminPermission
Code | Name |
---|---|
1 | Ticker Permission |
2 | Min Price Tick Size Permission |
4 | Min Quantity Tick Size Permission |
8 | Min Notional Permission |
16 | Initial Margin Ratio Permission |
32 | Maintenance Margin Ratio Permission |
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
res, err := chainClient.FetchChainSpotMarket(ctx, marketId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The market ID | Yes |
Response Parameters
Response Example:
{
"market":{
"ticker":"INJ/USDT",
"baseDenom":"inj",
"quoteDenom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"makerFeeRate":"-100000000000000",
"takerFeeRate":"1000000000000000",
"relayerFeeShareRate":"400000000000000000",
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"status":"Active",
"minPriceTickSize":"1000",
"minQuantityTickSize":"1000000000000000000000000000000000"
}
}
Parameter | Type | Description |
---|---|---|
market | SpotMarket | Market information |
SpotMarket
Parameter | Type | Description |
---|---|---|
ticker | String | Name of the pair in format AAA/BBB, where AAA is base asset, BBB is quote asset |
base_denom | String | Coin denom used for the base asset |
quote_denom | String | Coin denom used for the quote asset |
maker_fee_rate | Decimal | Fee percentage makers pay when trading |
taker_fee_rate | Decimal | Fee percentage takers pay when trading |
relayer_fee_share_rate | Decimal | Percentage of the transaction fee shared with the relayer in a derivative market |
market_id | String | The market ID |
status | MarketStatus | Status of the market |
min_price_tick_size | Decimal | Minimum tick size that the price required for orders in the market |
min_quantity_tick_size | Decimal | Minimum tick size of the quantity required for orders in the market |
min_notional | Decimal | Minimum notional (in quote asset) required for orders in the market |
admin | String | Current market admin's address |
admin_permissions | Integer | Level of admin permissions (the permission number is a result of adding up all individual permissions numbers) |
MarketStatus
Code | Name |
---|---|
0 | Unspecified |
1 | Active |
2 | Paused |
3 | Demolished |
4 | Expired |
AdminPermission
Code | Name |
---|---|
1 | Ticker Permission |
2 | Min Price Tick Size Permission |
4 | Min Quantity Tick Size Permission |
8 | Min Notional Permission |
16 | Initial Margin Ratio Permission |
32 | Maintenance Margin Ratio Permission |
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
status := "Active"
marketIds := []string{"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"}
withMidPriceAndTob := true
res, err := chainClient.FetchChainFullSpotMarkets(ctx, status, marketIds, withMidPriceAndTob)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
status | String | Status of the market | No |
market_ids | String Array | List of market IDs | No |
with_mid_price_and_tob | Boolean | Flag to activate/deactivate the inclusion of the markets mid price and top of the book buy and sell orders | No |
Response Parameters
Response Example:
{
"markets":[
{
"market":{
"ticker":"INJ/USDT",
"baseDenom":"inj",
"quoteDenom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"makerFeeRate":"-100000000000000",
"takerFeeRate":"1000000000000000",
"relayerFeeShareRate":"400000000000000000",
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"status":"Active",
"minPriceTickSize":"1000",
"minQuantityTickSize":"1000000000000000000000000000000000"
},
"midPriceAndTob":{
"midPrice":"42494500",
"bestBuyPrice":"42490000",
"bestSellPrice":"42499000"
}
}
]
}
Parameter | Type | Description |
---|---|---|
markets | FullSpotMarket Array | Markets information |
FullSpotMarket
Parameter | Type | Description |
---|---|---|
market | SpotMarket | Market basic information |
mid_price_and_tob | MidPriceAndTOB | The mid price for this market and the best ask and bid orders |
SpotMarket
Parameter | Type | Description |
---|---|---|
ticker | String | Name of the pair in format AAA/BBB, where AAA is base asset, BBB is quote asset |
base_denom | String | Coin denom used for the base asset |
quote_denom | String | Coin denom used for the quote asset |
maker_fee_rate | Decimal | Fee percentage makers pay when trading |
taker_fee_rate | Decimal | Fee percentage takers pay when trading |
relayer_fee_share_rate | Decimal | Percentage of the transaction fee shared with the relayer in a derivative market |
market_id | String | The market ID |
status | MarketStatus | Status of the market |
min_price_tick_size | Decimal | Minimum tick size that the price required for orders in the market |
min_quantity_tick_size | Decimal | Minimum tick size of the quantity required for orders in the market |
min_notional | Decimal | Minimum notional (in quote asset) required for orders in the market |
admin | String | Current market admin's address |
admin_permissions | Integer | Level of admin permissions (the permission number is a result of adding up all individual permissions numbers) |
MarketStatus
Code | Name |
---|---|
0 | Unspecified |
1 | Active |
2 | Paused |
3 | Demolished |
4 | Expired |
MidPriceAndTOB
Parameter | Type | Description |
---|---|---|
mid_price | Decimal | Market's mid price |
best_buy_price | Decimal | Market's best buy price |
best_sell_price | Decimal | Market's best sell price |
AdminPermission
Code | Name |
---|---|
1 | Ticker Permission |
2 | Min Price Tick Size Permission |
4 | Min Quantity Tick Size Permission |
8 | Min Notional Permission |
16 | Initial Margin Ratio Permission |
32 | Maintenance Margin Ratio Permission |
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
withMidPriceAndTob := true
res, err := chainClient.FetchChainFullSpotMarket(ctx, marketId, withMidPriceAndTob)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | Market ID to request for | Yes |
with_mid_price_and_tob | Boolean | Flag to activate/deactivate the inclusion of the markets mid price and top of the book buy and sell orders | No |
Response Parameters
Response Example:
{
"market":{
"market":{
"ticker":"INJ/USDT",
"baseDenom":"inj",
"quoteDenom":"peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5",
"makerFeeRate":"-100000000000000",
"takerFeeRate":"1000000000000000",
"relayerFeeShareRate":"400000000000000000",
"marketId":"0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
"status":"Active",
"minPriceTickSize":"1000",
"minQuantityTickSize":"1000000000000000000000000000000000"
},
"midPriceAndTob":{
"midPrice":"42473500",
"bestBuyPrice":"42336000",
"bestSellPrice":"42611000"
}
}
}
Parameter | Type | Description |
---|---|---|
market | FullSpotMarket | Markets information |
FullSpotMarket
Parameter | Type | Description |
---|---|---|
market | SpotMarket | Market basic information |
mid_price_and_tob | MidPriceAndTOB | The mid price for this market and the best ask and bid orders |
SpotMarket
Parameter | Type | Description |
---|---|---|
ticker | String | Name of the pair in format AAA/BBB, where AAA is base asset, BBB is quote asset |
base_denom | String | Coin denom used for the base asset |
quote_denom | String | Coin denom used for the quote asset |
maker_fee_rate | Decimal | Fee percentage makers pay when trading |
taker_fee_rate | Decimal | Fee percentage takers pay when trading |
relayer_fee_share_rate | Decimal | Percentage of the transaction fee shared with the relayer in a derivative market |
market_id | String | The market ID |
status | MarketStatus | Status of the market |
min_price_tick_size | Decimal | Minimum tick size that the price required for orders in the market |
min_quantity_tick_size | Decimal | Minimum tick size of the quantity required for orders in the market |
min_notional | Decimal | Minimum notional (in quote asset) required for orders in the market |
admin | String | Current market admin's address |
admin_permissions | Integer | Level of admin permissions (the permission number is a result of adding up all individual permissions numbers) |
MarketStatus
Code | Name |
---|---|
0 | Unspecified |
1 | Active |
2 | Paused |
3 | Demolished |
4 | Expired |
MidPriceAndTOB
Parameter | Type | Description |
---|---|---|
mid_price | Decimal | Market's mid price |
best_buy_price | Decimal | Market's best buy price |
best_sell_price | Decimal | Market's best sell price |
AdminPermission
Code | Name |
---|---|
1 | Ticker Permission |
2 | Min Price Tick Size Permission |
4 | Min Quantity Tick Size Permission |
8 | Min Notional Permission |
16 | Initial Margin Ratio Permission |
32 | Maintenance Margin Ratio Permission |
package main
import (
"context"
"encoding/json"
"fmt"
"cosmossdk.io/math"
"os"
"github.com/InjectiveLabs/sdk-go/chain/exchange/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
limit := uint64(2)
orderSide := types.OrderSide_Buy
limitCumulativeNotional := math.LegacyDec{}
limitCumulativeQuantity := math.LegacyDec{}
res, err := chainClient.FetchChainSpotOrderbook(ctx, marketId, limit, orderSide, limitCumulativeNotional, limitCumulativeQuantity)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | Market ID to request for | Yes |
limit | Integer | Max number of order book entries to return per side | No |
order_side | OrderSide | Specifies the side of the order book to return entries from | No |
limit_cumulative_notional | Decimal | Limit the number of entries to return per side based on the cumulative notional | No |
limit_cumulative_quantity | Decimal | Limit the number of entries to return per side based on the cumulative quantity | No |
OrderSide
Code | Name |
---|---|
0 | Side_Unspecified |
1 | Buy |
2 | Sell |
Response Parameters
Response Example:
{
"buysPriceLevel":[
{
"p":"43260000",
"q":"142000000000000000000000000000000000000"
},
{
"p":"43208000",
"q":"25554192000000000000000000000000000000000"
}
],
"sellsPriceLevel":[
]
}
Parameter | Type | Description |
---|---|---|
buys_price_level | Level Array | Bid side entries |
sells_price_level | Level Array | Ask side entries |
Level
Parameter | Type | Description |
---|---|---|
p | Decimal | Price |
q | Decimal | Quantity |
TraderSpotOrders
Retrieves a trader's spot orders
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
orders = await client.fetch_chain_trader_spot_orders(
market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
subaccount_id=subaccount_id,
)
print(orders)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
subaccountId := chainClient.Subaccount(senderAddress, 0)
res, err := chainClient.FetchChainTraderSpotOrders(ctx, marketId, subaccountId.Hex())
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | Market ID to request for | Yes |
subaccount_id | String | Trader's subaccount ID | Yes |
Response Parameters
Response Example:
{
"orders":[
{
"price":"7523000",
"quantity":"10000000000000000000000000000000000",
"fillable":"10000000000000000000000000000000000",
"isBuy":true,
"orderHash":"0xee405938e1924d20cce9d91e47476af0b40774843906b653ba4c439654fb9a8b"
},
{
"price":"3000000",
"quantity":"55000000000000000000000000000000000000",
"fillable":"55000000000000000000000000000000000000",
"isBuy":true,
"orderHash":"0x57a01cd26f1e2080860af3264e865d7c9c034a701e30946d01c1dc7a303cf2c1"
},
{
"price":"3000000",
"quantity":"55000000000000000000000000000000000000",
"fillable":"55000000000000000000000000000000000000",
"isBuy":true,
"orderHash":"0x079d65de81f03229d0fac69fb8ee0bfe0f043783099ad4cb28f1b30115736a02"
},
{
"price":"300000000",
"quantity":"55000000000000000000000000000000000000",
"fillable":"22458000000000000000000000000000000000",
"orderHash":"0x6e53d070e13be855d230de48849017b2390c2294afc3681bd3624370d153a7cc",
"isBuy":false
}
]
}
Parameter | Type | Description |
---|---|---|
orders | TrimmedSpotLimitOrder Array | Orders info |
TrimmedSpotLimitOrder
Parameter | Type | Description |
---|---|---|
price | Decimal | Order price |
quantity | Decimal | Order quantity |
fillable | Decimal | The remaining fillable amount of the order |
is_buy | Boolean | True if the order is a buy order |
order_hash | String | The order hash |
cid | String | The client order ID provided by the creator |
AccountAddressSpotOrders
Retrieves all account address spot orders
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
orders = await client.fetch_chain_account_address_spot_orders(
market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
account_address=address.to_acc_bech32(),
)
print(orders)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
res, err := chainClient.FetchChainAccountAddressSpotOrders(ctx, marketId, senderAddress.String())
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | Market ID to request for | Yes |
account_address | String | Trader's account address | Yes |
Response Parameters
Response Example:
{
"orders":[
{
"price":"3000000",
"quantity":"55000000000000000000000000000000000000",
"fillable":"55000000000000000000000000000000000000",
"isBuy":true,
"orderHash":"0xda7a606d542962da77f13b0f8373c24ce4511e421de8e4602a3e5f2b85b7623c"
},
{
"price":"3000000",
"quantity":"55000000000000000000000000000000000000",
"fillable":"55000000000000000000000000000000000000",
"isBuy":true,
"orderHash":"0x9c7c77da10b73d63c72875a175c4a7cb7313dbbeb9a3380bc1bf930cce883b1b"
},
{
"price":"7523000",
"quantity":"10000000000000000000000000000000000",
"fillable":"10000000000000000000000000000000000",
"isBuy":true,
"orderHash":"0xee405938e1924d20cce9d91e47476af0b40774843906b653ba4c439654fb9a8b"
},
{
"price":"3000000",
"quantity":"55000000000000000000000000000000000000",
"fillable":"55000000000000000000000000000000000000",
"isBuy":true,
"orderHash":"0x57a01cd26f1e2080860af3264e865d7c9c034a701e30946d01c1dc7a303cf2c1"
},
{
"price":"3000000",
"quantity":"55000000000000000000000000000000000000",
"fillable":"55000000000000000000000000000000000000",
"isBuy":true,
"orderHash":"0x079d65de81f03229d0fac69fb8ee0bfe0f043783099ad4cb28f1b30115736a02"
},
{
"price":"300000000",
"quantity":"55000000000000000000000000000000000000",
"fillable":"22458000000000000000000000000000000000",
"orderHash":"0x6e53d070e13be855d230de48849017b2390c2294afc3681bd3624370d153a7cc",
"isBuy":false
},
{
"price":"300000000",
"quantity":"55000000000000000000000000000000000000",
"fillable":"55000000000000000000000000000000000000",
"orderHash":"0xcb38413ecf5517faac19a4753726813b68374525d70e8ca3058bb20504a98e10",
"isBuy":false
}
]
}
Parameter | Type | Description |
---|---|---|
orders | TrimmedSpotLimitOrder Array | Orders info |
TrimmedSpotLimitOrder
Parameter | Type | Description |
---|---|---|
price | Decimal | Order price |
quantity | Decimal | Order quantity |
fillable | Decimal | The remaining fillable amount of the order |
is_buy | Boolean | True if the order is a buy order |
order_hash | String | The order hash |
cid | String | The client order ID provided by the creator |
SpotOrdersByHashes
Retrieves spot orders corresponding to specified order hashes for a given subaccount ID and market ID
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
orders = await client.fetch_chain_spot_orders_by_hashes(
market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
subaccount_id=subaccount_id,
order_hashes=["0x57a01cd26f1e2080860af3264e865d7c9c034a701e30946d01c1dc7a303cf2c1"],
)
print(orders)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
subaccountId := chainClient.Subaccount(senderAddress, 0)
orderHashes := []string{"0x57a01cd26f1e2080860af3264e865d7c9c034a701e30946d01c1dc7a303cf2c1"}
res, err := chainClient.FetchChainSpotOrdersByHashes(ctx, marketId, subaccountId.Hex(), orderHashes)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | Market ID to request for | Yes |
subaccount_id | String | Trader's subaccount ID | Yes |
order_hashes | String Array | List of order hashes to retrieve information for | Yes |
Response Parameters
Response Example:
{
"orders":[
{
"price":"3000000",
"quantity":"55000000000000000000000000000000000000",
"fillable":"55000000000000000000000000000000000000",
"isBuy":true,
"orderHash":"0x57a01cd26f1e2080860af3264e865d7c9c034a701e30946d01c1dc7a303cf2c1"
}
]
}
Parameter | Type | Description |
---|---|---|
orders | TrimmedSpotLimitOrder Array | Orders info |
TrimmedSpotLimitOrder
Parameter | Type | Description |
---|---|---|
price | Decimal | Order price |
quantity | Decimal | Order quantity |
fillable | Decimal | The remaining fillable amount of the order |
is_buy | Boolean | True if the order is a buy order |
order_hash | String | The order hash |
cid | String | The client order ID provided by the creator |
TraderSpotTransientOrders
Retrieves a trader's transient spot orders
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import PrivateKey
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
orders = await client.fetch_chain_trader_spot_transient_orders(
market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
subaccount_id=subaccount_id,
)
print(orders)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
subaccountId := chainClient.Subaccount(senderAddress, 0)
res, err := chainClient.FetchChainTraderSpotTransientOrders(ctx, marketId, subaccountId.Hex())
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | Market ID to request for | Yes |
subaccount_id | String | Trader's subaccount ID | Yes |
Response Parameters
Response Example:
{
"orders":[
]
}
Parameter | Type | Description |
---|---|---|
orders | TrimmedSpotLimitOrder Array | Orders info |
TrimmedSpotLimitOrder
Parameter | Type | Description |
---|---|---|
price | Decimal | Order price |
quantity | Decimal | Order quantity |
fillable | Decimal | The remaining fillable amount of the order |
is_buy | Boolean | True if the order is a buy order |
order_hash | String | The order hash |
cid | String | The client order ID provided by the creator |
SpotMidPriceAndTOB
Retrieves a spot market's mid-price
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
prices = await client.fetch_spot_mid_price_and_tob(
market_id="0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
)
print(prices)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
marketId := "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
res, err := chainClient.FetchSpotMidPriceAndTOB(ctx, marketId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | Market ID to request for | Yes |
Response Parameters
Response Example:
{
"midPrice":"44723500",
"bestBuyPrice":"44538000",
"bestSellPrice":"44909000"
}
Parameter | Type | Description |
---|---|---|
mid_price | Decimal | Market's mid price |
best_buy_price | Decimal | Market's bet bid price |
best_sell_price | Decimal | Market's bet ask price |
MsgInstantSpotMarketLaunch
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
from decimal import Decimal
import dotenv
from pyinjective.async_client import AsyncClient
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
await client.initialize_tokens_from_chain_denoms()
composer = await client.composer()
await client.sync_timeout_height()
message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
network=network,
private_key=configured_private_key,
)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
# prepare tx msg
message = composer.msg_instant_spot_market_launch(
sender=address.to_acc_bech32(),
ticker="INJ/USDC",
base_denom="INJ",
quote_denom="USDC",
min_price_tick_size=Decimal("0.001"),
min_quantity_tick_size=Decimal("0.01"),
min_notional=Decimal("1"),
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"cosmossdk.io/math"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := chainclient.NewMarketsAssistantInitializedFromChain(ctx, exchangeClient)
if err != nil {
panic(err)
}
baseToken := marketsAssistant.AllTokens()["INJ"]
quoteToken := marketsAssistant.AllTokens()["USDC"]
minPriceTickSize := math.LegacyMustNewDecFromStr("0.01")
minQuantityTickSize := math.LegacyMustNewDecFromStr("0.001")
minNotional := math.LegacyMustNewDecFromStr("1")
chainMinPriceTickSize := minPriceTickSize.Mul(math.LegacyNewDecFromIntWithPrec(math.NewInt(1), int64(quoteToken.Decimals)))
chainMinPriceTickSize = chainMinPriceTickSize.Quo(math.LegacyNewDecFromIntWithPrec(math.NewInt(1), int64(baseToken.Decimals)))
chainMinQuantityTickSize := minQuantityTickSize.Mul(math.LegacyNewDecFromIntWithPrec(math.NewInt(1), int64(baseToken.Decimals)))
chainMinNotional := minNotional.Mul(math.LegacyNewDecFromIntWithPrec(math.NewInt(1), int64(quoteToken.Decimals)))
msg := &exchangetypes.MsgInstantSpotMarketLaunch{
Sender: senderAddress.String(),
Ticker: "INJ/USDC",
BaseDenom: baseToken.Denom,
QuoteDenom: quoteToken.Denom,
MinPriceTickSize: chainMinPriceTickSize,
MinQuantityTickSize: chainMinQuantityTickSize,
MinNotional: chainMinNotional,
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.AsyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The market launch requestor address | Yes |
ticker | String | Ticker for the spot market | Yes |
base_denom | String | Base tocken denom | Yes |
quote_denom | String | Quote tocken denom | Yes |
min_price_tick_size | Decimal | Defines the minimum tick size of the order's price | Yes |
min_quantity_tick_size | Decimal | Defines the minimum tick size of the order's quantity | Yes |
min_notional | Decimal | Defines the minimum notional (in quote asset) required for orders in the market | Yes |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgCreateSpotLimitOrder
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import uuid
from decimal import Decimal
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
# prepare trade info
market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
cid = str(uuid.uuid4())
# prepare tx msg
msg = composer.msg_create_spot_limit_order(
sender=address.to_acc_bech32(),
market_id=market_id,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal("7.523"),
quantity=Decimal("0.01"),
order_type="BUY",
cid=cid,
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
sim_res_msg = sim_res["result"]["msgResponses"]
print("---Simulation Response---")
print(sim_res_msg)
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print("---Transaction Response---")
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
print(f"\n\ncid: {cid}")
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"os"
"time"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
"github.com/google/uuid"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
"github.com/shopspring/decimal"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("mainnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
fmt.Println(err)
return
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := chainclient.NewMarketsAssistantInitializedFromChain(ctx, exchangeClient)
if err != nil {
panic(err)
}
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
defaultSubaccountID := chainClient.DefaultSubaccount(senderAddress)
marketId := "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"
amount := decimal.NewFromFloat(2)
price := decimal.NewFromFloat(22.55)
order := chainClient.CreateSpotOrder(
defaultSubaccountID,
&chainclient.SpotOrderData{
OrderType: exchangetypes.OrderType_BUY, //BUY SELL BUY_PO SELL_PO
Quantity: amount,
Price: price,
FeeRecipient: senderAddress.String(),
MarketId: marketId,
Cid: uuid.NewString(),
},
marketsAssistant,
)
msg := new(exchangetypes.MsgCreateSpotLimitOrder)
msg.Sender = senderAddress.String()
msg.Order = exchangetypes.SpotOrder(*order)
simRes, err := chainClient.SimulateMsg(clientCtx, msg)
if err != nil {
fmt.Println(err)
return
}
msgCreateSpotLimitOrderResponse := exchangetypes.MsgCreateSpotLimitOrderResponse{}
err = msgCreateSpotLimitOrderResponse.Unmarshal(simRes.Result.MsgResponses[0].Value)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("simulated order hash: ", msgCreateSpotLimitOrderResponse.OrderHash)
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
return
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The message sender's address | Yes |
order | SpotOrder | Order's parameters | Yes |
SpotOrder
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The unique ID of the market | Yes |
order_info | OrderInfo | Order's information | Yes |
order_type | OrderType | The order type | Yes |
trigger_price | Decimal | The trigger price used by stop/take orders | No |
OrderInfo
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | Subaccount ID that created the order | Yes |
fee_recipient | String | Address that will receive fees for the order | No |
price | Decimal | Price of the order | Yes |
quantity | Decimal | Quantity of the order | Yes |
cid | String | Client order ID. An optional identifier for the order set by the creator | No |
OrderType
Code | Name |
---|---|
0 | UNSPECIFIED |
1 | BUY |
2 | SELL |
3 | STOP_BUY |
4 | STOP_SELL |
5 | TAKE_BUY |
6 | TAKE_SELL |
7 | BUY_PO |
8 | SELL_PO |
9 | BUY_ATOMIC |
10 | SELL_ATOMIC |
Response Parameters
Response Example:
---Simulation Response---
[order_hash: "0xee49d8060469fd6824d65a0f7099b02fe23fcb7302dd21800905cf0cd285bd82"
]
---Transaction Response---
txhash: "C56626C351E66EBAF085E84DF6422E84043DD6A1B81316367FE3976D762000FE"
raw_log: "[]"
gas wanted: 104011
gas fee: 0.0000520055 INJ
simulated order hash: 0x73d8e846abdfffd3d42ff2c190a650829a5af52b3337287319b4f2c54eb7ce80
DEBU[0001] broadcastTx with nonce 3492 fn=func1 src="client/chain/chain.go:598"
DEBU[0003] msg batch committed successfully at height 5212740 fn=func1 src="client/chain/chain.go:619" txHash=B62F7CC6DE3297EC4376C239AF93DB33193A89FA99FAC27C9E25AD5579B9BAD7
DEBU[0003] nonce incremented to 3493 fn=func1 src="client/chain/chain.go:623"
DEBU[0003] gas wanted: 129912 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.000064956 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgCreateSpotMarketOrder
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import uuid
from decimal import Decimal
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
# prepare trade info
market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
# prepare tx msg
msg = composer.msg_create_spot_market_order(
market_id=market_id,
sender=address.to_acc_bech32(),
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal("10.522"),
quantity=Decimal("0.01"),
order_type="BUY",
cid=str(uuid.uuid4()),
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
sim_res_msg = sim_res["result"]["msgResponses"]
print("---Simulation Response---")
print(sim_res_msg)
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print("---Transaction Response---")
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"os"
"time"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
"github.com/google/uuid"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
"github.com/shopspring/decimal"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := chainclient.NewMarketsAssistantInitializedFromChain(ctx, exchangeClient)
if err != nil {
panic(err)
}
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
defaultSubaccountID := chainClient.DefaultSubaccount(senderAddress)
marketId := "0x0511ddc4e6586f3bfe1acb2dd905f8b8a82c97e1edaef654b12ca7e6031ca0fa"
amount := decimal.NewFromFloat(0.1)
price := decimal.NewFromFloat(22)
order := chainClient.CreateSpotOrder(
defaultSubaccountID,
&chainclient.SpotOrderData{
OrderType: exchangetypes.OrderType_SELL, //BUY SELL
Quantity: amount,
Price: price,
FeeRecipient: senderAddress.String(),
MarketId: marketId,
Cid: uuid.NewString(),
},
marketsAssistant,
)
msg := new(exchangetypes.MsgCreateSpotMarketOrder)
msg.Sender = senderAddress.String()
msg.Order = exchangetypes.SpotOrder(*order)
simRes, err := chainClient.SimulateMsg(clientCtx, msg)
if err != nil {
fmt.Println(err)
return
}
msgCreateSpotMarketOrderResponse := exchangetypes.MsgCreateSpotMarketOrderResponse{}
err = msgCreateSpotMarketOrderResponse.Unmarshal(simRes.Result.MsgResponses[0].Value)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("simulated order hash", msgCreateSpotMarketOrderResponse.OrderHash)
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
return
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The message sender's address | Yes |
order | SpotOrder | Order's parameters | Yes |
SpotOrder
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The unique ID of the market | Yes |
order_info | OrderInfo | Order's information | Yes |
order_type | OrderType | The order type | Yes |
trigger_price | Decimal | The trigger price used by stop/take orders | No |
OrderInfo
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | Subaccount ID that created the order | Yes |
fee_recipient | String | Address that will receive fees for the order | No |
price | Decimal | Price of the order | Yes |
quantity | Decimal | Quantity of the order | Yes |
cid | String | Client order ID. An optional identifier for the order set by the creator | No |
OrderType
Code | Name |
---|---|
0 | UNSPECIFIED |
1 | BUY |
2 | SELL |
3 | STOP_BUY |
4 | STOP_SELL |
5 | TAKE_BUY |
6 | TAKE_SELL |
7 | BUY_PO |
8 | SELL_PO |
9 | BUY_ATOMIC |
10 | SELL_ATOMIC |
Response Parameters
Response Example:
---Simulation Response---
[order_hash: "0x7c6552c5f5ffd3adc2cb5fe9f2bc1eed4741952f698c84e9dc73c6f45b6af8b4"
]
---Transaction Response---
txhash: "9BBD3666A052FA11AF572F4D788C3C7D8B44F60CF0F0375EE40B84DA2408114A"
raw_log: "[]"
gas wanted: 104352
gas fee: 0.000052176 INJ
simulated order hash 0xfa9038ef2e59035a8f3368438aa4533fce90d8bbd3bee6c37e4cc06e8d1d0e6a
DEBU[0001] broadcastTx with nonce 3493 fn=func1 src="client/chain/chain.go:598"
DEBU[0004] msg batch committed successfully at height 5212834 fn=func1 src="client/chain/chain.go:619" txHash=14ABC252192D7286429730F9A29AB1BA67608B5EA7ACD7AD4D8F174C9B3852B3
DEBU[0004] nonce incremented to 3494 fn=func1 src="client/chain/chain.go:623"
DEBU[0004] gas wanted: 130596 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.000065298 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgCancelSpotOrder
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
# prepare trade info
market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
order_hash = "0x52888d397d5ae821869c8acde5823dfd8018802d2ef642d3aa639e5308173fcf"
# prepare tx msg
msg = composer.msg_cancel_spot_order(
sender=address.to_acc_bech32(), market_id=market_id, subaccount_id=subaccount_id, order_hash=order_hash
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"fmt"
"os"
"time"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
msg := &exchangetypes.MsgCancelSpotOrder{
Sender: senderAddress.String(),
MarketId: "0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0",
SubaccountId: "0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
OrderHash: "0xc1dd07efb7cf3a90c3d09da958fa22d96a5787eba3dbec56b63902c482accbd4",
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The message sender's address | Yes |
market_id | String | The unique ID of the order's market | Yes |
subaccount_id | String | The subaccount ID the order belongs to | Yes |
order_hash | String | The order hash (either order_hash or cid have to be provided) | No |
cid | String | The client order ID provided by the creator (either order_hash or cid have to be provided) | No |
Response Parameters
Response Example:
txhash: "3ABF365B8D90D44749AFF74FC510D792581202F98ABB406219B72E71315A64D4"
raw_log: "[]"
gas wanted: 102720
gas fee: 0.00005136 INJ
DEBU[0001] broadcastTx with nonce 3494 fn=func1 src="client/chain/chain.go:598"
DEBU[0002] msg batch committed successfully at height 5212920 fn=func1 src="client/chain/chain.go:619" txHash=14C2CB0592C5E950587D2041E97E337452A28F2A11220CC3E66624E5BAA73245
DEBU[0002] nonce incremented to 3495 fn=func1 src="client/chain/chain.go:623"
DEBU[0002] gas wanted: 127363 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.0000636815 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgBatchUpdateOrders
MsgBatchUpdateOrders allows for the atomic cancellation and creation of spot and derivative limit orders, along with a new order cancellation mode. Upon execution, order cancellations (if any) occur first, followed by order creations (if any).
Users can cancel all limit orders in a given spot or derivative market for a given subaccountID by specifying the associated marketID in the SpotMarketIdsToCancelAll and DerivativeMarketIdsToCancelAll. Users can also cancel individual limit orders in SpotOrdersToCancel or DerivativeOrdersToCancel, but must ensure that marketIDs in these individual order cancellations are not already provided in the SpotMarketIdsToCancelAll or DerivativeMarketIdsToCancelAll.
Further note that if no marketIDs are provided in the SpotMarketIdsToCancelAll or DerivativeMarketIdsToCancelAll, then the SubaccountID in the Msg should be left empty.
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import uuid
from decimal import Decimal
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
# prepare trade info
fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
derivative_market_id_create = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
spot_market_id_create = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
derivative_market_id_cancel = "0xd5e4b12b19ecf176e4e14b42944731c27677819d2ed93be4104ad7025529c7ff"
derivative_market_id_cancel_2 = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
spot_market_id_cancel = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
spot_market_id_cancel_2 = "0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0"
derivative_orders_to_cancel = [
composer.order_data(
market_id=derivative_market_id_cancel,
subaccount_id=subaccount_id,
order_hash="0x48690013c382d5dbaff9989db04629a16a5818d7524e027d517ccc89fd068103",
),
composer.order_data(
market_id=derivative_market_id_cancel_2,
subaccount_id=subaccount_id,
order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5",
),
]
spot_orders_to_cancel = [
composer.order_data(
market_id=spot_market_id_cancel,
subaccount_id=subaccount_id,
cid="0e5c3ad5-2cc4-4a2a-bbe5-b12697739163",
),
composer.order_data(
market_id=spot_market_id_cancel_2,
subaccount_id=subaccount_id,
order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2",
),
]
derivative_orders_to_create = [
composer.derivative_order(
market_id=derivative_market_id_create,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal(25000),
quantity=Decimal(0.1),
margin=composer.calculate_margin(
quantity=Decimal(0.1), price=Decimal(25000), leverage=Decimal(1), is_reduce_only=False
),
order_type="BUY",
cid=str(uuid.uuid4()),
),
composer.derivative_order(
market_id=derivative_market_id_create,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal(50000),
quantity=Decimal(0.01),
margin=composer.calculate_margin(
quantity=Decimal(0.01), price=Decimal(50000), leverage=Decimal(1), is_reduce_only=False
),
order_type="SELL",
cid=str(uuid.uuid4()),
),
]
spot_orders_to_create = [
composer.spot_order(
market_id=spot_market_id_create,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal("3"),
quantity=Decimal("55"),
order_type="BUY",
cid=str(uuid.uuid4()),
),
composer.spot_order(
market_id=spot_market_id_create,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal("300"),
quantity=Decimal("55"),
order_type="SELL",
cid=str(uuid.uuid4()),
),
]
# prepare tx msg
msg = composer.msg_batch_update_orders(
sender=address.to_acc_bech32(),
derivative_orders_to_create=derivative_orders_to_create,
spot_orders_to_create=spot_orders_to_create,
derivative_orders_to_cancel=derivative_orders_to_cancel,
spot_orders_to_cancel=spot_orders_to_cancel,
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
sim_res_msg = sim_res["result"]["msgResponses"]
print("---Simulation Response---")
print(sim_res_msg)
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print("---Transaction Response---")
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"os"
"time"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
"github.com/google/uuid"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
"github.com/shopspring/decimal"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
fmt.Println(err)
return
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := chainclient.NewMarketsAssistantInitializedFromChain(ctx, exchangeClient)
if err != nil {
panic(err)
}
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
fmt.Println(err)
return
}
defaultSubaccountID := chainClient.DefaultSubaccount(senderAddress)
smarketId := "0x0511ddc4e6586f3bfe1acb2dd905f8b8a82c97e1edaef654b12ca7e6031ca0fa"
samount := decimal.NewFromFloat(2)
sprice := decimal.NewFromFloat(22.5)
smarketIds := []string{"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"}
spot_order := chainClient.CreateSpotOrder(
defaultSubaccountID,
&chainclient.SpotOrderData{
OrderType: exchangetypes.OrderType_BUY, //BUY SELL BUY_PO SELL_PO
Quantity: samount,
Price: sprice,
FeeRecipient: senderAddress.String(),
MarketId: smarketId,
Cid: uuid.NewString(),
},
marketsAssistant,
)
dmarketId := "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"
damount := decimal.NewFromFloat(0.01)
dprice := decimal.RequireFromString("31000") //31,000
dleverage := decimal.RequireFromString("2")
dmarketIds := []string{"0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"}
derivative_order := chainClient.CreateDerivativeOrder(
defaultSubaccountID,
&chainclient.DerivativeOrderData{
OrderType: exchangetypes.OrderType_BUY, //BUY SELL BUY_PO SELL_PO
Quantity: damount,
Price: dprice,
Leverage: dleverage,
FeeRecipient: senderAddress.String(),
MarketId: dmarketId,
IsReduceOnly: false,
Cid: uuid.NewString(),
},
marketsAssistant,
)
msg := new(exchangetypes.MsgBatchUpdateOrders)
msg.Sender = senderAddress.String()
msg.SubaccountId = defaultSubaccountID.Hex()
msg.SpotOrdersToCreate = []*exchangetypes.SpotOrder{spot_order}
msg.DerivativeOrdersToCreate = []*exchangetypes.DerivativeOrder{derivative_order}
msg.SpotMarketIdsToCancelAll = smarketIds
msg.DerivativeMarketIdsToCancelAll = dmarketIds
simRes, err := chainClient.SimulateMsg(clientCtx, msg)
if err != nil {
fmt.Println(err)
return
}
MsgBatchUpdateOrdersResponse := exchangetypes.MsgBatchUpdateOrdersResponse{}
MsgBatchUpdateOrdersResponse.Unmarshal(simRes.Result.MsgResponses[0].Value)
fmt.Println("simulated spot order hashes", MsgBatchUpdateOrdersResponse.SpotOrderHashes)
fmt.Println("simulated derivative order hashes", MsgBatchUpdateOrdersResponse.DerivativeOrderHashes)
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
return
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The message sender's address | Yes |
subaccount_id | String | The subaccount ID is only used for the spot_market_ids_to_cancel_all and derivative_market_ids_to_cancel_all | No |
spot_market_ids_to_cancel_all | String Array | List of unique market IDs to cancel all subaccount_id orders | No |
derivative_market_ids_to_cancel_all | String Array | List of unique market IDs to cancel all subaccount_id orders | No |
spot_orders_to_cancel | OrderData Array | List of spot orders to be cancelled | No |
derivative_orders_to_cancel | OrderData Array | List of derivative orders to be cancelled | No |
spot_orders_to_create | SpotOrder Array | List of spot orders to be created | No |
derivative_orders_to_create | DerivativeOrder Array | List of derivative orders to be created | No |
binary_options_orders_to_cancel | OrderData Array | List of binary options orders to be cancelled | No |
binary_options_market_ids_to_cancel_all | String Array | List of unique market IDs to cancel all subaccount_id orders | No |
binary_options_orders_to_create | DerivativeOrder Array | List of binary options orders to be created | No |
OrderData
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The order's market ID | Yes |
subaccount_id | String | Subaccount ID that created the order | Yes |
order_hash | String | The order hash (either the order_hash or the cid should be provided) | No |
order_mask | OrderMask | The order mask that specifies the order type | No |
cid | String | The order's client order ID (either the order_hash or the cid should be provided) | No |
SpotOrder
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The unique ID of the market | Yes |
order_info | OrderInfo | Order's information | Yes |
order_type | OrderType | The order type | Yes |
trigger_price | Decimal | The trigger price used by stop/take orders | No |
DerivativeOrder
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The unique ID of the market | Yes |
order_info | OrderInfo | Order's information | Yes |
order_type | OrderType | The order type | Yes |
margin | Decimal | The margin amount used by the order | Yes |
trigger_price | Decimal | The trigger price used by stop/take orders | No |
OrderMask
Code | Name |
---|---|
0 | OrderMask_UNUSED |
1 | OrderMask_ANY |
2 | OrderMask_REGULAR |
4 | OrderMask_CONDITIONAL |
8 | OrderMask_BUY_OR_HIGHER |
16 | OrderMask_SELL_OR_LOWER |
32 | OrderMask_MARKET |
64 | OrderMask_LIMIT |
OrderInfo
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | Subaccount ID that created the order | Yes |
fee_recipient | String | Address that will receive fees for the order | No |
price | Decimal | Price of the order | Yes |
quantity | Decimal | Quantity of the order | Yes |
cid | String | Client order ID. An optional identifier for the order set by the creator | No |
OrderType
Code | Name |
---|---|
0 | UNSPECIFIED |
1 | BUY |
2 | SELL |
3 | STOP_BUY |
4 | STOP_SELL |
5 | TAKE_BUY |
6 | TAKE_SELL |
7 | BUY_PO |
8 | SELL_PO |
9 | BUY_ATOMIC |
10 | SELL_ATOMIC |
Response Parameters
Response Example:
---Simulation Response---
[spot_cancel_success: false
spot_cancel_success: false
derivative_cancel_success: false
derivative_cancel_success: false
spot_order_hashes: "0x3f5b5de6ec72b250c58e0a83408dbc1990cee369999036e3469e19b80fa9002e"
spot_order_hashes: "0x7d8580354e120b038967a180f73bc3aba0f49db9b6d2cb5c4cec85e8cab3e218"
derivative_order_hashes: "0x920a4ea4144c46d1e1084ca5807e4f5608639ce00f97139d5b44e628d487e15e"
derivative_order_hashes: "0x11d75d0c2ce8a07f352523be2e3456212c623397d0fc1a2f688b97a15c04372c"
]
---Transaction Response---
txhash: "4E29226884DCA22E127471588F39E0BB03D314E1AA27ECD810D24C4078D52DED"
raw_log: "[]"
gas wanted: 271213
gas fee: 0.0001356065 INJ
simulated spot order hashes [0xd9f30c7e700202615c2775d630b9fb276572d883fa480b6394abbddcb79c8109]
simulated derivative order hashes [0xb2bea3b15c204699a9ee945ca49650001560518d1e54266adac580aa061fedd4]
DEBU[0001] broadcastTx with nonce 3507 fn=func1 src="client/chain/chain.go:598"
DEBU[0003] msg batch committed successfully at height 5214679 fn=func1 src="client/chain/chain.go:619" txHash=CF53E0B31B9E28E0D6D8F763ECEC2D91E38481321EA24AC86F6A8774C658AF44
DEBU[0003] nonce incremented to 3508 fn=func1 src="client/chain/chain.go:623"
DEBU[0003] gas wanted: 659092 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.000329546 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgUpdateSpotMarket
Modifies certain market fields. It can only be sent by the market's admin.
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
from decimal import Decimal
import dotenv
from pyinjective.async_client import AsyncClient
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
await client.initialize_tokens_from_chain_denoms()
composer = await client.composer()
await client.sync_timeout_height()
message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
network=network,
private_key=configured_private_key,
)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
# prepare tx msg
message = composer.msg_update_spot_market(
admin=address.to_acc_bech32(),
market_id="0x215970bfdea5c94d8e964a759d3ce6eae1d113900129cc8428267db5ccdb3d1a",
new_ticker="INJ/USDC 2",
new_min_price_tick_size=Decimal("0.01"),
new_min_quantity_tick_size=Decimal("0.01"),
new_min_notional=Decimal("2"),
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"cosmossdk.io/math"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := chainclient.NewMarketsAssistantInitializedFromChain(ctx, exchangeClient)
if err != nil {
panic(err)
}
baseToken := marketsAssistant.AllTokens()["INJ"]
quoteToken := marketsAssistant.AllTokens()["USDC"]
minPriceTickSize := math.LegacyMustNewDecFromStr("0.01")
minQuantityTickSize := math.LegacyMustNewDecFromStr("0.01")
minNotional := math.LegacyMustNewDecFromStr("2")
chainMinPriceTickSize := minPriceTickSize.Mul(math.LegacyNewDecFromIntWithPrec(math.NewInt(1), int64(quoteToken.Decimals)))
chainMinPriceTickSize = chainMinPriceTickSize.Quo(math.LegacyNewDecFromIntWithPrec(math.NewInt(1), int64(baseToken.Decimals)))
chainMinQuantityTickSize := minQuantityTickSize.Mul(math.LegacyNewDecFromIntWithPrec(math.NewInt(1), int64(baseToken.Decimals)))
chainMinNotional := minNotional.Mul(math.LegacyNewDecFromIntWithPrec(math.NewInt(1), int64(quoteToken.Decimals)))
msg := &exchangetypes.MsgUpdateSpotMarket{
Admin: senderAddress.String(),
MarketId: "0x215970bfdea5c94d8e964a759d3ce6eae1d113900129cc8428267db5ccdb3d1a",
NewTicker: "INJ/USDC 2",
NewMinPriceTickSize: chainMinPriceTickSize,
NewMinQuantityTickSize: chainMinQuantityTickSize,
NewMinNotional: chainMinNotional,
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.AsyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
admin | String | The market's admin address (has to be the message broadcaster) | Yes |
market_id | String | The market's unique ID | Yes |
new_ticker | String | New ticker for the spot market | No |
new_min_price_tick_size | Decimal | Defines the minimum tick size of the order's price | No |
new_min_quantity_tick_size | Decimal | Defines the minimum tick size of the order's quantity | No |
new_min_notional | Decimal | Defines the minimum notional (in quote asset) required for orders in the market | No |
Response Parameters
Response Example:
txhash: "5AF048ADCE6AF753256F03AF2404A5B78C4C3E7E42A91F0B5C9994372E8AC2FE"
raw_log: "[]"
gas wanted: 106585
gas fee: 0.0000532925 INJ
DEBU[0001] broadcastTx with nonce 3503 fn=func1 src="client/chain/chain.go:598"
DEBU[0002] msg batch committed successfully at height 5214406 fn=func1 src="client/chain/chain.go:619"
txHash=31FDA89C3122322C0559B5766CDF892FD0AA12469017CF8BF88B53441464ECC4
DEBU[0002] nonce incremented to 3504 fn=func1 src="client/chain/chain.go:623"
DEBU[0002] gas wanted: 133614 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.000066807 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
LocalOrderHashComputation
This function computes order hashes locally for SpotOrder and DerivativeOrder. For more information, see the note below.
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import uuid
from decimal import Decimal
import dotenv
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.orderhash import OrderHashManager
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
subaccount_id_2 = address.get_subaccount_id(index=1)
order_hash_manager = OrderHashManager(address=address, network=network, subaccount_indexes=[0, 1, 2, 7])
# prepare trade info
spot_market_id = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
deriv_market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
spot_orders = [
composer.spot_order(
market_id=spot_market_id,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal("0.524"),
quantity=Decimal("0.01"),
order_type="BUY",
cid=str(uuid.uuid4()),
),
composer.spot_order(
market_id=spot_market_id,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal("27.92"),
quantity=Decimal("0.01"),
order_type="SELL",
cid=str(uuid.uuid4()),
),
]
derivative_orders = [
composer.derivative_order(
market_id=deriv_market_id,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal(10500),
quantity=Decimal(0.01),
margin=composer.calculate_margin(
quantity=Decimal(0.01), price=Decimal(10500), leverage=Decimal(2), is_reduce_only=False
),
order_type="BUY",
cid=str(uuid.uuid4()),
),
composer.derivative_order(
market_id=deriv_market_id,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal(65111),
quantity=Decimal(0.01),
margin=composer.calculate_margin(
quantity=Decimal(0.01), price=Decimal(65111), leverage=Decimal(2), is_reduce_only=False
),
order_type="SELL",
cid=str(uuid.uuid4()),
),
]
# prepare tx msg
spot_msg = composer.msg_batch_create_spot_limit_orders(sender=address.to_acc_bech32(), orders=spot_orders)
deriv_msg = composer.msg_batch_create_derivative_limit_orders(
sender=address.to_acc_bech32(), orders=derivative_orders
)
# compute order hashes
order_hashes = order_hash_manager.compute_order_hashes(
spot_orders=spot_orders, derivative_orders=derivative_orders, subaccount_index=0
)
print("computed spot order hashes", order_hashes.spot)
print("computed derivative order hashes", order_hashes.derivative)
# build tx 1
tx = (
Transaction()
.with_messages(spot_msg, deriv_msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
gas_price = GAS_PRICE
base_gas = 85000
gas_limit = base_gas + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
# compute order hashes
order_hashes = order_hash_manager.compute_order_hashes(
spot_orders=spot_orders, derivative_orders=derivative_orders, subaccount_index=0
)
print("computed spot order hashes", order_hashes.spot)
print("computed derivative order hashes", order_hashes.derivative)
# build tx 2
tx = (
Transaction()
.with_messages(spot_msg, deriv_msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
gas_price = GAS_PRICE
base_gas = 85000
gas_limit = base_gas + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
spot_orders = [
composer.spot_order(
market_id=spot_market_id,
subaccount_id=subaccount_id_2,
fee_recipient=fee_recipient,
price=Decimal("1.524"),
quantity=Decimal("0.01"),
order_type="BUY_PO",
cid=str(uuid.uuid4()),
),
composer.spot_order(
market_id=spot_market_id,
subaccount_id=subaccount_id_2,
fee_recipient=fee_recipient,
price=Decimal("27.92"),
quantity=Decimal("0.01"),
order_type="SELL_PO",
cid=str(uuid.uuid4()),
),
]
derivative_orders = [
composer.derivative_order(
market_id=deriv_market_id,
subaccount_id=subaccount_id_2,
fee_recipient=fee_recipient,
price=Decimal(25111),
quantity=Decimal(0.01),
margin=composer.calculate_margin(
quantity=Decimal(0.01), price=Decimal(25111), leverage=Decimal("1.5"), is_reduce_only=False
),
order_type="BUY",
cid=str(uuid.uuid4()),
),
composer.derivative_order(
market_id=deriv_market_id,
subaccount_id=subaccount_id_2,
fee_recipient=fee_recipient,
price=Decimal(65111),
quantity=Decimal(0.01),
margin=composer.calculate_margin(
quantity=Decimal(0.01), price=Decimal(25111), leverage=Decimal(2), is_reduce_only=False
),
order_type="SELL",
cid=str(uuid.uuid4()),
),
]
# prepare tx msg
spot_msg = composer.msg_batch_create_spot_limit_orders(sender=address.to_acc_bech32(), orders=spot_orders)
deriv_msg = composer.msg_batch_create_derivative_limit_orders(
sender=address.to_acc_bech32(), orders=derivative_orders
)
# compute order hashes
order_hashes = order_hash_manager.compute_order_hashes(
spot_orders=spot_orders, derivative_orders=derivative_orders, subaccount_index=1
)
print("computed spot order hashes", order_hashes.spot)
print("computed derivative order hashes", order_hashes.derivative)
# build tx 3
tx = (
Transaction()
.with_messages(spot_msg, deriv_msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
gas_price = GAS_PRICE
base_gas = 85000
gas_limit = base_gas + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"os"
"time"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
"github.com/google/uuid"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"github.com/shopspring/decimal"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
// initialize grpc client
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := chainclient.NewMarketsAssistantInitializedFromChain(ctx, exchangeClient)
if err != nil {
panic(err)
}
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
// prepare tx msg
defaultSubaccountID := chainClient.Subaccount(senderAddress, 1)
spotOrder := chainClient.CreateSpotOrder(
defaultSubaccountID,
&chainclient.SpotOrderData{
OrderType: exchangetypes.OrderType_BUY,
Quantity: decimal.NewFromFloat(2),
Price: decimal.NewFromFloat(22.55),
FeeRecipient: senderAddress.String(),
MarketId: "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe",
Cid: uuid.NewString(),
},
marketsAssistant,
)
derivativeOrder := chainClient.CreateDerivativeOrder(
defaultSubaccountID,
&chainclient.DerivativeOrderData{
OrderType: exchangetypes.OrderType_BUY,
Quantity: decimal.NewFromFloat(2),
Price: decimal.RequireFromString("31"),
Leverage: decimal.RequireFromString("2.5"),
FeeRecipient: senderAddress.String(),
MarketId: "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
Cid: uuid.NewString(),
},
marketsAssistant,
)
msg := new(exchangetypes.MsgBatchCreateSpotLimitOrders)
msg.Sender = senderAddress.String()
msg.Orders = []exchangetypes.SpotOrder{*spotOrder}
msg1 := new(exchangetypes.MsgBatchCreateDerivativeLimitOrders)
msg1.Sender = senderAddress.String()
msg1.Orders = []exchangetypes.DerivativeOrder{*derivativeOrder, *derivativeOrder}
// compute local order hashes
orderHashes, err := chainClient.ComputeOrderHashes(msg.Orders, msg1.Orders, defaultSubaccountID)
if err != nil {
fmt.Println(err)
}
fmt.Println("computed spot order hashes: ", orderHashes.Spot)
fmt.Println("computed derivative order hashes: ", orderHashes.Derivative)
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg, msg1)
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Response Parameters
Response Example:
computed spot order hashes ['0xa2d59cca00bade680a552f02deeb43464df21c73649191d64c6436313b311cba', '0xab78219e6c494373262a310d73660198c7a4c91196c0f6bb8808c81d8fb54a11']
computed derivative order hashes ['0x38d432c011f4a62c6b109615718b26332e7400a86f5e6f44e74a8833b7eed992', '0x66a921d83e6931513df9076c91a920e5e943837e2b836ad370b5cf53a1ed742c']
txhash: "604757CD9024FFF2DDCFEED6FC070E435AC09A829DB2E81AD4AD65B33E987A8B"
raw_log: "[]"
gas wanted: 196604
gas fee: 0.000098302 INJ
computed spot order hashes: [0x0103ca50d0d033e6b8528acf28a3beb3fd8bac20949fc1ba60a2da06c53ad94f]
computed derivative order hashes: [0x15334a7a0f1c2f98b9369f79b9a62a1f357d3e63b46a8895a4cec0ca375ddbbb 0xc26c8f74f56eade275e518f73597dd8954041bfbae3951ed4d7efeb0d060edbd]
DEBU[0001] broadcastTx with nonce 3488 fn=func1 src="client/chain/chain.go:598"
DEBU[0003] msg batch committed successfully at height 5212331 fn=func1 src="client/chain/chain.go:619" txHash=19D8D81BB1DF59889E00EAA600A01079BA719F00A4A43CCC1B56580A1BBD6455
DEBU[0003] nonce incremented to 3489 fn=func1 src="client/chain/chain.go:623"
DEBU[0003] gas wanted: 271044 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.000135522 INJ
Note on LocalOrderHashComputation for HFTs/API Traders
LocalOrderHashComputation
returns a locally computed transaction hash for spot and derivative orders, which is useful when the user needs the transaction hash faster than orders can be streamed through StreamOrdersHistory
(there is extra latency since the order must be included by a block, and the block must be indexed by the Indexer). While the hash can also be obtained through transaction simulation, the process adds a layer of latency and can only be used for one transaction per block (simulation relies on a nonce based on the state machine which does not change until the transaction is included in a block).
On Injective, subaccount nonces are used to calculate order hashes. The subaccount nonce is incremented with each order so that order hashes remain unique.
For strategies employing high frequency trading, order hashes should be calculated locally before transactions are broadcasted. This is possible as long as the subaccount nonce is cached/tracked locally instead of queried from the chain. Similarly, the account sequence (like nonce on Ethereum) should be cached if more than one transaction per block is desired. The LocalOrderHashComputation
implementation can be found here. Refer to the above API example for usage.
There are two caveats to be mindful of when taking this approach:
1. Gas must be manually calculated instead of fetched from simulation
- To avoid latency issues from simulation, it's best to completely omit simulation for fetching gas and order hash.
- To calculate gas, a constant value should be set for the base transaction object. The tx object consists of a constant set of attributes such as memo, sequence, etc., so gas should be the same as long as the amount of data being transmitted remains constant (i.e. gas may change if the memo size is very large). The gas can then be increased per order creation/cancellation.
- These constants can be found through simulating a transaction with a single order and a separate transaction with two orders, then solving the linear equations to obtain the base gas and the per-order gas amounts.
class GasLimitConstant:
base = 65e3
extra = 20e3
spot_order = 60e3
spot_cancel = 40e3
- An extra 20,000 buffer can be added to the gas calculation to ensure the transaction is not rejected during execution on the validator node. Transactions often require a bit more gas depending on the operations; for example, a post-only order could cross the order book and get cancelled, which would cost a different amount of gas than if that order was posted in the book as a limit order. See example on right:
- Note: In cosmos-sdk v0.46, a gas refund capability was added through the PostHandler functionality. In theory, this means that gas constants can be set much higher such that transactions never fail; however, because v0.46 was not compatible with CosmWasm during the last chain upgrade, the refund capability is not implemented on Injective. This may change in the future, but as of now, gas is paid in its entirety as set.
2. In the event a transaction fails, the account sequence and subaccount nonce must both be refreshed
- If the client receives a sequence mismatch error (code 32), a refresh in sequence and subaccount nonce will likely resolve the error.
res = await self.client.broadcast_tx_sync_mode(tx_raw_bytes)
if res.code == 32:
await client.fetch_account(address.to_acc_bech32())
- To refresh the cached account sequence, updated account data can be fetched using the client. See example on right, using the Python client:
- To refresh the cached subaccount nonce, the
OrderHashManager
can be reinitialized since the subaccount nonce is fetched from the chain during init.
- Chain Exchange for Binary Options
Includes all messages related to binary options.
BinaryOptionsMarkets
Retrieves binary options markets
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
markets = await client.fetch_chain_binary_options_markets(status="Active")
print(markets)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
status := "Active"
res, err := chainClient.FetchChainBinaryOptionsMarkets(ctx, status)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
status | String | Market status | No |
Response Parameters
Response Example:
{
"markets":[
]
}
Parameter | Type | Description |
---|---|---|
markets | BinaryOptionsMarket Array | List of binary options markets |
BinaryOptionsMarket
Parameter | Type | Description |
---|---|---|
ticker | String | Name of the pair in format AAA/BBB, where AAA is base asset, BBB is quote asset |
oracle_symbol | String | Oracle symbol |
oracle_provider | String | Oracle provider |
oracle_type | OracleType | The oracle type |
oracle_scale_factor | Integer | The oracle number of scale decimals |
expiration_timestamp | Integer | The market expiration timestamp |
settlement_timestamp | Integer | The market settlement timestamp |
admin | String | The market's admin address |
quote_denom | String | Coin denom used for the quote asset |
market_id | String | The market ID |
maker_fee_rate | Decimal | Fee percentage makers pay when trading |
taker_fee_rate | Decimal | Fee percentage takers pay when trading |
relayer_fee_share_rate | Decimal | Percentage of the transaction fee shared with the relayer in a derivative market |
status | MarketStatus | Status of the market |
min_price_tick_size | Decimal | Minimum tick size that the price required for orders in the market |
min_quantity_tick_size | Decimal | Minimum tick size of the quantity required for orders in the market |
settlement_price | Decimal | The market's settlement price |
min_notional | Decimal | Minimum notional (in quote asset) required for orders in the market |
admin_permissions | Integer | Level of admin permissions (the permission number is a result of adding up all individual permissions numbers) |
OracleType
Code | Name |
---|---|
0 | Unspecified |
1 | Band |
2 | PriceFeed |
3 | Coinbase |
4 | Chainlink |
5 | Razor |
6 | Dia |
7 | API3 |
8 | Uma |
9 | Pyth |
10 | BandIBC |
11 | Provider |
AdminPermission
Code | Name |
---|---|
1 | Ticker Permission |
2 | Min Price Tick Size Permission |
4 | Min Quantity Tick Size Permission |
8 | Min Notional Permission |
16 | Initial Margin Ratio Permission |
32 | Maintenance Margin Ratio Permission |
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"cosmossdk.io/math"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
oracletypes "github.com/InjectiveLabs/sdk-go/chain/oracle/types"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := chainclient.NewMarketsAssistantInitializedFromChain(ctx, exchangeClient)
if err != nil {
panic(err)
}
quoteToken := marketsAssistant.AllTokens()["USDC"]
minPriceTickSize := math.LegacyMustNewDecFromStr("0.01")
minQuantityTickSize := math.LegacyMustNewDecFromStr("0.001")
chainMinPriceTickSize := minPriceTickSize.Mul(math.LegacyNewDecFromIntWithPrec(math.NewInt(1), int64(quoteToken.Decimals)))
chainMinQuantityTickSize := minQuantityTickSize
msg := &exchangetypes.MsgInstantBinaryOptionsMarketLaunch{
Sender: senderAddress.String(),
Ticker: "UFC-KHABIB-TKO-05/30/2023",
OracleSymbol: "UFC-KHABIB-TKO-05/30/2023",
OracleProvider: "UFC",
OracleType: oracletypes.OracleType_Provider,
OracleScaleFactor: 6,
MakerFeeRate: math.LegacyMustNewDecFromStr("0.0005"),
TakerFeeRate: math.LegacyMustNewDecFromStr("0.0010"),
ExpirationTimestamp: 1680730982,
SettlementTimestamp: 1690730982,
Admin: senderAddress.String(),
QuoteDenom: quoteToken.Denom,
MinPriceTickSize: chainMinPriceTickSize,
MinQuantityTickSize: chainMinQuantityTickSize,
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.AsyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The market launch requestor address | Yes |
ticker | String | Ticker for the binary options market | Yes |
oracle_symbol | String | Oracle symbol | Yes |
oracle_provider | String | Oracle provider | Yes |
oracle_type | OracleType | The oracle type | Yes |
oracle_scale_factor | Integer | Scale factor for oracle prices | Yes |
maker_fee_rate | Decimal | Defines the trade fee rate for makers on the perpetual market | Yes |
taker_fee_rate | Decimal | Defines the trade fee rate for takers on the perpetual market | Yes |
expiration_timestamp | Integer | The market's expiration time in seconds | Yes |
settlement_timestamp | Integer | The market's settlement time in seconds | Yes |
admin | String | The market's admin address | Yes |
quote_denom | String | Quote tocken denom | Yes |
min_price_tick_size | Decimal | Defines the minimum tick size of the order's price | Yes |
min_quantity_tick_size | Decimal | Defines the minimum tick size of the order's quantity | Yes |
min_notional | Decimal | Defines the minimum notional (in quote asset) required for orders in the market | Yes |
OracleType
Code | Name |
---|---|
0 | Unspecified |
1 | Band |
2 | PriceFeed |
3 | Coinbase |
4 | Chainlink |
5 | Razor |
6 | Dia |
7 | API3 |
8 | Uma |
9 | Pyth |
10 | BandIBC |
11 | Provider |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgCreateBinaryOptionsLimitOrder
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import uuid
from decimal import Decimal
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.utils.denom import Denom
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
# prepare trade info
market_id = "0x767e1542fbc111e88901e223e625a4a8eb6d630c96884bbde672e8bc874075bb"
fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
# set custom denom to bypass ini file load (optional)
denom = Denom(
description="desc",
base=0,
quote=6,
min_price_tick_size=1000,
min_quantity_tick_size=0.0001,
min_notional=0,
)
# prepare tx msg
msg = composer.msg_create_binary_options_limit_order(
sender=address.to_acc_bech32(),
market_id=market_id,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal("0.5"),
quantity=Decimal("1"),
margin=Decimal("0.5"),
order_type="BUY",
cid=str(uuid.uuid4()),
denom=denom,
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
sim_res_msg = sim_res["result"]["msgResponses"]
print("---Simulation Response---")
print(sim_res_msg)
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print("---Transaction Response---")
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The message sender's address | Yes |
order | DerivativeOrder | Order's parameters | Yes |
DerivativeOrder
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The unique ID of the market | Yes |
order_info | OrderInfo | Order's information | Yes |
order_type | OrderType | The order type | Yes |
margin | Decimal | The margin amount used by the order | Yes |
trigger_price | Decimal | The trigger price used by stop/take orders | No |
OrderInfo
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | Subaccount ID that created the order | Yes |
fee_recipient | String | Address that will receive fees for the order | No |
price | Decimal | Price of the order | Yes |
quantity | Decimal | Quantity of the order | Yes |
cid | String | Client order ID. An optional identifier for the order set by the creator | No |
OrderType
Code | Name |
---|---|
0 | UNSPECIFIED |
1 | BUY |
2 | SELL |
3 | STOP_BUY |
4 | STOP_SELL |
5 | TAKE_BUY |
6 | TAKE_SELL |
7 | BUY_PO |
8 | SELL_PO |
9 | BUY_ATOMIC |
10 | SELL_ATOMIC |
Response Parameters
Response Example:
---Simulation Response---
[order_hash: "0xc1e1a8e81659360c3092043a000786f23fce5f3b8a355da32227c3e8eafb1fde"
]
---Transaction Response---
txhash: "7955AE8D7EA90E85F07E776372369E92952A0A86DC9BCBDBA3132447DB738282"
raw_log: "[]"
gas wanted: 121249
gas fee: 0.0000606245 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgCreateBinaryOptionsMarketOrder
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import uuid
from decimal import Decimal
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
# prepare trade info
market_id = "0x00617e128fdc0c0423dd18a1ff454511af14c4db6bdd98005a99cdf8fdbf74e9"
fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
# prepare tx msg
msg = composer.msg_create_binary_options_market_order(
sender=address.to_acc_bech32(),
market_id=market_id,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal("0.5"),
quantity=Decimal(1),
margin=composer.calculate_margin(
quantity=Decimal(1), price=Decimal("0.5"), leverage=Decimal(1), is_reduce_only=False
),
cid=str(uuid.uuid4()),
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
sim_res_msg = sim_res["result"]["msgResponses"]
print("---Simulation Response---")
print(sim_res_msg)
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print("---Transaction Response---")
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The message sender's address | Yes |
order | DerivativeOrder | Order's parameters | Yes |
DerivativeOrder
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The unique ID of the market | Yes |
order_info | OrderInfo | Order's information | Yes |
order_type | OrderType | The order type | Yes |
margin | Decimal | The margin amount used by the order | Yes |
trigger_price | Decimal | The trigger price used by stop/take orders | No |
OrderInfo
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | Subaccount ID that created the order | Yes |
fee_recipient | String | Address that will receive fees for the order | No |
price | Decimal | Price of the order | Yes |
quantity | Decimal | Quantity of the order | Yes |
cid | String | Client order ID. An optional identifier for the order set by the creator | No |
OrderType
Code | Name |
---|---|
0 | UNSPECIFIED |
1 | BUY |
2 | SELL |
3 | STOP_BUY |
4 | STOP_SELL |
5 | TAKE_BUY |
6 | TAKE_SELL |
7 | BUY_PO |
8 | SELL_PO |
9 | BUY_ATOMIC |
10 | SELL_ATOMIC |
Response Parameters
Response Example:
---Simulation Response---
[order_hash: "0x1d4ebeaa75bb6a5232ef20cf9ff10eedc470be8f716fb4b3a57780fb1247b4dc"
]
---Transaction Response---
txhash: "FE91A0828F1900FB9FD202BF872B66580A89E663062B3DF13874328A7F6CF797"
raw_log: "[]"
gas wanted: 107903
gas fee: 0.0000539515 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgCancelBinaryOptionsOrder
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
# prepare trade info
market_id = "0x00617e128fdc0c0423dd18a1ff454511af14c4db6bdd98005a99cdf8fdbf74e9"
order_hash = "a975fbd72b874bdbf5caf5e1e8e2653937f33ce6dd14d241c06c8b1f7b56be46"
# prepare tx msg
msg = composer.msg_cancel_binary_options_order(
sender=address.to_acc_bech32(), market_id=market_id, subaccount_id=subaccount_id, order_hash=order_hash
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
sim_res_msg = sim_res["result"]["msgResponses"]
print("---Simulation Response---")
print(sim_res_msg)
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print("---Transaction Response---")
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The message sender's address | Yes |
market_id | String | The unique ID of the order's market | Yes |
subaccount_id | String | The subaccount ID the order belongs to | Yes |
order_hash | String | The order hash (either order_hash or cid have to be provided) | No |
order_mask | OrderMask | The order mask that specifies the order type | No |
cid | String | The client order ID provided by the creator (either order_hash or cid have to be provided) | No |
OrderMask
Code | Name |
---|---|
0 | OrderMask_UNUSED |
1 | OrderMask_ANY |
2 | OrderMask_REGULAR |
4 | OrderMask_CONDITIONAL |
8 | OrderMask_BUY_OR_HIGHER |
16 | OrderMask_SELL_OR_LOWER |
32 | OrderMask_MARKET |
64 | OrderMask_LIMIT |
Response Parameters
Response Example:
---Transaction Response---
txhash: "4B85368A96A67BB9B6DABB8B730A824051E0E4C9243F5970DF1512B98FCF2D67"
raw_log: "[]"
gas wanted: 111303
gas fee: 0.0000556515 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgAdminUpdateBinaryOptionsMarket
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
from decimal import Decimal
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
# prepare trade info
market_id = "0xfafec40a7b93331c1fc89c23f66d11fbb48f38dfdd78f7f4fc4031fad90f6896"
status = "Demolished"
settlement_price = Decimal(1)
expiration_timestamp = 1685460582
settlement_timestamp = 1690730982
# prepare tx msg
msg = composer.msg_admin_update_binary_options_market(
sender=address.to_acc_bech32(),
market_id=market_id,
settlement_price=settlement_price,
expiration_timestamp=expiration_timestamp,
settlement_timestamp=settlement_timestamp,
status=status,
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
sim_res_msg = sim_res["result"]["msgResponses"]
print("---Simulation Response---")
print(sim_res_msg)
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print("---Transaction Response---")
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The market launch requestor address | Yes |
market_id | String | The unique market ID | Yes |
settlement_price | Decimal | The price at which market will be settled | No |
expiration_timestamp | Integer | The market's expiration time in seconds | Yes |
settlement_timestamp | Integer | The market's settlement time in seconds | Yes |
market_status | MarketStatus | The market status | Yes |
MarketStatus
Code | Name |
---|---|
0 | Unspecified |
1 | Active |
2 | Paused |
3 | Demolished |
4 | Expired |
Response Parameters
Response Example:
---Transaction Response---
txhash: "4B85368A96A67BB9B6DABB8B730A824051E0E4C9243F5970DF1512B98FCF2D67"
raw_log: "[]"
gas wanted: 111303
gas fee: 0.0000556515 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgBatchUpdateOrders
MsgBatchUpdateOrders allows for the atomic cancellation and creation of spot and derivative limit orders, along with a new order cancellation mode. Upon execution, order cancellations (if any) occur first, followed by order creations (if any).
Users can cancel all limit orders in a given spot or derivative market for a given subaccountID by specifying the associated marketID in the SpotMarketIdsToCancelAll and DerivativeMarketIdsToCancelAll. Users can also cancel individual limit orders in SpotOrdersToCancel or DerivativeOrdersToCancel, but must ensure that marketIDs in these individual order cancellations are not already provided in the SpotMarketIdsToCancelAll or DerivativeMarketIdsToCancelAll.
Further note that if no marketIDs are provided in the SpotMarketIdsToCancelAll or DerivativeMarketIdsToCancelAll, then the SubaccountID in the Msg should be left empty.
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import uuid
from decimal import Decimal
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
subaccount_id = address.get_subaccount_id(index=0)
# prepare trade info
fee_recipient = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
derivative_market_id_create = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
spot_market_id_create = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
derivative_market_id_cancel = "0xd5e4b12b19ecf176e4e14b42944731c27677819d2ed93be4104ad7025529c7ff"
derivative_market_id_cancel_2 = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
spot_market_id_cancel = "0x0611780ba69656949525013d947713300f56c37b6175e02f26bffa495c3208fe"
spot_market_id_cancel_2 = "0x7a57e705bb4e09c88aecfc295569481dbf2fe1d5efe364651fbe72385938e9b0"
derivative_orders_to_cancel = [
composer.order_data(
market_id=derivative_market_id_cancel,
subaccount_id=subaccount_id,
order_hash="0x48690013c382d5dbaff9989db04629a16a5818d7524e027d517ccc89fd068103",
),
composer.order_data(
market_id=derivative_market_id_cancel_2,
subaccount_id=subaccount_id,
order_hash="0x7ee76255d7ca763c56b0eab9828fca89fdd3739645501c8a80f58b62b4f76da5",
),
]
spot_orders_to_cancel = [
composer.order_data(
market_id=spot_market_id_cancel,
subaccount_id=subaccount_id,
cid="0e5c3ad5-2cc4-4a2a-bbe5-b12697739163",
),
composer.order_data(
market_id=spot_market_id_cancel_2,
subaccount_id=subaccount_id,
order_hash="0x222daa22f60fe9f075ed0ca583459e121c23e64431c3fbffdedda04598ede0d2",
),
]
derivative_orders_to_create = [
composer.derivative_order(
market_id=derivative_market_id_create,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal(25000),
quantity=Decimal(0.1),
margin=composer.calculate_margin(
quantity=Decimal(0.1), price=Decimal(25000), leverage=Decimal(1), is_reduce_only=False
),
order_type="BUY",
cid=str(uuid.uuid4()),
),
composer.derivative_order(
market_id=derivative_market_id_create,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal(50000),
quantity=Decimal(0.01),
margin=composer.calculate_margin(
quantity=Decimal(0.01), price=Decimal(50000), leverage=Decimal(1), is_reduce_only=False
),
order_type="SELL",
cid=str(uuid.uuid4()),
),
]
spot_orders_to_create = [
composer.spot_order(
market_id=spot_market_id_create,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal("3"),
quantity=Decimal("55"),
order_type="BUY",
cid=str(uuid.uuid4()),
),
composer.spot_order(
market_id=spot_market_id_create,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal("300"),
quantity=Decimal("55"),
order_type="SELL",
cid=str(uuid.uuid4()),
),
]
# prepare tx msg
msg = composer.msg_batch_update_orders(
sender=address.to_acc_bech32(),
derivative_orders_to_create=derivative_orders_to_create,
spot_orders_to_create=spot_orders_to_create,
derivative_orders_to_cancel=derivative_orders_to_cancel,
spot_orders_to_cancel=spot_orders_to_cancel,
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
sim_res_msg = sim_res["result"]["msgResponses"]
print("---Simulation Response---")
print(sim_res_msg)
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print("---Transaction Response---")
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"os"
"time"
exchangeclient "github.com/InjectiveLabs/sdk-go/client/exchange"
"github.com/google/uuid"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
"github.com/shopspring/decimal"
exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
fmt.Println(err)
return
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
exchangeClient, err := exchangeclient.NewExchangeClient(network)
if err != nil {
panic(err)
}
ctx := context.Background()
marketsAssistant, err := chainclient.NewMarketsAssistantInitializedFromChain(ctx, exchangeClient)
if err != nil {
panic(err)
}
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
fmt.Println(err)
return
}
defaultSubaccountID := chainClient.DefaultSubaccount(senderAddress)
smarketId := "0x0511ddc4e6586f3bfe1acb2dd905f8b8a82c97e1edaef654b12ca7e6031ca0fa"
samount := decimal.NewFromFloat(2)
sprice := decimal.NewFromFloat(22.5)
smarketIds := []string{"0xa508cb32923323679f29a032c70342c147c17d0145625922b0ef22e955c844c0"}
spot_order := chainClient.CreateSpotOrder(
defaultSubaccountID,
&chainclient.SpotOrderData{
OrderType: exchangetypes.OrderType_BUY, //BUY SELL BUY_PO SELL_PO
Quantity: samount,
Price: sprice,
FeeRecipient: senderAddress.String(),
MarketId: smarketId,
Cid: uuid.NewString(),
},
marketsAssistant,
)
dmarketId := "0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"
damount := decimal.NewFromFloat(0.01)
dprice := decimal.RequireFromString("31000") //31,000
dleverage := decimal.RequireFromString("2")
dmarketIds := []string{"0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce"}
derivative_order := chainClient.CreateDerivativeOrder(
defaultSubaccountID,
&chainclient.DerivativeOrderData{
OrderType: exchangetypes.OrderType_BUY, //BUY SELL BUY_PO SELL_PO
Quantity: damount,
Price: dprice,
Leverage: dleverage,
FeeRecipient: senderAddress.String(),
MarketId: dmarketId,
IsReduceOnly: false,
Cid: uuid.NewString(),
},
marketsAssistant,
)
msg := new(exchangetypes.MsgBatchUpdateOrders)
msg.Sender = senderAddress.String()
msg.SubaccountId = defaultSubaccountID.Hex()
msg.SpotOrdersToCreate = []*exchangetypes.SpotOrder{spot_order}
msg.DerivativeOrdersToCreate = []*exchangetypes.DerivativeOrder{derivative_order}
msg.SpotMarketIdsToCancelAll = smarketIds
msg.DerivativeMarketIdsToCancelAll = dmarketIds
simRes, err := chainClient.SimulateMsg(clientCtx, msg)
if err != nil {
fmt.Println(err)
return
}
MsgBatchUpdateOrdersResponse := exchangetypes.MsgBatchUpdateOrdersResponse{}
MsgBatchUpdateOrdersResponse.Unmarshal(simRes.Result.MsgResponses[0].Value)
fmt.Println("simulated spot order hashes", MsgBatchUpdateOrdersResponse.SpotOrderHashes)
fmt.Println("simulated derivative order hashes", MsgBatchUpdateOrdersResponse.DerivativeOrderHashes)
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
return
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The message sender's address | Yes |
subaccount_id | String | The subaccount ID is only used for the spot_market_ids_to_cancel_all and derivative_market_ids_to_cancel_all | No |
spot_market_ids_to_cancel_all | String Array | List of unique market IDs to cancel all subaccount_id orders | No |
derivative_market_ids_to_cancel_all | String Array | List of unique market IDs to cancel all subaccount_id orders | No |
spot_orders_to_cancel | OrderData Array | List of spot orders to be cancelled | No |
derivative_orders_to_cancel | OrderData Array | List of derivative orders to be cancelled | No |
spot_orders_to_create | SpotOrder Array | List of spot orders to be created | No |
derivative_orders_to_create | DerivativeOrder Array | List of derivative orders to be created | No |
binary_options_orders_to_cancel | OrderData Array | List of binary options orders to be cancelled | No |
binary_options_market_ids_to_cancel_all | String Array | List of unique market IDs to cancel all subaccount_id orders | No |
binary_options_orders_to_create | DerivativeOrder Array | List of binary options orders to be created | No |
OrderData
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The order's market ID | Yes |
subaccount_id | String | Subaccount ID that created the order | Yes |
order_hash | String | The order hash (either the order_hash or the cid should be provided) | No |
order_mask | OrderMask | The order mask that specifies the order type | No |
cid | String | The order's client order ID (either the order_hash or the cid should be provided) | No |
SpotOrder
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The unique ID of the market | Yes |
order_info | OrderInfo | Order's information | Yes |
order_type | OrderType | The order type | Yes |
trigger_price | Decimal | The trigger price used by stop/take orders | No |
DerivativeOrder
Parameter | Type | Description | Required |
---|---|---|---|
market_id | String | The unique ID of the market | Yes |
order_info | OrderInfo | Order's information | Yes |
order_type | OrderType | The order type | Yes |
margin | Decimal | The margin amount used by the order | Yes |
trigger_price | Decimal | The trigger price used by stop/take orders | No |
OrderMask
Code | Name |
---|---|
0 | OrderMask_UNUSED |
1 | OrderMask_ANY |
2 | OrderMask_REGULAR |
4 | OrderMask_CONDITIONAL |
8 | OrderMask_BUY_OR_HIGHER |
16 | OrderMask_SELL_OR_LOWER |
32 | OrderMask_MARKET |
64 | OrderMask_LIMIT |
OrderInfo
Parameter | Type | Description | Required |
---|---|---|---|
subaccount_id | String | Subaccount ID that created the order | Yes |
fee_recipient | String | Address that will receive fees for the order | No |
price | Decimal | Price of the order | Yes |
quantity | Decimal | Quantity of the order | Yes |
cid | String | Client order ID. An optional identifier for the order set by the creator | No |
OrderType
Code | Name |
---|---|
0 | UNSPECIFIED |
1 | BUY |
2 | SELL |
3 | STOP_BUY |
4 | STOP_SELL |
5 | TAKE_BUY |
6 | TAKE_SELL |
7 | BUY_PO |
8 | SELL_PO |
9 | BUY_ATOMIC |
10 | SELL_ATOMIC |
Response Parameters
Response Example:
---Simulation Response---
[spot_cancel_success: false
spot_cancel_success: false
derivative_cancel_success: false
derivative_cancel_success: false
spot_order_hashes: "0x3f5b5de6ec72b250c58e0a83408dbc1990cee369999036e3469e19b80fa9002e"
spot_order_hashes: "0x7d8580354e120b038967a180f73bc3aba0f49db9b6d2cb5c4cec85e8cab3e218"
derivative_order_hashes: "0x920a4ea4144c46d1e1084ca5807e4f5608639ce00f97139d5b44e628d487e15e"
derivative_order_hashes: "0x11d75d0c2ce8a07f352523be2e3456212c623397d0fc1a2f688b97a15c04372c"
]
---Transaction Response---
txhash: "4E29226884DCA22E127471588F39E0BB03D314E1AA27ECD810D24C4078D52DED"
raw_log: "[]"
gas wanted: 271213
gas fee: 0.0001356065 INJ
simulated spot order hashes [0xd9f30c7e700202615c2775d630b9fb276572d883fa480b6394abbddcb79c8109]
simulated derivative order hashes [0xb2bea3b15c204699a9ee945ca49650001560518d1e54266adac580aa061fedd4]
DEBU[0001] broadcastTx with nonce 3507 fn=func1 src="client/chain/chain.go:598"
DEBU[0003] msg batch committed successfully at height 5214679 fn=func1 src="client/chain/chain.go:619" txHash=CF53E0B31B9E28E0D6D8F763ECEC2D91E38481321EA24AC86F6A8774C658AF44
DEBU[0003] nonce incremented to 3508 fn=func1 src="client/chain/chain.go:623"
DEBU[0003] gas wanted: 659092 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.000329546 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
- IBC Core Channel
Includes all the messages and queries associated to channels from the IBC core channel module
Channel
Queries an IBC Channel
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
port_id = "transfer"
channel_id = "channel-126"
channel = await client.fetch_ibc_channel(port_id=port_id, channel_id=channel_id)
print(channel)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
portId := "transfer"
channelId := "channel-126"
ctx := context.Background()
res, err := chainClient.FetchIBCChannel(ctx, portId, channelId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
port_id | String | Port unique identifier | Yes |
channel_id | String | Channel unique identifier | Yes |
Response Parameters
Response Example:
{
"channel":{
"state":"STATE_OPEN",
"ordering":"ORDER_UNORDERED",
"counterparty":{
"portId":"transfer",
"channelId":"channel-352"
},
"connectionHops":[
"connection-173"
],
"version":"ics20-1"
},
"proofHeight":{
"revisionNumber":"888",
"revisionHeight":"26820151"
},
"proof":""
}
Parameter | Type | Description |
---|---|---|
channel | Channel | Channel details |
proof | Byte Array | Merkle proof of existence |
proof_height | Height | Height at which the proof was retrieved |
Channel
Parameter | Type | Description |
---|---|---|
state | State | Current state of the channel end |
ordering | Order | Whether the channel is ordered or unordered |
counterparty | Counterparty | Counterparty channel end |
connection_hops | String Array | List of connection identifiers, in order, along which packets sent on this channel will travel |
version | String | Opaque channel version, which is agreed upon during the handshake |
upgrade_sequence | Integer | Indicates the latest upgrade attempt performed by this channel. The value of 0 indicates the channel has never been upgraded |
State
Code | Name |
---|---|
0 | STATE_UNINITIALIZED_UNSPECIFIED |
1 | STATE_INIT |
2 | STATE_TRYOPEN |
3 | STATE_OPEN |
4 | STATE_CLOSED |
Order
Code | Name |
---|---|
0 | ORDER_NONE_UNSPECIFIED |
1 | ORDER_UNORDERED |
2 | ORDER_ORDERED |
Counterparty
Parameter | Type | Description |
---|---|---|
port_id | String | Port on the counterparty chain which owns the other end of the channel |
channel_id | String | Channel end on the counterparty chain |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
Channels
Queries all the IBC channels of a chain
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
pagination = PaginationOption(skip=2, limit=4)
channels = await client.fetch_ibc_channels(pagination=pagination)
print(channels)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
pagination := query.PageRequest{Offset: 2, Limit: 4}
ctx := context.Background()
res, err := chainClient.FetchIBCChannels(ctx, &pagination)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
pagination | PageRequest | The optional pagination for the request | No |
PageRequest
Parameter | Type | Description | Required |
---|---|---|---|
key | Byte Array | Key is a value returned in PageResponse.next_key to begin querying the next page most efficiently. Only one of offset or key should be set | No |
offset | Integer | Numeric offset that can be used when key is unavailable. It is less efficient than using key. Only one of offset or key should be set | No |
limit | Integer | Total number of results to be returned in the result page | No |
count_total | Boolean | Set to true to indicate that the result set should include a count of the total number of items available for pagination in UIs. It is only respected when offset is used. It is ignored when key is set | No |
reverse | Boolean | Reverse is set to true if results are to be returned in the descending order | No |
Response Parameters
Response Example:
{
"channels":[
{
"state":"STATE_OPEN",
"ordering":"ORDER_ORDERED",
"counterparty":{
"portId":"icacontroller-sweep-inj",
"channelId":"channel-19"
},
"connectionHops":[
"connection-182"
],
"version":"{\"version\":\"ics27-1\",\"controller_connection_id\":\"connection-9\",\"host_connection_id\":\"connection-182\",\"address\":\"inj1v0es67dxtlmzmauhr3krk058sp9cvt6e2hvmys2g8pjnpj30fezq93qp07\",\"encoding\":\"proto3\",\"tx_type\":\"sdk_multi_msg\"}",
"portId":"icahost",
"channelId":"channel-134"
},
{
"state":"STATE_CLOSED",
"ordering":"ORDER_ORDERED",
"counterparty":{
"portId":"icacontroller-delegation-inj",
"channelId":"channel-20"
},
"connectionHops":[
"connection-182"
],
"version":"{\"version\":\"ics27-1\",\"controller_connection_id\":\"connection-9\",\"host_connection_id\":\"connection-182\",\"address\":\"inj1urqc59ft3hl75mxhru4848xusu5rhpghz48zdfypyuu923w2gzyqm8y02d\",\"encoding\":\"proto3\",\"tx_type\":\"sdk_multi_msg\"}",
"portId":"icahost",
"channelId":"channel-136"
},
{
"state":"STATE_OPEN",
"ordering":"ORDER_ORDERED",
"counterparty":{
"portId":"icacontroller-sweep-inj",
"channelId":"channel-21"
},
"connectionHops":[
"connection-185"
],
"version":"{\"version\":\"ics27-1\",\"controller_connection_id\":\"connection-3\",\"host_connection_id\":\"connection-185\",\"address\":\"inj1s58qfzwjduykz6emh936v8uxytvck4cf0lkvpuerh2qwt6jkaj9qh9cl7x\",\"encoding\":\"proto3\",\"tx_type\":\"sdk_multi_msg\"}",
"portId":"icahost",
"channelId":"channel-182"
},
{
"state":"STATE_OPEN",
"ordering":"ORDER_ORDERED",
"counterparty":{
"portId":"icacontroller-reward-inj",
"channelId":"channel-20"
},
"connectionHops":[
"connection-185"
],
"version":"{\"version\":\"ics27-1\",\"controller_connection_id\":\"connection-3\",\"host_connection_id\":\"connection-185\",\"address\":\"inj1k3cdwxqkjmmjn62tesyumlynj0n5ap2k9ysnyn56zar4uns09a5qvy575s\",\"encoding\":\"proto3\",\"tx_type\":\"sdk_multi_msg\"}",
"portId":"icahost",
"channelId":"channel-183"
}
],
"pagination":{
"nextKey":"L3BvcnRzL2ljYWhvc3QvY2hhbm5lbHMvY2hhbm5lbC0xODQ=",
"total":"0"
},
"height":{
"revisionNumber":"888",
"revisionHeight":"26823064"
}
}
Parameter | Type | Description |
---|---|---|
channels | IdentifiedChannel Array | List of channels |
pagination | PageResponse | Pagination information in the response |
height | Height | Query block height |
IdentifiedChannel
Parameter | Type | Description |
---|---|---|
state | State | Current state of the channel end |
ordering | Order | Whether the channel is ordered or unordered |
counterparty | Counterparty | Counterparty channel end |
connection_hops | String Array | List of connection identifiers, in order, along which packets sent on this channel will travel |
version | String | Opaque channel version, which is agreed upon during the handshake |
port_id | String | Port identifier |
channel_id | String | Channel identifier |
upgrade_sequence | Integer | Indicates the latest upgrade attempt performed by this channel. The value of 0 indicates the channel has never been upgraded |
State
Code | Name |
---|---|
0 | STATE_UNINITIALIZED_UNSPECIFIED |
1 | STATE_INIT |
2 | STATE_TRYOPEN |
3 | STATE_OPEN |
4 | STATE_CLOSED |
Order
Code | Name |
---|---|
0 | ORDER_NONE_UNSPECIFIED |
1 | ORDER_UNORDERED |
2 | ORDER_ORDERED |
Counterparty
Parameter | Type | Description |
---|---|---|
port_id | String | Port on the counterparty chain which owns the other end of the channel |
channel_id | String | Channel end on the counterparty chain |
PageResponse
Parameter | Type | Description |
---|---|---|
next_key | Byte Array | The key to be passed to PageRequest.key to query the next page most efficiently. It will be empty if there are no more results. |
total | Integer | Total number of results available if PageRequest.count_total was set, its value is undefined otherwise |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
ConnectionChannels
Queries all the channels associated with a connection end
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
connection = "connection-182"
pagination = PaginationOption(skip=2, limit=4)
channels = await client.fetch_ibc_connection_channels(connection=connection, pagination=pagination)
print(channels)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
connection := "connection-182"
pagination := query.PageRequest{Offset: 2, Limit: 4}
ctx := context.Background()
res, err := chainClient.FetchIBCConnectionChannels(ctx, connection, &pagination)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
connection | String | Connection unique identifier | Yes |
pagination | PageRequest | The optional pagination for the request | No |
PageRequest
Parameter | Type | Description | Required |
---|---|---|---|
key | Byte Array | Key is a value returned in PageResponse.next_key to begin querying the next page most efficiently. Only one of offset or key should be set | No |
offset | Integer | Numeric offset that can be used when key is unavailable. It is less efficient than using key. Only one of offset or key should be set | No |
limit | Integer | Total number of results to be returned in the result page | No |
count_total | Boolean | Set to true to indicate that the result set should include a count of the total number of items available for pagination in UIs. It is only respected when offset is used. It is ignored when key is set | No |
reverse | Boolean | Reverse is set to true if results are to be returned in the descending order | No |
Response Parameters
Response Example:
{
"channels":[
{
"state":"STATE_CLOSED",
"ordering":"ORDER_ORDERED",
"counterparty":{
"portId":"icacontroller-delegation-inj",
"channelId":"channel-17"
},
"connectionHops":[
"connection-182"
],
"version":"{\"version\":\"ics27-1\",\"controller_connection_id\":\"connection-9\",\"host_connection_id\":\"connection-182\",\"address\":\"inj1urqc59ft3hl75mxhru4848xusu5rhpghz48zdfypyuu923w2gzyqm8y02d\",\"encoding\":\"proto3\",\"tx_type\":\"sdk_multi_msg\"}",
"portId":"icahost",
"channelId":"channel-132"
},
{
"state":"STATE_OPEN",
"ordering":"ORDER_ORDERED",
"counterparty":{
"portId":"icacontroller-reward-inj",
"channelId":"channel-18"
},
"connectionHops":[
"connection-182"
],
"version":"{\"version\":\"ics27-1\",\"controller_connection_id\":\"connection-9\",\"host_connection_id\":\"connection-182\",\"address\":\"inj1mn3p9d2aw02mdrkfhleefmvr70skrx39mlkkc4f5rnewlc5aux3qs37nt6\",\"encoding\":\"proto3\",\"tx_type\":\"sdk_multi_msg\"}",
"portId":"icahost",
"channelId":"channel-133"
},
{
"state":"STATE_OPEN",
"ordering":"ORDER_ORDERED",
"counterparty":{
"portId":"icacontroller-sweep-inj",
"channelId":"channel-19"
},
"connectionHops":[
"connection-182"
],
"version":"{\"version\":\"ics27-1\",\"controller_connection_id\":\"connection-9\",\"host_connection_id\":\"connection-182\",\"address\":\"inj1v0es67dxtlmzmauhr3krk058sp9cvt6e2hvmys2g8pjnpj30fezq93qp07\",\"encoding\":\"proto3\",\"tx_type\":\"sdk_multi_msg\"}",
"portId":"icahost",
"channelId":"channel-134"
},
{
"state":"STATE_CLOSED",
"ordering":"ORDER_ORDERED",
"counterparty":{
"portId":"icacontroller-delegation-inj",
"channelId":"channel-20"
},
"connectionHops":[
"connection-182"
],
"version":"{\"version\":\"ics27-1\",\"controller_connection_id\":\"connection-9\",\"host_connection_id\":\"connection-182\",\"address\":\"inj1urqc59ft3hl75mxhru4848xusu5rhpghz48zdfypyuu923w2gzyqm8y02d\",\"encoding\":\"proto3\",\"tx_type\":\"sdk_multi_msg\"}",
"portId":"icahost",
"channelId":"channel-136"
},
{
"state":"STATE_OPEN",
"ordering":"ORDER_UNORDERED",
"counterparty":{
"portId":"transfer",
"channelId":"channel-16"
},
"connectionHops":[
"connection-182"
],
"version":"ics20-1",
"portId":"transfer",
"channelId":"channel-131"
}
],
"pagination":{
"nextKey":"",
"total":"0"
},
"height":{
"revisionNumber":"888",
"revisionHeight":"26832162"
}
}
Parameter | Type | Description |
---|---|---|
channels | IdentifiedChannel Array | List of channels |
pagination | PageResponse | Pagination information in the response |
height | Height | Query block height |
IdentifiedChannel
Parameter | Type | Description |
---|---|---|
state | State | Current state of the channel end |
ordering | Order | Whether the channel is ordered or unordered |
counterparty | Counterparty | Counterparty channel end |
connection_hops | String Array | List of connection identifiers, in order, along which packets sent on this channel will travel |
version | String | Opaque channel version, which is agreed upon during the handshake |
port_id | String | Port identifier |
channel_id | String | Channel identifier |
upgrade_sequence | Integer | Indicates the latest upgrade attempt performed by this channel. The value of 0 indicates the channel has never been upgraded |
State
Code | Name |
---|---|
0 | STATE_UNINITIALIZED_UNSPECIFIED |
1 | STATE_INIT |
2 | STATE_TRYOPEN |
3 | STATE_OPEN |
4 | STATE_CLOSED |
Order
Code | Name |
---|---|
0 | ORDER_NONE_UNSPECIFIED |
1 | ORDER_UNORDERED |
2 | ORDER_ORDERED |
Counterparty
Parameter | Type | Description |
---|---|---|
port_id | String | Port on the counterparty chain which owns the other end of the channel |
channel_id | String | Channel end on the counterparty chain |
PageResponse
Parameter | Type | Description |
---|---|---|
next_key | Byte Array | The key to be passed to PageRequest.key to query the next page most efficiently. It will be empty if there are no more results. |
total | Integer | Total number of results available if PageRequest.count_total was set, its value is undefined otherwise |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
ChannelClientState
Queries the client state for the channel associated with the provided channel identifiers
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
port_id = "transfer"
channel_id = "channel-126"
state = await client.fetch_ibc_channel_client_state(port_id=port_id, channel_id=channel_id)
print(state)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
portId := "transfer"
channelId := "channel-126"
ctx := context.Background()
res, err := chainClient.FetchIBCChannelClientState(ctx, portId, channelId)
if err != nil {
fmt.Println(err)
}
fmt.Print(res)
}
Parameter | Type | Description | Required |
---|---|---|---|
port_id | String | Port unique identifier | Yes |
channel_id | String | Channel unique identifier | Yes |
Response Parameters
Response Example:
{
"identifiedClientState":{
"clientId":"07-tendermint-179",
"clientState":{
"@type":"/ibc.lightclients.tendermint.v1.ClientState",
"chainId":"pisco-1",
"trustLevel":{
"numerator":"1",
"denominator":"3"
},
"trustingPeriod":"288000s",
"unbondingPeriod":"432000s",
"maxClockDrift":"40s",
"frozenHeight":{
"revisionNumber":"0",
"revisionHeight":"0"
},
"latestHeight":{
"revisionNumber":"1",
"revisionHeight":"7990906"
},
"proofSpecs":[
{
"leafSpec":{
"hash":"SHA256",
"prehashValue":"SHA256",
"length":"VAR_PROTO",
"prefix":"AA==",
"prehashKey":"NO_HASH"
},
"innerSpec":{
"childOrder":[
0,
1
],
"childSize":33,
"minPrefixLength":4,
"maxPrefixLength":12,
"hash":"SHA256",
"emptyChild":""
},
"maxDepth":0,
"minDepth":0,
"prehashKeyBeforeComparison":false
},
{
"leafSpec":{
"hash":"SHA256",
"prehashValue":"SHA256",
"length":"VAR_PROTO",
"prefix":"AA==",
"prehashKey":"NO_HASH"
},
"innerSpec":{
"childOrder":[
0,
1
],
"childSize":32,
"minPrefixLength":1,
"maxPrefixLength":1,
"hash":"SHA256",
"emptyChild":""
},
"maxDepth":0,
"minDepth":0,
"prehashKeyBeforeComparison":false
}
],
"upgradePath":[
"upgrade",
"upgradedIBCState"
],
"allowUpdateAfterExpiry":true,
"allowUpdateAfterMisbehaviour":true
}
},
"proofHeight":{
"revisionNumber":"888",
"revisionHeight":"26834667"
},
"proof":""
}
Parameter | Type | Description |
---|---|---|
identified_client_state | IdentifiedChannel | Client state associated with the channel |
proof | Byte Array | Merkle proof of existence |
proof_height | Height | Height at which the proof was retrieved |
IdentifiedChannel
Parameter | Type | Description |
---|---|---|
state | State | Current state of the channel end |
ordering | Order | Whether the channel is ordered or unordered |
counterparty | Counterparty | Counterparty channel end |
connection_hops | String Array | List of connection identifiers, in order, along which packets sent on this channel will travel |
version | String | Opaque channel version, which is agreed upon during the handshake |
port_id | String | Port identifier |
channel_id | String | Channel identifier |
upgrade_sequence | Integer | Indicates the latest upgrade attempt performed by this channel. The value of 0 indicates the channel has never been upgraded |
State
Code | Name |
---|---|
0 | STATE_UNINITIALIZED_UNSPECIFIED |
1 | STATE_INIT |
2 | STATE_TRYOPEN |
3 | STATE_OPEN |
4 | STATE_CLOSED |
Order
Code | Name |
---|---|
0 | ORDER_NONE_UNSPECIFIED |
1 | ORDER_UNORDERED |
2 | ORDER_ORDERED |
Counterparty
Parameter | Type | Description |
---|---|---|
port_id | String | Port on the counterparty chain which owns the other end of the channel |
channel_id | String | Channel end on the counterparty chain |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
ChannelConsensusState
Queries the client state for the channel associated with the provided channel identifiers
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
port_id = "transfer"
channel_id = "channel-126"
revision_number = 1
revision_height = 7990906
state = await client.fetch_ibc_channel_consensus_state(
port_id=port_id, channel_id=channel_id, revision_number=revision_number, revision_height=revision_height
)
print(state)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
portId := "transfer"
channelId := "channel-126"
revisionNumber := uint64(1)
revisionHeight := uint64(7990906)
ctx := context.Background()
res, err := chainClient.FetchIBCChannelConsensusState(ctx, portId, channelId, revisionNumber, revisionHeight)
if err != nil {
fmt.Println(err)
}
fmt.Print(res)
}
Parameter | Type | Description | Required |
---|---|---|---|
port_id | String | Port unique identifier | Yes |
channel_id | String | Channel unique identifier | Yes |
revision_number | Integer | Revision number of the consensus state | Yes |
revision_height | Integer | Revision height of the consensus state | Yes |
Response Parameters
Response Example:
{
"consensusState":{
"@type":"/ibc.lightclients.tendermint.v1.ConsensusState",
"timestamp":"2023-10-21T14:57:23.344911848Z",
"root":{
"hash":"89ggv/9AgSoyCBZ0ohhBSMI0LX+ZYe24VdUOA1x6i6I="
},
"nextValidatorsHash":"8DzvA/mMhLfz2C0qSK5+YtbfTopxfFpKm4kApB/u10Y="
},
"clientId":"07-tendermint-179",
"proofHeight":{
"revisionNumber":"888",
"revisionHeight":"26835676"
},
"proof":""
}
Parameter | Type | Description |
---|---|---|
consensus_state | Any | Consensus state associated with the channel |
client_id | String | Client ID associated with the consensus state |
proof | Byte Array | Merkle proof of existence |
proof_height | Height | Height at which the proof was retrieved |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
PacketCommitment
Queries a stored packet commitment hash
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
port_id = "transfer"
channel_id = "channel-126"
sequence = 1
commitment = await client.fetch_ibc_packet_commitment(port_id=port_id, channel_id=channel_id, sequence=sequence)
print(commitment)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
portId := "transfer"
channelId := "channel-126"
sequence := uint64(1)
ctx := context.Background()
res, err := chainClient.FetchIBCPacketCommitment(ctx, portId, channelId, sequence)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
port_id | String | Port unique identifier | Yes |
channel_id | String | Channel unique identifier | Yes |
sequence | Integer | Packet sequence | Yes |
Response Parameters
Response Example:
{
"commitment":"bIKl7JAqoA1IGSDDlb0McwW2A/A77Jpph0yt87BnCO4=",
"proofHeight":{
"revisionNumber":"888",
"revisionHeight":"26836334"
},
"proof":""
}
Parameter | Type | Description |
---|---|---|
commitment | Byte Array | Packet associated with the request fields |
proof | Byte Array | Merkle proof of existence |
proof_height | Height | Height at which the proof was retrieved |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
PacketCommitments
Returns all the packet commitments hashes associated with a channel
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
port_id = "transfer"
channel_id = "channel-126"
pagination = PaginationOption(skip=2, limit=4)
commitment = await client.fetch_ibc_packet_commitments(
port_id=port_id,
channel_id=channel_id,
pagination=pagination,
)
print(commitment)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
portId := "transfer"
channelId := "channel-126"
pagination := query.PageRequest{Offset: 2, Limit: 4}
ctx := context.Background()
res, err := chainClient.FetchIBCPacketCommitments(ctx, portId, channelId, &pagination)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
port_id | String | Port unique identifier | Yes |
channel_id | String | Channel unique identifier | Yes |
pagination | PageRequest | The optional pagination for the request | No |
Response Parameters
Response Example:
{
"commitments":[
{
"portId":"transfer",
"channelId":"channel-126",
"sequence":"100",
"data":"CMcjhUhXioc12WQEv+SVK7pdCdBei9Zw2MNyKm64aII="
},
{
"portId":"transfer",
"channelId":"channel-126",
"sequence":"101",
"data":"hUdJyOfw9Y4X6IqtcZNwOy9vvkir2SK6MGlhqn6gF7w="
},
{
"portId":"transfer",
"channelId":"channel-126",
"sequence":"102",
"data":"pi3qUxhzyDrgmrTHMu+9AW3vEsGBl1W6YUsEgi/UCwo="
},
{
"portId":"transfer",
"channelId":"channel-126",
"sequence":"103",
"data":"eDSZipO0vWlCEzM5sS2DNL254KBMSMH5JZn0u5ccIIs="
}
],
"pagination":{
"nextKey":"LzEwNA==",
"total":"0"
},
"height":{
"revisionNumber":"888",
"revisionHeight":"26836728"
}
}
Parameter | Type | Description |
---|---|---|
commitments | PacketState Array | Commitments information |
pagination | PageResponse | Pagination information in the response |
height | Height | Query block height |
PacketState
Parameter | Type | Description |
---|---|---|
port_id | String | Port identifier |
channel_id | String | Channel identifier |
sequence | Integer | Packet sequence |
data | Byte Array | Embedded data that represents packet state |
PageResponse
Parameter | Type | Description |
---|---|---|
next_key | Byte Array | The key to be passed to PageRequest.key to query the next page most efficiently. It will be empty if there are no more results. |
total | Integer | Total number of results available if PageRequest.count_total was set, its value is undefined otherwise |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
PacketReceipt
Queries if a given packet sequence has been received on the queried chain
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
port_id = "transfer"
channel_id = "channel-126"
sequence = 1
receipt = await client.fetch_ibc_packet_receipt(port_id=port_id, channel_id=channel_id, sequence=sequence)
print(receipt)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
portId := "transfer"
channelId := "channel-126"
sequence := uint64(1)
ctx := context.Background()
res, err := chainClient.FetchIBCPacketReceipt(ctx, portId, channelId, sequence)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
port_id | String | Port unique identifier | Yes |
channel_id | String | Channel unique identifier | Yes |
sequence | Integer | Packet sequence | Yes |
Response Parameters
Response Example:
{
"received":true,
"proofHeight":{
"revisionNumber":"888",
"revisionHeight":"27058834"
},
"proof":""
}
Parameter | Type | Description |
---|---|---|
received | Boolean | Success flag to mark if the receipt exists |
proof | Byte Array | Merkle proof of existence |
proof_height | Height | Height at which the proof was retrieved |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
PacketAcknowledgement
Queries a stored packet acknowledgement hash
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
port_id = "transfer"
channel_id = "channel-126"
sequence = 1
acknowledgement = await client.fetch_ibc_packet_acknowledgement(
port_id=port_id, channel_id=channel_id, sequence=sequence
)
print(acknowledgement)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
portId := "transfer"
channelId := "channel-126"
sequence := uint64(1)
ctx := context.Background()
res, err := chainClient.FetchIBCPacketAcknowledgement(ctx, portId, channelId, sequence)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
port_id | String | Port unique identifier | Yes |
channel_id | String | Channel unique identifier | Yes |
sequence | Integer | Packet sequence | Yes |
Response Parameters
Response Example:
{
"acknowledgement":"CPdVftUYJv4Y2EUSvyTsdQAe268hI6R333KgqfNkCnw=",
"proofHeight":{
"revisionNumber":"888",
"revisionHeight":"27065978"
},
"proof":""
}
Parameter | Type | Description |
---|---|---|
acknowledgement | Byte Array | Success flag to mark if the receipt exists |
proof | Byte Array | Merkle proof of existence |
proof_height | Height | Height at which the proof was retrieved |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
PacketAcknowledgements
Returns all the packet acknowledgements associated with a channel
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
port_id = "transfer"
channel_id = "channel-126"
sequences = [1, 2]
pagination = PaginationOption(skip=2, limit=4)
acknowledgements = await client.fetch_ibc_packet_acknowledgements(
port_id=port_id,
channel_id=channel_id,
packet_commitment_sequences=sequences,
pagination=pagination,
)
print(acknowledgements)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
portId := "transfer"
channelId := "channel-126"
sequences := []uint64{1, 2}
pagination := query.PageRequest{Offset: 2, Limit: 4}
ctx := context.Background()
res, err := chainClient.FetchIBCPacketAcknowledgements(ctx, portId, channelId, sequences, &pagination)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
port_id | String | Port unique identifier | Yes |
channel_id | String | Channel unique identifier | Yes |
pagination | PageRequest | The optional pagination for the request | No |
packet_commitment_sequences | Integer Array | List of packet sequences | No |
PageRequest
Parameter | Type | Description | Required |
---|---|---|---|
key | Byte Array | Key is a value returned in PageResponse.next_key to begin querying the next page most efficiently. Only one of offset or key should be set | No |
offset | Integer | Numeric offset that can be used when key is unavailable. It is less efficient than using key. Only one of offset or key should be set | No |
limit | Integer | Total number of results to be returned in the result page | No |
count_total | Boolean | Set to true to indicate that the result set should include a count of the total number of items available for pagination in UIs. It is only respected when offset is used. It is ignored when key is set | No |
reverse | Boolean | Reverse is set to true if results are to be returned in the descending order | No |
Response Parameters
Response Example:
{
"acknowledgements":[
{
"portId":"transfer",
"channelId":"channel-126",
"sequence":"1",
"data":"CPdVftUYJv4Y2EUSvyTsdQAe268hI6R333KgqfNkCnw="
},
{
"portId":"transfer",
"channelId":"channel-126",
"sequence":"2",
"data":"CPdVftUYJv4Y2EUSvyTsdQAe268hI6R333KgqfNkCnw="
}
],
"height":{
"revisionNumber":"888",
"revisionHeight":"27066401"
}
}
Parameter | Type | Description |
---|---|---|
acknowledgements | PacketState Array | Acknowledgements details |
pagination | PageResponse | Pagination information in the response |
height | Height | Query block height |
PacketState
Parameter | Type | Description |
---|---|---|
port_id | String | Port identifier |
channel_id | String | Channel identifier |
sequence | Integer | Packet sequence |
data | Byte Array | Embedded data that represents packet state |
PageResponse
Parameter | Type | Description |
---|---|---|
next_key | Byte Array | The key to be passed to PageRequest.key to query the next page most efficiently. It will be empty if there are no more results. |
total | Integer | Total number of results available if PageRequest.count_total was set, its value is undefined otherwise |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
UnreceivedPackets
Returns all the unreceived IBC packets associated with a channel and sequences
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
port_id = "transfer"
channel_id = "channel-126"
sequences = [1, 2]
packets = await client.fetch_ibc_unreceived_packets(
port_id=port_id, channel_id=channel_id, packet_commitment_sequences=sequences
)
print(packets)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
portId := "transfer"
channelId := "channel-126"
sequences := []uint64{1, 2}
ctx := context.Background()
res, err := chainClient.FetchIBCUnreceivedPackets(ctx, portId, channelId, sequences)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
port_id | String | Port unique identifier | Yes |
channel_id | String | Channel unique identifier | Yes |
packet_commitment_sequences | Integer Array | List of packet sequences | No |
Response Parameters
Response Example:
{
"height":{
"revisionNumber":"888",
"revisionHeight":"27067282"
},
"sequences":[
]
}
Parameter | Type | Description |
---|---|---|
sequences | Integer Array | List of unreceived packet sequences |
height | Height | Query block height |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
UnreceivedAcks
Returns all the unreceived IBC acknowledgements associated with a channel and sequences
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
port_id = "transfer"
channel_id = "channel-126"
acks = await client.fetch_ibc_unreceived_acks(
port_id=port_id,
channel_id=channel_id,
)
print(acks)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
portId := "transfer"
channelId := "channel-126"
sequences := []uint64{1, 2}
ctx := context.Background()
res, err := chainClient.FetchIBCUnreceivedAcks(ctx, portId, channelId, sequences)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
port_id | String | Port unique identifier | Yes |
channel_id | String | Channel unique identifier | Yes |
packet_ack_sequences | Integer Array | List of acknowledgement sequences | No |
Response Parameters
Response Example:
{
"height":{
"revisionNumber":"888",
"revisionHeight":"27067653"
},
"sequences":[
]
}
Parameter | Type | Description |
---|---|---|
sequences | Integer Array | List of unreceived packet sequences |
height | Height | Query block height |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
NextSequenceReceive
Returns the next receive sequence for a given channel
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
port_id = "transfer"
channel_id = "channel-126"
sequence = await client.fetch_next_sequence_receive(
port_id=port_id,
channel_id=channel_id,
)
print(sequence)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
portId := "transfer"
channelId := "channel-126"
ctx := context.Background()
res, err := chainClient.FetchIBCNextSequenceReceive(ctx, portId, channelId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
port_id | String | Port unique identifier | Yes |
channel_id | String | Channel unique identifier | Yes |
Response Parameters
Response Example:
{
"nextSequenceReceive":"1",
"proofHeight":{
"revisionNumber":"888",
"revisionHeight":"27067952"
},
"proof":""
}
Parameter | Type | Description |
---|---|---|
next_sequence_receive | Integer | Next sequence receive number |
proof | Byte Array | Merkle proof of existence |
proof_height | Height | Height at which the proof was retrieved |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
- IBC Core Client
Includes all the messages and queries associated to clients and consensus from the IBC core client module
ClientState
Queries an IBC light client
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
client_id = "07-tendermint-0"
state = await client.fetch_ibc_client_state(client_id=client_id)
print(state)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
clientId := "07-tendermint-0"
ctx := context.Background()
res, err := chainClient.FetchIBCClientState(ctx, clientId)
if err != nil {
fmt.Println(err)
}
fmt.Print(res)
}
Parameter | Type | Description | Required |
---|---|---|---|
client_id | String | Client state unique identifier | Yes |
Response Parameters
Response Example:
{
"clientState":{
"@type":"/ibc.lightclients.tendermint.v1.ClientState",
"chainId":"band-laozi-testnet4",
"trustLevel":{
"numerator":"1",
"denominator":"3"
},
"trustingPeriod":"1209600s",
"unbondingPeriod":"1814400s",
"maxClockDrift":"20s",
"frozenHeight":{
"revisionNumber":"0",
"revisionHeight":"0"
},
"latestHeight":{
"revisionHeight":"7379538",
"revisionNumber":"0"
},
"proofSpecs":[
{
"leafSpec":{
"hash":"SHA256",
"prehashValue":"SHA256",
"length":"VAR_PROTO",
"prefix":"AA==",
"prehashKey":"NO_HASH"
},
"innerSpec":{
"childOrder":[
0,
1
],
"childSize":33,
"minPrefixLength":4,
"maxPrefixLength":12,
"hash":"SHA256",
"emptyChild":""
},
"maxDepth":0,
"minDepth":0,
"prehashKeyBeforeComparison":false
},
{
"leafSpec":{
"hash":"SHA256",
"prehashValue":"SHA256",
"length":"VAR_PROTO",
"prefix":"AA==",
"prehashKey":"NO_HASH"
},
"innerSpec":{
"childOrder":[
0,
1
],
"childSize":32,
"minPrefixLength":1,
"maxPrefixLength":1,
"hash":"SHA256",
"emptyChild":""
},
"maxDepth":0,
"minDepth":0,
"prehashKeyBeforeComparison":false
}
],
"upgradePath":[
"upgrade",
"upgradedIBCState"
],
"allowUpdateAfterExpiry":true,
"allowUpdateAfterMisbehaviour":true
},
"proofHeight":{
"revisionNumber":"888",
"revisionHeight":"27527237"
},
"proof":""
}
Parameter | Type | Description |
---|---|---|
client_state | Any | Client state associated with the request identifier |
proof | Byte Array | Merkle proof of existence |
proof_height | Height | Height at which the proof was retrieved |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
ClientStates
Queries all the IBC light clients of a chain
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
pagination = PaginationOption(skip=2, limit=4)
states = await client.fetch_ibc_client_states(pagination=pagination)
print(states)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
pagination := query.PageRequest{Offset: 2, Limit: 4}
ctx := context.Background()
res, err := chainClient.FetchIBCClientStates(ctx, &pagination)
if err != nil {
fmt.Println(err)
}
fmt.Print(res)
}
Parameter | Type | Description | Required |
---|---|---|---|
pagination | PageRequest | The optional pagination for the request | No |
Response Parameters
Response Example:
{
"clientStates":[
{
"clientId":"07-tendermint-0",
"clientState":{
"@type":"/ibc.lightclients.tendermint.v1.ClientState",
"chainId":"band-laozi-testnet4",
"trustLevel":{
"numerator":"1",
"denominator":"3"
},
"trustingPeriod":"1209600s",
"unbondingPeriod":"1814400s",
"maxClockDrift":"20s",
"frozenHeight":{
"revisionNumber":"0",
"revisionHeight":"0"
},
"latestHeight":{
"revisionHeight":"7379538",
"revisionNumber":"0"
},
"proofSpecs":[
{
"leafSpec":{
"hash":"SHA256",
"prehashValue":"SHA256",
"length":"VAR_PROTO",
"prefix":"AA==",
"prehashKey":"NO_HASH"
},
"innerSpec":{
"childOrder":[
0,
1
],
"childSize":33,
"minPrefixLength":4,
"maxPrefixLength":12,
"hash":"SHA256",
"emptyChild":""
},
"maxDepth":0,
"minDepth":0,
"prehashKeyBeforeComparison":false
},
{
"leafSpec":{
"hash":"SHA256",
"prehashValue":"SHA256",
"length":"VAR_PROTO",
"prefix":"AA==",
"prehashKey":"NO_HASH"
},
"innerSpec":{
"childOrder":[
0,
1
],
"childSize":32,
"minPrefixLength":1,
"maxPrefixLength":1,
"hash":"SHA256",
"emptyChild":""
},
"maxDepth":0,
"minDepth":0,
"prehashKeyBeforeComparison":false
}
],
"upgradePath":[
"upgrade",
"upgradedIBCState"
],
"allowUpdateAfterExpiry":true,
"allowUpdateAfterMisbehaviour":true
}
},
{
"clientId":"07-tendermint-1",
"clientState":{
"@type":"/ibc.lightclients.tendermint.v1.ClientState",
"chainId":"band-laozi-testnet4",
"trustLevel":{
"numerator":"1",
"denominator":"3"
},
"trustingPeriod":"1209600s",
"unbondingPeriod":"1814400s",
"maxClockDrift":"20s",
"frozenHeight":{
"revisionNumber":"0",
"revisionHeight":"0"
},
"latestHeight":{
"revisionHeight":"7692651",
"revisionNumber":"0"
},
"proofSpecs":[
{
"leafSpec":{
"hash":"SHA256",
"prehashValue":"SHA256",
"length":"VAR_PROTO",
"prefix":"AA==",
"prehashKey":"NO_HASH"
},
"innerSpec":{
"childOrder":[
0,
1
],
"childSize":33,
"minPrefixLength":4,
"maxPrefixLength":12,
"hash":"SHA256",
"emptyChild":""
},
"maxDepth":0,
"minDepth":0,
"prehashKeyBeforeComparison":false
},
{
"leafSpec":{
"hash":"SHA256",
"prehashValue":"SHA256",
"length":"VAR_PROTO",
"prefix":"AA==",
"prehashKey":"NO_HASH"
},
"innerSpec":{
"childOrder":[
0,
1
],
"childSize":32,
"minPrefixLength":1,
"maxPrefixLength":1,
"hash":"SHA256",
"emptyChild":""
},
"maxDepth":0,
"minDepth":0,
"prehashKeyBeforeComparison":false
}
],
"upgradePath":[
"upgrade",
"upgradedIBCState"
],
"allowUpdateAfterExpiry":true,
"allowUpdateAfterMisbehaviour":true
}
},
{
"clientId":"07-tendermint-10",
"clientState":{
"@type":"/ibc.lightclients.tendermint.v1.ClientState",
"chainId":"pisco-1",
"trustLevel":{
"numerator":"1",
"denominator":"3"
},
"trustingPeriod":"345600s",
"unbondingPeriod":"432000s",
"maxClockDrift":"50s",
"frozenHeight":{
"revisionNumber":"0",
"revisionHeight":"0"
},
"latestHeight":{
"revisionNumber":"1",
"revisionHeight":"2304261"
},
"proofSpecs":[
{
"leafSpec":{
"hash":"SHA256",
"prehashValue":"SHA256",
"length":"VAR_PROTO",
"prefix":"AA==",
"prehashKey":"NO_HASH"
},
"innerSpec":{
"childOrder":[
0,
1
],
"childSize":33,
"minPrefixLength":4,
"maxPrefixLength":12,
"hash":"SHA256",
"emptyChild":""
},
"maxDepth":0,
"minDepth":0,
"prehashKeyBeforeComparison":false
},
{
"leafSpec":{
"hash":"SHA256",
"prehashValue":"SHA256",
"length":"VAR_PROTO",
"prefix":"AA==",
"prehashKey":"NO_HASH"
},
"innerSpec":{
"childOrder":[
0,
1
],
"childSize":32,
"minPrefixLength":1,
"maxPrefixLength":1,
"hash":"SHA256",
"emptyChild":""
},
"maxDepth":0,
"minDepth":0,
"prehashKeyBeforeComparison":false
}
],
"upgradePath":[
"upgrade",
"upgradedIBCState"
],
"allowUpdateAfterExpiry":true,
"allowUpdateAfterMisbehaviour":true
}
},
{
"clientId":"07-tendermint-100",
"clientState":{
"@type":"/ibc.lightclients.tendermint.v1.ClientState",
"chainId":"osmo-test-4",
"trustLevel":{
"numerator":"1",
"denominator":"3"
},
"trustingPeriod":"806400s",
"unbondingPeriod":"1209600s",
"maxClockDrift":"20s",
"frozenHeight":{
"revisionNumber":"0",
"revisionHeight":"0"
},
"latestHeight":{
"revisionNumber":"4",
"revisionHeight":"10356505"
},
"proofSpecs":[
{
"leafSpec":{
"hash":"SHA256",
"prehashValue":"SHA256",
"length":"VAR_PROTO",
"prefix":"AA==",
"prehashKey":"NO_HASH"
},
"innerSpec":{
"childOrder":[
0,
1
],
"childSize":33,
"minPrefixLength":4,
"maxPrefixLength":12,
"hash":"SHA256",
"emptyChild":""
},
"maxDepth":0,
"minDepth":0,
"prehashKeyBeforeComparison":false
},
{
"leafSpec":{
"hash":"SHA256",
"prehashValue":"SHA256",
"length":"VAR_PROTO",
"prefix":"AA==",
"prehashKey":"NO_HASH"
},
"innerSpec":{
"childOrder":[
0,
1
],
"childSize":32,
"minPrefixLength":1,
"maxPrefixLength":1,
"hash":"SHA256",
"emptyChild":""
},
"maxDepth":0,
"minDepth":0,
"prehashKeyBeforeComparison":false
}
],
"upgradePath":[
"upgrade",
"upgradedIBCState"
],
"allowUpdateAfterExpiry":true,
"allowUpdateAfterMisbehaviour":true
}
},
{
"clientId":"07-tendermint-101",
"clientState":{
"@type":"/ibc.lightclients.tendermint.v1.ClientState",
"chainId":"osmo-test-4",
"trustLevel":{
"numerator":"1",
"denominator":"3"
},
"trustingPeriod":"806400s",
"unbondingPeriod":"1209600s",
"maxClockDrift":"20s",
"frozenHeight":{
"revisionNumber":"0",
"revisionHeight":"0"
},
"latestHeight":{
"revisionNumber":"4",
"revisionHeight":"10356847"
},
"proofSpecs":[
{
"leafSpec":{
"hash":"SHA256",
"prehashValue":"SHA256",
"length":"VAR_PROTO",
"prefix":"AA==",
"prehashKey":"NO_HASH"
},
"innerSpec":{
"childOrder":[
0,
1
],
"childSize":33,
"minPrefixLength":4,
"maxPrefixLength":12,
"hash":"SHA256",
"emptyChild":""
},
"maxDepth":0,
"minDepth":0,
"prehashKeyBeforeComparison":false
},
{
"leafSpec":{
"hash":"SHA256",
"prehashValue":"SHA256",
"length":"VAR_PROTO",
"prefix":"AA==",
"prehashKey":"NO_HASH"
},
"innerSpec":{
"childOrder":[
0,
1
],
"childSize":32,
"minPrefixLength":1,
"maxPrefixLength":1,
"hash":"SHA256",
"emptyChild":""
},
"maxDepth":0,
"minDepth":0,
"prehashKeyBeforeComparison":false
}
],
"upgradePath":[
"upgrade",
"upgradedIBCState"
],
"allowUpdateAfterExpiry":true,
"allowUpdateAfterMisbehaviour":true
}
},
{
"clientId":"07-tendermint-102",
"clientState":{
"@type":"/ibc.lightclients.tendermint.v1.ClientState",
"chainId":"osmo-test-4",
"trustLevel":{
"numerator":"1",
"denominator":"3"
},
"trustingPeriod":"806400s",
"unbondingPeriod":"1209600s",
"maxClockDrift":"20s",
"frozenHeight":{
"revisionNumber":"0",
"revisionHeight":"0"
},
"latestHeight":{
"revisionNumber":"4",
"revisionHeight":"10357322"
},
"proofSpecs":[
{
"leafSpec":{
"hash":"SHA256",
"prehashValue":"SHA256",
"length":"VAR_PROTO",
"prefix":"AA==",
"prehashKey":"NO_HASH"
},
"innerSpec":{
"childOrder":[
0,
1
],
"childSize":33,
"minPrefixLength":4,
"maxPrefixLength":12,
"hash":"SHA256",
"emptyChild":""
},
"maxDepth":0,
"minDepth":0,
"prehashKeyBeforeComparison":false
},
{
"leafSpec":{
"hash":"SHA256",
"prehashValue":"SHA256",
"length":"VAR_PROTO",
"prefix":"AA==",
"prehashKey":"NO_HASH"
},
"innerSpec":{
"childOrder":[
0,
1
],
"childSize":32,
"minPrefixLength":1,
"maxPrefixLength":1,
"hash":"SHA256",
"emptyChild":""
},
"maxDepth":0,
"minDepth":0,
"prehashKeyBeforeComparison":false
}
],
"upgradePath":[
"upgrade",
"upgradedIBCState"
],
"allowUpdateAfterExpiry":true,
"allowUpdateAfterMisbehaviour":true
}
},
{
"clientId":"07-tendermint-103",
"clientState":{
"@type":"/ibc.lightclients.tendermint.v1.ClientState",
"chainId":"galileo-3",
"trustLevel":{
"numerator":"1",
"denominator":"3"
},
"trustingPeriod":"604800s",
"unbondingPeriod":"1814400s",
"maxClockDrift":"30s",
"frozenHeight":{
"revisionNumber":"0",
"revisionHeight":"0"
},
"latestHeight":{
"revisionNumber":"3",
"revisionHeight":"2848767"
},
"proofSpecs":[
{
"leafSpec":{
"hash":"SHA256",
"prehashValue":"SHA256",
"length":"VAR_PROTO",
"prefix":"AA==",
"prehashKey":"NO_HASH"
},
"innerSpec":{
"childOrder":[
0,
1
],
"childSize":33,
"minPrefixLength":4,
"maxPrefixLength":12,
"hash":"SHA256",
"emptyChild":""
},
"maxDepth":0,
"minDepth":0,
"prehashKeyBeforeComparison":false
},
{
"leafSpec":{
"hash":"SHA256",
"prehashValue":"SHA256",
"length":"VAR_PROTO",
"prefix":"AA==",
"prehashKey":"NO_HASH"
},
"innerSpec":{
"childOrder":[
0,
1
],
"childSize":32,
"minPrefixLength":1,
"maxPrefixLength":1,
"hash":"SHA256",
"emptyChild":""
},
"maxDepth":0,
"minDepth":0,
"prehashKeyBeforeComparison":false
}
],
"upgradePath":[
"upgrade",
"upgradedIBCState"
],
"allowUpdateAfterExpiry":true,
"allowUpdateAfterMisbehaviour":true
}
}
],
"pagination":{
"nextKey":"LzA3LXRlbmRlcm1pbnQtMTAzL2NsaWVudFN0YXRl",
"total":"0"
}
}
Parameter | Type | Description |
---|---|---|
client_states | IdentifiedClientState Array | Client state associated with the request identifier |
pagination | PageResponse | Pagination information in the response |
IdentifiedClientState
Parameter | Type | Description |
---|---|---|
client_id | String | Client identifier |
client_state | Any | Client state |
ConsensusState
Queries a consensus state associated with a client state at a given height
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
client_id = "07-tendermint-0"
revision_number = 0
revision_height = 7379538
state = await client.fetch_ibc_consensus_state(
client_id=client_id, revision_number=revision_number, revision_height=revision_height
)
print(state)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
clientId := "07-tendermint-0"
revisionNumber := uint64(0)
revisionHeight := uint64(7379538)
latestHeight := false
ctx := context.Background()
res, err := chainClient.FetchIBCConsensusState(ctx, clientId, revisionNumber, revisionHeight, latestHeight)
if err != nil {
fmt.Println(err)
}
fmt.Print(res)
}
Parameter | Type | Description | Required |
---|---|---|---|
client_id | String | Client identifier | Yes |
revision_number | Integer | Consensus state revision number | Yes |
client_id | Integer | Consensus state revision height | Yes |
latest_height | Boolean | Overrrides the height field and queries the latest stored ConsensusState | No |
Response Parameters
Response Example:
{
"consensusState":{
"@type":"/ibc.lightclients.tendermint.v1.ConsensusState",
"timestamp":"2022-07-04T10:34:53.874345276Z",
"root":{
"hash":"viI6JuzZ/kOAh6jIeecglN7Xt+mGQT/PpvAGqGLcVmM="
},
"nextValidatorsHash":"olPEfP4dzPCC07Oyg/3+6U5/uumw/HmELk2MwpMogSg="
},
"proofHeight":{
"revisionNumber":"888",
"revisionHeight":"27531028"
},
"proof":""
}
Parameter | Type | Description |
---|---|---|
consensus_state | Any | Client state associated with the request identifier |
proof | Byte Array | Merkle proof of existence |
proof_height | Height | Height at which the proof was retrieved |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
ConsensusStates
Queries all the consensus state associated with a given client
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
client_id = "07-tendermint-0"
pagination = PaginationOption(skip=2, limit=4)
states = await client.fetch_ibc_consensus_states(client_id=client_id, pagination=pagination)
print(states)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
clientId := "07-tendermint-0"
pagination := query.PageRequest{Offset: 2, Limit: 4}
ctx := context.Background()
res, err := chainClient.FetchIBCConsensusStates(ctx, clientId, &pagination)
if err != nil {
fmt.Println(err)
}
fmt.Print(res)
}
Parameter | Type | Description | Required |
---|---|---|---|
client_id | String | Client identifier | Yes |
pagination | PageRequest | The optional pagination for the request | No |
Response Parameters
Response Example:
{
"consensusStates":[
{
"height":{
"revisionHeight":"7379500",
"revisionNumber":"0"
},
"consensusState":{
"@type":"/ibc.lightclients.tendermint.v1.ConsensusState",
"timestamp":"2022-07-04T10:32:23.232327085Z",
"root":{
"hash":"PlwKOemX6GQh/sGlPzvT89sRijeZa0pUK+sjvASu/5s="
},
"nextValidatorsHash":"olPEfP4dzPCC07Oyg/3+6U5/uumw/HmELk2MwpMogSg="
}
},
{
"height":{
"revisionHeight":"7379506",
"revisionNumber":"0"
},
"consensusState":{
"@type":"/ibc.lightclients.tendermint.v1.ConsensusState",
"timestamp":"2022-07-04T10:32:46.188675417Z",
"root":{
"hash":"LTmLr8YzxO/yfajKO1RrnZeTK3JUMrvYcm/IZyi0XeY="
},
"nextValidatorsHash":"olPEfP4dzPCC07Oyg/3+6U5/uumw/HmELk2MwpMogSg="
}
},
{
"height":{
"revisionHeight":"7379521",
"revisionNumber":"0"
},
"consensusState":{
"@type":"/ibc.lightclients.tendermint.v1.ConsensusState",
"timestamp":"2022-07-04T10:33:46.953207174Z",
"root":{
"hash":"lyXb+gmcyDOcHL35Zppqv10y0irbqlnsllERaOEb9R4="
},
"nextValidatorsHash":"olPEfP4dzPCC07Oyg/3+6U5/uumw/HmELk2MwpMogSg="
}
},
{
"height":{
"revisionHeight":"7379538",
"revisionNumber":"0"
},
"consensusState":{
"@type":"/ibc.lightclients.tendermint.v1.ConsensusState",
"timestamp":"2022-07-04T10:34:53.874345276Z",
"root":{
"hash":"viI6JuzZ/kOAh6jIeecglN7Xt+mGQT/PpvAGqGLcVmM="
},
"nextValidatorsHash":"olPEfP4dzPCC07Oyg/3+6U5/uumw/HmELk2MwpMogSg="
}
}
],
"pagination":{
"nextKey":"",
"total":"0"
}
}
Parameter | Type | Description |
---|---|---|
consensus_states | ConsensusStateWithHeight Array | Consensus states associated with the identifier |
pagination | PageResponse | Pagination information in the response |
ConsensusStateWithHeight
Parameter | Type | Description |
---|---|---|
height | Height | Consensus state height |
consensus_state | Any | Consensus state |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
ConsensusStateHeights
Queries the height of every consensus states associated with a given client
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
client_id = "07-tendermint-0"
pagination = PaginationOption(skip=2, limit=4)
states = await client.fetch_ibc_consensus_state_heights(client_id=client_id, pagination=pagination)
print(states)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
clientId := "07-tendermint-0"
pagination := query.PageRequest{Offset: 2, Limit: 4}
ctx := context.Background()
res, err := chainClient.FetchIBCConsensusStateHeights(ctx, clientId, &pagination)
if err != nil {
fmt.Println(err)
}
fmt.Print(res)
}
Parameter | Type | Description | Required |
---|---|---|---|
client_id | String | Client identifier | Yes |
pagination | PageRequest | The optional pagination for the request | No |
Response Parameters
Response Example:
{
"consensusStateHeights":[
{
"revisionHeight":"7379500",
"revisionNumber":"0"
},
{
"revisionHeight":"7379506",
"revisionNumber":"0"
},
{
"revisionHeight":"7379521",
"revisionNumber":"0"
},
{
"revisionHeight":"7379538",
"revisionNumber":"0"
}
],
"pagination":{
"nextKey":"",
"total":"0"
}
}
Parameter | Type | Description |
---|---|---|
consensus_state_heights | Height Array | Consensus state heights |
pagination | PageResponse | Pagination information in the response |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
ClientStatus
Queries the status of an IBC client
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
client_id = "07-tendermint-0"
state = await client.fetch_ibc_client_status(client_id=client_id)
print(state)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
clientId := "07-tendermint-0"
ctx := context.Background()
res, err := chainClient.FetchIBCClientStatus(ctx, clientId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
client_id | String | Client unique identifier | Yes |
Response Parameters
Response Example:
{
"status":"Expired"
}
Parameter | Type | Description |
---|---|---|
status | String | Client status |
ClientParams
Queries all parameters of the ibc client submodule
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
params = await client.fetch_ibc_client_params()
print(params)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchIBCClientParams(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
No parameters
Response Parameters
Response Example:
{
"params":{
"allowedClients":[
"06-solomachine",
"07-tendermint"
]
}
}
Parameter | Type | Description |
---|---|---|
params | params | Module's parameters |
Params
Parameter | Type | Description |
---|---|---|
allowed_clients | String Array | Allowed_clients defines the list of allowed client state types which can be created and interacted with. If a client type is removed from the allowed clients list, usage of this client will be disabled until it is added again to the list |
UpgradedClientState
Queries an Upgraded IBC light client
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
state = await client.fetch_ibc_upgraded_client_state()
print(state)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchIBCUpgradedClientState(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
No parameters
Response Parameters
Response Example:
Parameter | Type | Description |
---|---|---|
upgraded_client_state | Any | Client state associated with the request identifier |
UpgradedConsensusState
Queries an Upgraded IBC consensus state
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
state = await client.fetch_ibc_upgraded_consensus_state()
print(state)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchIBCUpgradedConsensusState(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
No parameters
Response Parameters
Response Example:
Parameter | Type | Description |
---|---|---|
upgraded_consensus_state | Any | Consensus state associated with the request identifier |
- IBC Core Connection
Includes all the messages and queries associated to connections from the IBC core connection module
Connection
Queries an IBC connection end
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
connection_id = "connection-0"
connection = await client.fetch_ibc_connection(connection_id=connection_id)
print(connection)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
connectionId := "connection-0"
ctx := context.Background()
res, err := chainClient.FetchIBCConnection(ctx, connectionId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
connection_id | String | Connection unique identifier | Yes |
Response Parameters
Response Example:
{
"connection":{
"clientId":"07-tendermint-0",
"versions":[
{
"identifier":"1",
"features":[
"ORDER_ORDERED",
"ORDER_UNORDERED"
]
}
],
"state":"STATE_OPEN",
"counterparty":{
"clientId":"07-tendermint-904",
"connectionId":"connection-877",
"prefix":{
"keyPrefix":"aWJj"
}
},
"delayPeriod":"0"
},
"proofHeight":{
"revisionNumber":"888",
"revisionHeight":"27778433"
},
"proof":""
}
Parameter | Type | Description |
---|---|---|
connection | ConnectionEnd | Connection associated with the request identifier |
proof | Byte Array | Merkle proof of existence |
proof_height | Height | Height at which the proof was retrieved |
ConnectionEnd
Parameter | Type | Description |
---|---|---|
client_id | String | Client associated with this connection |
versions | Version String | Channel identifier |
state | State | Current state of the connection end |
counterparty | Counterparty | Counterparty chain associated with this connection |
delay_period | Integer | Delay period that must pass before a consensus state can be used for packet-verification NOTE: delay period logic is only implemented by some clients |
Version
Parameter | Type | Description |
---|---|---|
identifier | String | Unique version identifier |
features | String Array | List of features compatible with the specified identifier |
State
Code | Name |
---|---|
0 | STATE_UNINITIALIZED_UNSPECIFIED |
1 | STATE_INIT |
2 | STATE_TRYOPEN |
3 | STATE_OPEN |
Counterparty
Parameter | Type | Description |
---|---|---|
client_id | String | Identifies the client on the counterparty chain associated with a given connection |
connection_id | String | Identifies the connection end on the counterparty chain associated with a given connection |
prefix | MarketPrefix | Commitment merkle prefix of the counterparty chain |
MerklePrefix
Parameter | Type | Description |
---|---|---|
key_prefix | Byte Array | Merkle path prefixed to the key |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
Connections
Queries all the IBC connections of a chain
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
pagination = PaginationOption(skip=2, limit=4)
connections = await client.fetch_ibc_connections(pagination=pagination)
print(connections)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
pagination := query.PageRequest{Offset: 2, Limit: 4}
ctx := context.Background()
res, err := chainClient.FetchIBCConnections(ctx, &pagination)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
pagination | PageRequest | The optional pagination for the request | No |
PageRequest
Parameter | Type | Description | Required |
---|---|---|---|
key | Byte Array | Key is a value returned in PageResponse.next_key to begin querying the next page most efficiently. Only one of offset or key should be set | No |
offset | Integer | Numeric offset that can be used when key is unavailable. It is less efficient than using key. Only one of offset or key should be set | No |
limit | Integer | Total number of results to be returned in the result page | No |
count_total | Boolean | Set to true to indicate that the result set should include a count of the total number of items available for pagination in UIs. It is only respected when offset is used. It is ignored when key is set | No |
reverse | Boolean | Reverse is set to true if results are to be returned in the descending order | No |
Response Parameters
Response Example:
{
"connections":[
{
"id":"connection-10",
"clientId":"07-tendermint-12",
"versions":[
{
"identifier":"1",
"features":[
"ORDER_ORDERED",
"ORDER_UNORDERED"
]
}
],
"state":"STATE_OPEN",
"counterparty":{
"clientId":"07-tendermint-103",
"connectionId":"connection-93",
"prefix":{
"keyPrefix":"aWJj"
}
},
"delayPeriod":"0"
},
{
"id":"connection-100",
"clientId":"07-tendermint-126",
"versions":[
{
"identifier":"1",
"features":[
"ORDER_ORDERED",
"ORDER_UNORDERED"
]
}
],
"state":"STATE_OPEN",
"counterparty":{
"clientId":"07-tendermint-168",
"connectionId":"connection-118",
"prefix":{
"keyPrefix":"aWJj"
}
},
"delayPeriod":"0"
},
{
"id":"connection-101",
"clientId":"07-tendermint-127",
"versions":[
{
"identifier":"1",
"features":[
"ORDER_ORDERED",
"ORDER_UNORDERED"
]
}
],
"state":"STATE_OPEN",
"counterparty":{
"clientId":"07-tendermint-3",
"connectionId":"connection-5",
"prefix":{
"keyPrefix":"aWJj"
}
},
"delayPeriod":"0"
},
{
"id":"connection-102",
"clientId":"07-tendermint-128",
"versions":[
{
"identifier":"1",
"features":[
"ORDER_ORDERED",
"ORDER_UNORDERED"
]
}
],
"state":"STATE_OPEN",
"counterparty":{
"clientId":"07-tendermint-633",
"connectionId":"connection-574",
"prefix":{
"keyPrefix":"aWJj"
}
},
"delayPeriod":"0"
}
],
"pagination":{
"nextKey":"L2Nvbm5lY3Rpb24tMTAz",
"total":"0"
},
"height":{
"revisionNumber":"888",
"revisionHeight":"27779944"
}
}
Parameter | Type | Description |
---|---|---|
connections | IdentifiedConnection Array | Connection associated with the request identifier |
pagination | PageResponse | Pagination information in the response |
height | Height | Query block height |
IdentifiedConnection
Parameter | Type | Description |
---|---|---|
id | String | Connection identifier |
client_id | String | Client associated with this connection |
versions | Version String | IBC version which can be utilised to determine encodings or protocols for channels or packets utilising this connection |
state | State | Current state of the connection end |
counterparty | Counterparty | Counterparty chain associated with this connection |
delay_period | Integer | Delay period associated with this connection |
PageResponse
Parameter | Type | Description |
---|---|---|
next_key | Byte Array | The key to be passed to PageRequest.key to query the next page most efficiently. It will be empty if there are no more results. |
total | Integer | Total number of results available if PageRequest.count_total was set, its value is undefined otherwise |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
Version
Parameter | Type | Description |
---|---|---|
identifier | String | Unique version identifier |
features | String Array | List of features compatible with the specified identifier |
State
Code | Name |
---|---|
0 | STATE_UNINITIALIZED_UNSPECIFIED |
1 | STATE_INIT |
2 | STATE_TRYOPEN |
3 | STATE_OPEN |
Counterparty
Parameter | Type | Description |
---|---|---|
client_id | String | Identifies the client on the counterparty chain associated with a given connection |
connection_id | String | Identifies the connection end on the counterparty chain associated with a given connection |
prefix | MarketPrefix | Commitment merkle prefix of the counterparty chain |
MerklePrefix
Parameter | Type | Description |
---|---|---|
key_prefix | Byte Array | Merkle path prefixed to the key |
ClientConnections
Queries the connection paths associated with a client state
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
client_id = "07-tendermint-0"
connections = await client.fetch_ibc_client_connections(client_id=client_id)
print(connections)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
clientId := "07-tendermint-0"
ctx := context.Background()
res, err := chainClient.FetchIBCClientConnections(ctx, clientId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
client_id | String | Client identifier associated with a connection | Yes |
Response Parameters
Response Example:
{
"connectionPaths":[
"connection-0"
],
"proofHeight":{
"revisionNumber":"888",
"revisionHeight":"27783349"
},
"proof":""
}
Parameter | Type | Description |
---|---|---|
connection_paths | String Array | All the connection paths associated with a client |
proof | Byte Array | Merkle proof of existence |
proof_height | Height | Height at which the proof was retrieved |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
ConnectionClientState
Queries the client state associated with the connection
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
connection_id = "connection-0"
state = await client.fetch_ibc_connection_client_state(connection_id=connection_id)
print(state)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
connectionId := "connection-0"
ctx := context.Background()
res, err := chainClient.FetchIBCConnectionClientState(ctx, connectionId)
if err != nil {
fmt.Println(err)
}
fmt.Print(res)
}
Parameter | Type | Description | Required |
---|---|---|---|
connection_id | String | Connection identifier | Yes |
Response Parameters
Response Example:
{
"identifiedClientState":{
"clientId":"07-tendermint-0",
"clientState":{
"@type":"/ibc.lightclients.tendermint.v1.ClientState",
"chainId":"band-laozi-testnet4",
"trustLevel":{
"numerator":"1",
"denominator":"3"
},
"trustingPeriod":"1209600s",
"unbondingPeriod":"1814400s",
"maxClockDrift":"20s",
"frozenHeight":{
"revisionNumber":"0",
"revisionHeight":"0"
},
"latestHeight":{
"revisionHeight":"7379538",
"revisionNumber":"0"
},
"proofSpecs":[
{
"leafSpec":{
"hash":"SHA256",
"prehashValue":"SHA256",
"length":"VAR_PROTO",
"prefix":"AA==",
"prehashKey":"NO_HASH"
},
"innerSpec":{
"childOrder":[
0,
1
],
"childSize":33,
"minPrefixLength":4,
"maxPrefixLength":12,
"hash":"SHA256",
"emptyChild":""
},
"maxDepth":0,
"minDepth":0,
"prehashKeyBeforeComparison":false
},
{
"leafSpec":{
"hash":"SHA256",
"prehashValue":"SHA256",
"length":"VAR_PROTO",
"prefix":"AA==",
"prehashKey":"NO_HASH"
},
"innerSpec":{
"childOrder":[
0,
1
],
"childSize":32,
"minPrefixLength":1,
"maxPrefixLength":1,
"hash":"SHA256",
"emptyChild":""
},
"maxDepth":0,
"minDepth":0,
"prehashKeyBeforeComparison":false
}
],
"upgradePath":[
"upgrade",
"upgradedIBCState"
],
"allowUpdateAfterExpiry":true,
"allowUpdateAfterMisbehaviour":true
}
},
"proofHeight":{
"revisionNumber":"888",
"revisionHeight":"27783852"
},
"proof":""
}
Parameter | Type | Description |
---|---|---|
identified_client_state | IdentifiedClientState | Client state associated with the channel |
proof | Byte Array | Merkle proof of existence |
proof_height | Height | Height at which the proof was retrieved |
IdentifiedClientState
Parameter | Type | Description |
---|---|---|
client_id | String | Client identifier |
client_state | Any | Client state |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
ConnectionConsensusState
Queries the consensus state associated with the connection
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
connection_id = "connection-0"
revision_number = 0
revision_height = 7379538
state = await client.fetch_ibc_connection_consensus_state(
connection_id=connection_id, revision_number=revision_number, revision_height=revision_height
)
print(state)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
connectionId := "connection-0"
revisionNumber := uint64(0)
revisionHeight := uint64(7379538)
ctx := context.Background()
res, err := chainClient.FetchIBCConnectionConsensusState(ctx, connectionId, revisionNumber, revisionHeight)
if err != nil {
fmt.Println(err)
}
fmt.Print(res)
}
Parameter | Type | Description | Required |
---|---|---|---|
connection_id | String | Connection identifier | Yes |
revision_number | Integer | Revision number of the consensus state | Yes |
revision_height | Integer | Revision height of the consensus state | Yes |
Response Parameters
Response Example:
{
"consensusState":{
"@type":"/ibc.lightclients.tendermint.v1.ConsensusState",
"timestamp":"2022-07-04T10:34:53.874345276Z",
"root":{
"hash":"viI6JuzZ/kOAh6jIeecglN7Xt+mGQT/PpvAGqGLcVmM="
},
"nextValidatorsHash":"olPEfP4dzPCC07Oyg/3+6U5/uumw/HmELk2MwpMogSg="
},
"clientId":"07-tendermint-0",
"proofHeight":{
"revisionNumber":"888",
"revisionHeight":"27784841"
},
"proof":""
}
Parameter | Type | Description |
---|---|---|
consensus_state | Any | Consensus state associated with the channel |
client_id | String | Client identifier associated with the consensus state |
proof | Byte Array | Merkle proof of existence |
proof_height | Height | Height at which the proof was retrieved |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
ConnectionParams
Queries all parameters of the ibc connection submodule
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
params = await client.fetch_ibc_connection_params()
print(params)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchIBCConnectionParams(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
No parameters
Response Parameters
Response Example:
{
"params":{
"maxExpectedTimePerBlock":"30000000000"
}
}
Parameter | Type | Description |
---|---|---|
params | Params | Module's parameters |
Params
Parameter | Type | Description |
---|---|---|
max_expected_time_per_block | Integer | Maximum expected time per block (in nanoseconds), used to enforce block delay. This parameter should reflect the largest amount of time that the chain might reasonably take to produce the next block under normal operating conditions. A safe choice is 3-5x the expected time per block |
- IBC Transfer
Includes all the messages and queries associated to transfers from the IBC transfer module
DenomTrace
Queries a denomination trace information
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from hashlib import sha256
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
path = "transfer/channel-126"
base_denom = "uluna"
full_path = f"{path}/{base_denom}"
path_hash = sha256(full_path.encode()).hexdigest()
trace_hash = f"ibc/{path_hash}"
denom_trace = await client.fetch_denom_trace(hash=trace_hash)
print(denom_trace)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
denomTrace := types.DenomTrace{
Path: "transfer/channel-126",
BaseDenom: "uluna",
}
ctx := context.Background()
res, err := chainClient.FetchDenomTrace(ctx, denomTrace.Hash().String())
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
hash | String | The denom trace hash | Yes |
Response Parameters
Response Example:
{
"denomTrace":{
"path":"transfer/channel-126",
"baseDenom":"uluna"
}
}
Parameter | Type | Description |
---|---|---|
denom_trace | DenomTrace | Denom trace information |
DenomTrace
Parameter | Type | Description |
---|---|---|
path | String | Path is the port and channel |
base_denom | String | The token denom |
DenomTraces
Queries all denomination traces
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
pagination = PaginationOption(skip=2, limit=4)
denom_traces = await client.fetch_denom_traces(pagination=pagination)
print(denom_traces)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/cosmos/cosmos-sdk/types/query"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
pagination := query.PageRequest{Offset: 2, Limit: 4}
ctx := context.Background()
res, err := chainClient.FetchDenomTraces(ctx, &pagination)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
pagination | PageRequest | The optional pagination for the request | No |
PageRequest
Parameter | Type | Description | Required |
---|---|---|---|
key | Byte Array | Key is a value returned in PageResponse.next_key to begin querying the next page most efficiently. Only one of offset or key should be set | No |
offset | Integer | Numeric offset that can be used when key is unavailable. It is less efficient than using key. Only one of offset or key should be set | No |
limit | Integer | Total number of results to be returned in the result page | No |
count_total | Boolean | Set to true to indicate that the result set should include a count of the total number of items available for pagination in UIs. It is only respected when offset is used. It is ignored when key is set | No |
reverse | Boolean | Reverse is set to true if results are to be returned in the descending order | No |
Response Parameters
Response Example:
{
"denomTraces":[
{
"path":"transfer/channel-160",
"baseDenom":"uatom"
},
{
"path":"transfer/channel-2",
"baseDenom":"uphoton"
},
{
"path":"transfer/channel-43",
"baseDenom":"uandr"
},
{
"path":"transfer/channel-6",
"baseDenom":"cw20:terra167dsqkh2alurx997wmycw9ydkyu54gyswe3ygmrs4lwume3vmwks8ruqnv"
}
],
"pagination":{
"nextKey":"WZNnsWM6uaj4vFpbpqm1M+3mVbhdRvmgClPl/2jiXlc=",
"total":"0"
}
}
Parameter | Type | Description |
---|---|---|
denom_traces | DenomTrace Array | Denom traces information |
pagination | PageResponse | Pagination information in the response |
PageResponse
Parameter | Type | Description |
---|---|---|
next_key | Byte Array | The key to be passed to PageRequest.key to query the next page most efficiently. It will be empty if there are no more results. |
total | Integer | Total number of results available if PageRequest.count_total was set, its value is undefined otherwise |
DenomHash
Queries a denomination hash information
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
path = "transfer/channel-126"
base_denom = "uluna"
full_path = f"{path}/{base_denom}"
denom_hash = await client.fetch_denom_hash(trace=full_path)
print(denom_hash)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
path := "transfer/channel-126"
baseDenom := "uluna"
fullPath := fmt.Sprintf("%s/%s", path, baseDenom)
ctx := context.Background()
res, err := chainClient.FetchDenomHash(ctx, fullPath)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
trace | String | The denomination trace ([port_id]/[channel_id])+/[denom] | Yes |
Response Parameters
Response Example:
{
"hash":"97498452BF27CC90656FD7D6EFDA287FA2BFFFF3E84691C84CB9E0451F6DF0A4"
}
Parameter | Type | Description |
---|---|---|
hash | String | Hash (in hex format) of the denomination trace information |
EscrowAddress
Returns the escrow address for a particular port and channel id
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
port_id = "transfer"
channel_id = "channel-126"
escrow_address = await client.fetch_escrow_address(port_id=port_id, channel_id=channel_id)
print(escrow_address)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
portId := "transfer"
channelId := "channel-126"
ctx := context.Background()
res, err := chainClient.FetchEscrowAddress(ctx, portId, channelId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
port_id | String | The unique port identifier | Yes |
channel_id | String | The unique channel identifier | Yes |
Response Parameters
Response Example:
{
"escrowAddress":"inj1w8ent9jwwqy2d5s8grq6muk2hqa6kj2863m3mg"
}
Parameter | Type | Description |
---|---|---|
escrow_address | String | The escrow account address |
TotalEscrowForDenom
Returns the total amount of tokens in escrow based on the denom
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
base_denom = "uluna"
escrow = await client.fetch_total_escrow_for_denom(denom=base_denom)
print(escrow)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"os"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
baseDenom := "uluna"
ctx := context.Background()
res, err := chainClient.FetchTotalEscrowForDenom(ctx, baseDenom)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | Token denom | Yes |
Response Parameters
Response Example:
{
"amount":{
"denom":"uluna",
"amount":"0"
}
}
Parameter | Type | Description |
---|---|---|
amount | Coin | Amount of token in the escrow |
Coin
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | The token denom | Yes |
amount | String | The amount of tokens | Yes |
MsgTransfer
Defines a msg to transfer fungible tokens (i.e Coins) between ICS20 enabled chains. See ICS Spec here: ICS Spec
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
from decimal import Decimal
import dotenv
from pyinjective.async_client import AsyncClient
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
await client.initialize_tokens_from_chain_denoms()
composer = await client.composer()
await client.sync_timeout_height()
message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
network=network,
private_key=configured_private_key,
)
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
source_port = "transfer"
source_channel = "channel-126"
token_amount = composer.create_coin_amount(amount=Decimal("0.1"), token_name="INJ")
sender = address.to_acc_bech32()
receiver = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
timeout_height = 10
# prepare tx msg
message = composer.msg_ibc_transfer(
source_port=source_port,
source_channel=source_channel,
token_amount=token_amount,
sender=sender,
receiver=receiver,
timeout_height=timeout_height,
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"encoding/json"
"fmt"
"os"
"cosmossdk.io/math"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
sdktypes "github.com/cosmos/cosmos-sdk/types"
ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
ibccoretypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
// initialize grpc client
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
sourcePort := "transfer"
sourceChannel := "channel-126"
coin := sdktypes.Coin{
Denom: "inj", Amount: math.NewInt(1000000000000000000), // 1 INJ
}
sender := senderAddress.String()
receiver := "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
timeoutHeight := ibccoretypes.Height{RevisionNumber: 10, RevisionHeight: 10}
msg := &ibctransfertypes.MsgTransfer{
SourcePort: sourcePort,
SourceChannel: sourceChannel,
Token: coin,
Sender: sender,
Receiver: receiver,
TimeoutHeight: timeoutHeight,
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.AsyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description |
---|---|---|
source_port | String | The port on which the packet will be sent |
source_channel | String | The channel by which the packet will be sent |
token | Coin | The tokens to be transferred |
sender | String | The sender address |
receiver | String | The recipient address on the destination chain |
timeout_height | Height | Timeout height relative to the current block height. The timeout is disabled when set to 0 |
timeout_timestamp | Integer | Timeout timestamp in absolute nanoseconds since unix epoch. The timeout is disabled when set to 0 |
memo | String | Optional memo |
Coin
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | The token denom | Yes |
amount | String | The amount of tokens | Yes |
Height
Parameter | Type | Description |
---|---|---|
revision_number | Integer | The revision that the client is currently on |
revision_height | Integer | The height within the given revision |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
- Insurance
Includes the messages to create, underwrite and redeem in insurance funds.
MsgCreateInsuranceFund
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
# set custom cookie location (optional) - defaults to current dir
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
msg = composer.MsgCreateInsuranceFund(
sender=address.to_acc_bech32(),
ticker="5202d32a9-1701406800-SF",
quote_denom="USDT",
oracle_base="Frontrunner",
oracle_quote="Frontrunner",
oracle_type=11,
expiry=-2,
initial_deposit=1000,
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The Injective Chain address | Yes |
ticker | String | The name of the pair | Yes |
quote_denom | String | Coin denom used for the quote asset | Yes |
oracle_base | String | Oracle base currency | Yes |
oracle_quote | String | Oracle quote currency | Yes |
oracle_type | Integer | The oracle provider | Yes |
expiry | Integer | The expiry date | Yes |
initial_deposit | Integer | The initial deposit in the quote asset | Yes |
Response Parameters
Response Example:
txhash: "BB882A23CF0BC6E287F164DB2650990C7F317D9CF4CC2138B1EE479A8FB7F1CE"
raw_log: "[]"
gas wanted: 151648
gas fee: 0.000075824 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgUnderwrite
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
# set custom cookie location (optional) - defaults to current dir
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
msg = composer.MsgUnderwrite(
sender=address.to_acc_bech32(),
market_id="0x141e3c92ed55107067ceb60ee412b86256cedef67b1227d6367b4cdf30c55a74",
quote_denom="USDT",
amount=100,
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The Injective Chain address | Yes |
market_id | String | The market ID | Yes |
quote_denom | String | Coin denom used for the quote asset | Yes |
amount | Integer | The amount to underwrite in the quote asset | Yes |
Response Example:
txhash: "1229C821E16F0DB89B64C86F1E00B6EE51D4B528EC5070B231C6FD8363A1A8BE"
raw_log: "[]"
gas wanted: 142042
gas fee: 0.000071021 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgRequestRedemption
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
# set custom cookie location (optional) - defaults to current dir
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
msg = composer.MsgRequestRedemption(
sender=address.to_acc_bech32(),
market_id="0x141e3c92ed55107067ceb60ee412b86256cedef67b1227d6367b4cdf30c55a74",
share_denom="share15",
amount=100, # raw chain value
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The Injective Chain address | Yes |
market_id | String | The market ID | Yes |
share_denom | String | Share denom used for the insurance fund | Yes |
amount | Integer | The amount to redeem in shares | Yes |
Response Parameters
Response Example:
txhash: "47982CB6CC7418FE7F2B406D40C4AD703CD87F4AA04B12E6151B648061785CD8"
raw_log: "[]"
gas wanted: 110689
gas fee: 0.0000553445 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
- Oracle
Includes the message to relay a price feed.
MsgRelayPriceFeedPrice
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
price = 100
price_to_send = [str(int(price * 10**18))]
base = ["BAYC"]
quote = ["WETH"]
# prepare tx msg
msg = composer.MsgRelayPriceFeedPrice(sender=address.to_acc_bech32(), price=price_to_send, base=base, quote=quote)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"fmt"
"os"
"cosmossdk.io/math"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
oracletypes "github.com/InjectiveLabs/sdk-go/chain/oracle/types"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
price := []math.LegacyDec{math.LegacyMustNewDecFromStr("100")}
base := []string{"BAYC"}
quote := []string{"WETH"}
msg := &oracletypes.MsgRelayPriceFeedPrice{
Sender: senderAddress.String(),
Price: price,
Base: base,
Quote: quote,
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
result, err := chainClient.SyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
fmt.Printf("Broadcast result: %s\n", result)
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The Injective Chain address of the sender | Yes |
price | Array | The price of the base asset | Yes |
base | Array | The base denom | Yes |
quote | Array | The quote denom | Yes |
Response Example:
txhash: "88F5B9C28813BB32607DF312A5411390F43C44F5E1F9D3BA0023EFE0EE4BD0EC"
raw_log: "[]"
gas wanted: 93486
gas fee: 0.000046743 INJ
DEBU[0001] broadcastTx with nonce 1314 fn=func1 src="client/chain/chain.go:598"
DEBU[0002] msg batch committed successfully at height 5215101 fn=func1 src="client/chain/chain.go:619" txHash=641DE5923625C1A81C2544B72E5029E53AE721E47F40221182AFAD6F66F39EA4
DEBU[0002] nonce incremented to 1315 fn=func1 src="client/chain/chain.go:623"
DEBU[0002] gas wanted: 113647 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.0000568235 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgRelayProviderPrices
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
provider = "ufc"
symbols = ["KHABIB-TKO-05/30/2023", "KHABIB-TKO-05/26/2023"]
prices = [0.5, 0.8]
# prepare tx msg
msg = composer.MsgRelayProviderPrices(
sender=address.to_acc_bech32(), provider=provider, symbols=symbols, prices=prices
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
sim_res_msg = sim_res["result"]["msgResponses"]
print("---Simulation Response---")
print(sim_res_msg)
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print("---Transaction Response---")
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The Injective Chain address | Yes |
provider | String | The provider name | Yes |
symbols | List | The symbols we want to relay a price for | Yes |
prices | List | The prices for the respective symbols | Yes |
Response Example:
---Transaction Response---
txhash: "784728B42AD56D0241B166A531815FC82511432FF636E2AD22CBA856123F4AB1"
raw_log: "[]"
gas wanted: 172751
gas fee: 0.0000863755 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
- Permissions
Permissions module provides an extra layer of configuration for all actions related to tokens: mint, transfer and burn.
AllNamespaces
Defines a gRPC query method that returns the permissions module's created namespaces
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
namespaces = await client.fetch_all_permissions_namespaces()
print(namespaces)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("devnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchAllNamespaces(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
No parameters
Response Parameters
Response Example:
Parameter | Type | Description |
---|---|---|
namespaces | Namespace Array | List of namespaces |
Namespace
Parameter | Type | Description |
---|---|---|
denom | String | Token denom |
wasm_hook | String | Address of the wasm contract that will provide the real destination address |
mints_paused | Bool | Mint action status |
sends_paused | Bool | Send action status |
burns_paused | Bool | Burn action status |
role_permissions | Role Array | List of roles |
address_roles | AddressRoles Array | List of Injective addresses and their associated role |
Role
Parameter | Type | Description |
---|---|---|
role | String | Role name |
permissions | Integer | Integer representing the bitwhise combination of all actions assigned to the role |
PermissionAction
Parameter | Type | Description |
---|---|---|
role | String | Role name |
permissions | Integer | Integer representing the bitwhise combination of all actions assigned to the role |
AddressRoles
Parameter | Type | Description |
---|---|---|
address | String | Injective address |
roles | String Array | List of roles assigned to the address |
NamespaceByDenom
Defines a gRPC query method that returns the permissions module's namespace associated with a denom
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
denom = "inj"
namespace = await client.fetch_permissions_namespace_by_denom(denom=denom, include_roles=True)
print(namespace)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("devnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
namespaceDenom := "factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test"
ctx := context.Background()
res, err := chainClient.FetchNamespaceByDenom(ctx, namespaceDenom, true)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | The token denom | Yes |
include_roles | Bool | Option to request the roles in the response | No |
Response Parameters
Response Example:
Parameter | Type | Description |
---|---|---|
namespace | Namespace | The namespace information (if found) |
Namespace
Parameter | Type | Description |
---|---|---|
denom | String | Token denom |
wasm_hook | String | Address of the wasm contract that will provide the real destination address |
mints_paused | Bool | Mint action status |
sends_paused | Bool | Send action status |
burns_paused | Bool | Burn action status |
role_permissions | Role Array | List of roles |
address_roles | AddressRoles Array | List of Injective addresses and their associated role |
Role
Parameter | Type | Description |
---|---|---|
role | String | Role name |
permissions | Integer | Integer representing the bitwhise combination of all actions assigned to the role |
PermissionAction
Parameter | Type | Description |
---|---|---|
role | String | Role name |
permissions | Integer | Integer representing the bitwhise combination of all actions assigned to the role |
AddressRoles
Parameter | Type | Description |
---|---|---|
address | String | Injective address |
roles | String Array | List of roles assigned to the address |
AddressRoles
Defines a gRPC query method that returns a namespace's roles associated with the provided address
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
denom = "inj"
address = "inj1knhahceyp57j5x7xh69p7utegnnnfgxavmahjr"
roles = await client.fetch_permissions_address_roles(denom=denom, address=address)
print(roles)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("devnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
namespaceDenom := "factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test"
address := senderAddress.String()
ctx := context.Background()
res, err := chainClient.FetchAddressRoles(ctx, namespaceDenom, address)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | The token denom | Yes |
address | String | The Injective address to query the roles for | Yes |
Response Parameters
Response Example:
Parameter | Type | Description |
---|---|---|
roles | String Array | List of role names |
AddressesByRole
Defines a query method that returns a namespace's roles associated with the provided address
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
denom = "inj"
role = "roleName"
addresses = await client.fetch_permissions_addresses_by_role(denom=denom, role=role)
print(addresses)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("devnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
namespaceDenom := "factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test"
role := "blacklisted"
ctx := context.Background()
res, err := chainClient.FetchAddressesByRole(ctx, namespaceDenom, role)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | The token denom | Yes |
role | String | The role name to query the addresses for | Yes |
Response Parameters
Response Example:
Parameter | Type | Description |
---|---|---|
addresses | String Array | List of Injective addresses |
VouchersForAddress
Defines a query method that returns a map of vouchers that are held by permissions module for this address, keyed by the originator address
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
address = "inj1knhahceyp57j5x7xh69p7utegnnnfgxavmahjr"
addresses = await client.fetch_permissions_vouchers_for_address(address=address)
print(addresses)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("devnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
address := senderAddress.String()
ctx := context.Background()
res, err := chainClient.FetchVouchersForAddress(ctx, address)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
address | String | The Injective address to query for | Yes |
Response Parameters
Response Example:
Parameter | Type | Description |
---|---|---|
vouchers | Coin Array | List of available vouchers for the address |
Coin
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | The token denom | Yes |
amount | String | The amount of tokens | Yes |
CreateNamespace
Message to create a new namespace
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
private_key_in_hexa = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.devnet()
composer = ProtoMsgComposer(network=network.string())
message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
network=network,
private_key=private_key_in_hexa,
)
priv_key = PrivateKey.from_hex(private_key_in_hexa)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
blocked_address = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
denom = "factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test"
role1 = composer.permissions_role(
role=composer.DEFAULT_PERMISSIONS_EVERYONE_ROLE,
permissions=composer.MINT_ACTION_PERMISSION
| composer.RECEIVE_ACTION_PERMISSION
| composer.BURN_ACTION_PERMISSION,
)
role2 = composer.permissions_role(role="blacklisted", permissions=composer.UNDEFINED_ACTION_PERMISSION)
address_role1 = composer.permissions_address_roles(address=blocked_address, roles=["blacklisted"])
message = composer.msg_create_namespace(
sender=address.to_acc_bech32(),
denom=denom,
wasm_hook="",
mints_paused=False,
sends_paused=False,
burns_paused=False,
role_permissions=[role1, role2],
address_roles=[address_role1],
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"encoding/json"
"fmt"
"os"
permissionstypes "github.com/InjectiveLabs/sdk-go/chain/permissions/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("devnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
blockedAddress := "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
namespace := permissionstypes.Namespace{
Denom: "factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test",
RolePermissions: []*permissionstypes.Role{
{
Role: permissionstypes.EVERYONE,
Permissions: uint32(permissionstypes.Action_MINT | permissionstypes.Action_RECEIVE | permissionstypes.Action_BURN),
},
{
Role: "blacklisted",
Permissions: 0,
},
},
AddressRoles: []*permissionstypes.AddressRoles{
{
Address: blockedAddress,
Roles: []string{"blacklisted"},
},
},
}
msg := &permissionstypes.MsgCreateNamespace{
Sender: senderAddress.String(),
Namespace: namespace,
}
//AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.SyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The sender's Injective address | Yes |
namespace | Namespace | The namespace information | Yes |
Namespace
Parameter | Type | Description |
---|---|---|
denom | String | Token denom |
wasm_hook | String | Address of the wasm contract that will provide the real destination address |
mints_paused | Bool | Mint action status |
sends_paused | Bool | Send action status |
burns_paused | Bool | Burn action status |
role_permissions | Role Array | List of roles |
address_roles | AddressRoles Array | List of Injective addresses and their associated role |
Role
Parameter | Type | Description |
---|---|---|
role | String | Role name |
permissions | Integer | Integer representing the bitwhise combination of all actions assigned to the role |
PermissionAction
Parameter | Type | Description |
---|---|---|
role | String | Role name |
permissions | Integer | Integer representing the bitwhise combination of all actions assigned to the role |
AddressRoles
Parameter | Type | Description |
---|---|---|
address | String | Injective address |
roles | String Array | List of roles assigned to the address |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
DeleteNamespace
Message to delete a namespace
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
private_key_in_hexa = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.devnet()
composer = ProtoMsgComposer(network=network.string())
message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
network=network,
private_key=private_key_in_hexa,
)
priv_key = PrivateKey.from_hex(private_key_in_hexa)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
denom = "factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test"
message = composer.msg_delete_namespace(
sender=address.to_acc_bech32(),
namespace_denom=denom,
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"encoding/json"
"fmt"
"os"
permissionstypes "github.com/InjectiveLabs/sdk-go/chain/permissions/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("devnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
namespaceDenom := "factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test"
msg := &permissionstypes.MsgDeleteNamespace{
Sender: senderAddress.String(),
NamespaceDenom: namespaceDenom,
}
//AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.SyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The sender's Injective address | Yes |
namespace_denom | String | The token denom of the namespace to delete | Yes |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
UpdateNamespace
Message to update a namespace configuration
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
private_key_in_hexa = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.devnet()
composer = ProtoMsgComposer(network=network.string())
message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
network=network,
private_key=private_key_in_hexa,
)
priv_key = PrivateKey.from_hex(private_key_in_hexa)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
denom = "factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test"
message = composer.msg_update_namespace(
sender=address.to_acc_bech32(),
namespace_denom=denom,
wasm_hook="inj19ld6swyldyujcn72j7ugnu9twafhs9wxlyye5m",
mints_paused=True,
sends_paused=True,
burns_paused=True,
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"encoding/json"
"fmt"
"os"
permissionstypes "github.com/InjectiveLabs/sdk-go/chain/permissions/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("devnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
namespaceDenom := "factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test"
msg := &permissionstypes.MsgUpdateNamespace{
Sender: senderAddress.String(),
NamespaceDenom: namespaceDenom,
WasmHook: &permissionstypes.MsgUpdateNamespace_MsgSetWasmHook{NewValue: "inj19ld6swyldyujcn72j7ugnu9twafhs9wxlyye5m"},
SendsPaused: &permissionstypes.MsgUpdateNamespace_MsgSetSendsPaused{NewValue: true},
MintsPaused: &permissionstypes.MsgUpdateNamespace_MsgSetMintsPaused{NewValue: true},
BurnsPaused: &permissionstypes.MsgUpdateNamespace_MsgSetBurnsPaused{NewValue: true},
}
//AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.SyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The sender's Injective address | Yes |
namespace_denom | String | The token denom of the namespace to update | Yes |
wasm_hook | String | Address of the wasm contract that will provide the real destination address | Yes |
mints_paused | Bool | Mint action status | Yes |
sends_paused | Bool | Send action status | Yes |
burns_paused | Bool | Burn action status | Yes |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
UpdateNamespaceRoles
Message to update a namespace roles
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
private_key_in_hexa = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.devnet()
composer = ProtoMsgComposer(network=network.string())
message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
network=network,
private_key=private_key_in_hexa,
)
priv_key = PrivateKey.from_hex(private_key_in_hexa)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
blocked_address = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
denom = "factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test"
role1 = composer.permissions_role(
role=composer.DEFAULT_PERMISSIONS_EVERYONE_ROLE,
permissions=composer.RECEIVE_ACTION_PERMISSION,
)
role2 = composer.permissions_role(role="blacklisted", permissions=composer.UNDEFINED_ACTION_PERMISSION)
address_role1 = composer.permissions_address_roles(address=blocked_address, roles=["blacklisted"])
message = composer.msg_update_namespace_roles(
sender=address.to_acc_bech32(),
namespace_denom=denom,
role_permissions=[role1, role2],
address_roles=[address_role1],
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"encoding/json"
"fmt"
"os"
permissionstypes "github.com/InjectiveLabs/sdk-go/chain/permissions/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("devnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
namespaceDenom := "factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test"
blockedAddress := "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
msg := &permissionstypes.MsgUpdateNamespaceRoles{
Sender: senderAddress.String(),
NamespaceDenom: namespaceDenom,
RolePermissions: []*permissionstypes.Role{
{
Role: permissionstypes.EVERYONE,
Permissions: uint32(permissionstypes.Action_RECEIVE),
},
{
Role: "blacklisted",
Permissions: 0,
},
},
AddressRoles: []*permissionstypes.AddressRoles{
{
Address: blockedAddress,
Roles: []string{"blacklisted"},
},
},
}
//AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.SyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The sender's Injective address | Yes |
namespace_denom | String | The token denom of the namespace to update | Yes |
role_permissions | Role Array | List of roles | Yes |
address_roles | AddressRoles Array | List of Injective addresses and their associated role | Yes |
Role
Parameter | Type | Description |
---|---|---|
role | String | Role name |
permissions | Integer | Integer representing the bitwhise combination of all actions assigned to the role |
PermissionAction
Parameter | Type | Description |
---|---|---|
role | String | Role name |
permissions | Integer | Integer representing the bitwhise combination of all actions assigned to the role |
AddressRoles
Parameter | Type | Description |
---|---|---|
address | String | Injective address |
roles | String Array | List of roles assigned to the address |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
RevokeNamespaceRoles
Message to revoke roles from addresses
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
private_key_in_hexa = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.devnet()
composer = ProtoMsgComposer(network=network.string())
message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
network=network,
private_key=private_key_in_hexa,
)
priv_key = PrivateKey.from_hex(private_key_in_hexa)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
blocked_address = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
denom = "factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test"
address_role1 = composer.permissions_address_roles(address=blocked_address, roles=["blacklisted"])
message = composer.msg_revoke_namespace_roles(
sender=address.to_acc_bech32(),
namespace_denom=denom,
address_roles_to_revoke=[address_role1],
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"encoding/json"
"fmt"
"os"
permissionstypes "github.com/InjectiveLabs/sdk-go/chain/permissions/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("devnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
namespaceDenom := "factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test"
blockedAddress := "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
msg := &permissionstypes.MsgRevokeNamespaceRoles{
Sender: senderAddress.String(),
NamespaceDenom: namespaceDenom,
AddressRolesToRevoke: []*permissionstypes.AddressRoles{
{
Address: blockedAddress,
Roles: []string{"blacklisted"},
},
},
}
//AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.SyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The sender's Injective address | Yes |
namespace_denom | String | The token denom of the namespace to update | Yes |
address_roles_to_revoke | AddressRoles Array | List of Injective addresses and their associated role | Yes |
AddressRoles
Parameter | Type | Description |
---|---|---|
address | String | Injective address |
roles | String Array | List of roles assigned to the address |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
ClaimVoucher
Message to claim existing vouchers for a particular address
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
private_key_in_hexa = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.devnet()
composer = ProtoMsgComposer(network=network.string())
message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
network=network,
private_key=private_key_in_hexa,
)
priv_key = PrivateKey.from_hex(private_key_in_hexa)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
denom = "factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test"
message = composer.msg_claim_voucher(
sender=address.to_acc_bech32(),
denom=denom,
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"encoding/json"
"fmt"
"os"
permissionstypes "github.com/InjectiveLabs/sdk-go/chain/permissions/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("devnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
denom := "factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test"
msg := &permissionstypes.MsgClaimVoucher{
Sender: senderAddress.String(),
Denom: denom,
}
//AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.SyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The sender's Injective address | Yes |
denom | String | The token denom of the voucher to claim | Yes |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
- Staking
Includes the messages to claim and withdraw delegator rewards, and query staking state
ValidatorDistributionInfo
Queries validator commission and self-delegation rewards for validator
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
validator_address = "injvaloper1jue5dpr9lerjn6wlwtrywxrsenrf28ru89z99z"
distribution_info = await client.fetch_validator_distribution_info(validator_address=validator_address)
print(distribution_info)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
validatorAddress := "injvaloper1jue5dpr9lerjn6wlwtrywxrsenrf28ru89z99z"
ctx := context.Background()
res, err := chainClient.FetchValidatorDistributionInfo(ctx, validatorAddress)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
validator_address | String | The validator address to query for | Yes |
Response Parameters
Response Example:
{
"operatorAddress":"inj1jue5dpr9lerjn6wlwtrywxrsenrf28rusrhqyx",
"selfBondRewards":[
{
"denom":"inj",
"amount":"520293543167557100000"
}
],
"commission":[
{
"denom":"inj",
"amount":"105136140964470306856270639550202093130"
}
]
}
Parameter | Type | Description |
---|---|---|
operator_address | String | The validator operator address |
self_bond_rewards | DecCoin Array | The self delegations rewards |
commission | DecCoin Array | The commission the validator received |
DecCoin
Parameter | Type | Description |
---|---|---|
denom | String | The token denom |
amount | String | The amount of tokens |
ValidatorOutstandingRewards
Queries rewards of a validator address
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
validator_address = "injvaloper1jue5dpr9lerjn6wlwtrywxrsenrf28ru89z99z"
rewards = await client.fetch_validator_outstanding_rewards(validator_address=validator_address)
print(rewards)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
validatorAddress := "injvaloper1jue5dpr9lerjn6wlwtrywxrsenrf28ru89z99z"
ctx := context.Background()
res, err := chainClient.FetchValidatorOutstandingRewards(ctx, validatorAddress)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
validator_address | String | The validator address to query for | Yes |
Response Parameters
Response Example:
{
"rewards":{
"rewards":[
{
"denom":"inj",
"amount":"1997451426304473936130044829302179245433"
}
]
}
}
Parameter | Type | Description |
---|---|---|
rewards | ValidatorOutstandingRewards | Details of all the rewards |
ValidatorOutstandingRewards
Parameter | Type | Description |
---|---|---|
rewards | DecCoin Array | Details of all the rewards |
DecCoin
Parameter | Type | Description |
---|---|---|
denom | String | The token denom |
amount | String | The amount of tokens |
ValidatorCommission
Queries accumulated commission for a validator
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
validator_address = "injvaloper1jue5dpr9lerjn6wlwtrywxrsenrf28ru89z99z"
commission = await client.fetch_validator_commission(validator_address=validator_address)
print(commission)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
validatorAddress := "injvaloper1jue5dpr9lerjn6wlwtrywxrsenrf28ru89z99z"
ctx := context.Background()
res, err := chainClient.FetchValidatorCommission(ctx, validatorAddress)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
validator_address | String | The validator address to query for | Yes |
Response Parameters
Response Example:
{
"commission":{
"commission":[
{
"denom":"inj",
"amount":"105379963222887965961634697913891232463"
}
]
}
}
Parameter | Type | Description |
---|---|---|
commission | ValidatorAccumulatedCommission | The commission the validator received |
ValidatorAccumulatedCommission
Parameter | Type | Description |
---|---|---|
commission | DecCoin Array | Accumulated commissions for the validator |
DecCoin
Parameter | Type | Description |
---|---|---|
denom | String | The token denom |
amount | String | The amount of tokens |
ValidatorSlashes
Queries slash events of a validator
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
limit = 2
pagination = PaginationOption(limit=limit)
validator_address = "injvaloper1jue5dpr9lerjn6wlwtrywxrsenrf28ru89z99z"
contracts = await client.fetch_validator_slashes(validator_address=validator_address, pagination=pagination)
print(contracts)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
validatorAddress := "injvaloper1jue5dpr9lerjn6wlwtrywxrsenrf28ru89z99z"
startingHeight := uint64(0)
endingHeight := uint64(0)
pagination := query.PageRequest{Limit: 10}
ctx := context.Background()
res, err := chainClient.FetchValidatorSlashes(ctx, validatorAddress, startingHeight, endingHeight, &pagination)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
validator_address | String | The validator address to query for | Yes |
starting_height | Integer | The optional starting height to query the slashes | No |
ending_height | Integer | The optional ending height to query the slashes | No |
pagination | PageRequest | The optional pagination for the request | No |
PageRequest
Parameter | Type | Description | Required |
---|---|---|---|
key | Byte Array | Key is a value returned in PageResponse.next_key to begin querying the next page most efficiently. Only one of offset or key should be set | No |
offset | Integer | Numeric offset that can be used when key is unavailable. It is less efficient than using key. Only one of offset or key should be set | No |
limit | Integer | Total number of results to be returned in the result page | No |
count_total | Boolean | Set to true to indicate that the result set should include a count of the total number of items available for pagination in UIs. It is only respected when offset is used. It is ignored when key is set | No |
reverse | Boolean | Reverse is set to true if results are to be returned in the descending order | No |
Response Parameters
Response Example:
Parameter | Type | Description |
---|---|---|
slashes | ValidatorSlashEvent Array | Slashes de validator received |
pagination | PageResponse | Pagination information in the response |
ValidatorSlashEvent
Parameter | Type | Description |
---|---|---|
validator_period | Integer | The period when the validator got slashed |
fraction | String | Slashing applied |
PageResponse
Parameter | Type | Description |
---|---|---|
next_key | Byte Array | The key to be passed to PageRequest.key to query the next page most efficiently. It will be empty if there are no more results. |
total | Integer | Total number of results available if PageRequest.count_total was set, its value is undefined otherwise |
DelegationRewards
Queries the total rewards accrued by a delegation
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
delegator_address = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
validator_address = "injvaloper156t3yxd4udv0h9gwagfcmwnmm3quy0nph7tyh5"
rewards = await client.fetch_delegation_rewards(
delegator_address=delegator_address, validator_address=validator_address
)
print(rewards)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
delegatorAddress := "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
validatorAddress := "injvaloper156t3yxd4udv0h9gwagfcmwnmm3quy0nph7tyh5"
ctx := context.Background()
res, err := chainClient.FetchDelegationRewards(ctx, delegatorAddress, validatorAddress)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
delegator_address | String | Delegator address to query for | Yes |
validator_address | String | Validator address to query for | Yes |
Response Parameters
Response Example:
{
"rewards":[
{
"denom":"inj",
"amount":"1965602260312"
}
]
}
Parameter | Type | Description |
---|---|---|
rewards | DecCoin Array | The rewards accrued by a delegation |
DecCoin
Parameter | Type | Description |
---|---|---|
denom | String | The token denom |
amount | String | The amount of tokens |
DelegationTotalRewards
Queries the total rewards accrued by each validator
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
delegator_address = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
rewards = await client.fetch_delegation_total_rewards(
delegator_address=delegator_address,
)
print(rewards)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
delegatorAddress := "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
ctx := context.Background()
res, err := chainClient.FetchDelegationTotalRewards(ctx, delegatorAddress)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
delegator_address | String | The delegator address to query for | Yes |
Response Parameters
Response Example:
{
"rewards":[
{
"validatorAddress":"injvaloper156t3yxd4udv0h9gwagfcmwnmm3quy0nph7tyh5",
"reward":[
{
"denom":"inj",
"amount":"1972565915361"
}
]
},
{
"validatorAddress":"injvaloper1cq6mvxqp978f6lxrh5s6c35ddr2slcj9h7tqng",
"reward":[
]
},
{
"validatorAddress":"injvaloper16nd8yqxe9p6ggnrz58qr7dxn5y2834yeytmczf",
"reward":[
]
},
{
"validatorAddress":"injvaloper1u3slvlxpyckrpdk28a45uthku87wck3e934kl0",
"reward":[
]
},
{
"validatorAddress":"injvaloper17lzhgs2d50qcwlwdn06y3sghphlwl3xxxgml46",
"reward":[
]
}
],
"total":[
{
"denom":"inj",
"amount":"1972565915361"
}
]
}
Parameter | Type | Description |
---|---|---|
rewards | DelegationDelegatorReward Array | All the rewards accrued by a delegator |
total | DecCoin Array | The sum of all rewards |
DelegationDelegatorReward
Parameter | Type | Description |
---|---|---|
validator_address | String | The validator's Injective address |
reward | DecCoin Array | List of all the rewards for the validator |
DecCoin
Parameter | Type | Description |
---|---|---|
denom | String | The token denom |
amount | String | The amount of tokens |
DelegatorValidators
Queries the validators of a delegator
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
delegator_address = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
validators = await client.fetch_delegator_validators(
delegator_address=delegator_address,
)
print(validators)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
delegatorAddress := "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
ctx := context.Background()
res, err := chainClient.FetchDelegatorValidators(ctx, delegatorAddress)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
delegator_address | String | The delegator address to query for | Yes |
Response Parameters
Response Example:
{
"validators":[
"injvaloper156t3yxd4udv0h9gwagfcmwnmm3quy0nph7tyh5",
"injvaloper1cq6mvxqp978f6lxrh5s6c35ddr2slcj9h7tqng",
"injvaloper16nd8yqxe9p6ggnrz58qr7dxn5y2834yeytmczf",
"injvaloper1u3slvlxpyckrpdk28a45uthku87wck3e934kl0",
"injvaloper17lzhgs2d50qcwlwdn06y3sghphlwl3xxxgml46"
]
}
Parameter | Type | Description |
---|---|---|
validators | String Array | List of all validators a delegator is delegating for |
DelegatorWithdrawAddress
Queries the withdraw address of a delegator
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
delegator_address = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
withdraw_address = await client.fetch_delegator_withdraw_address(
delegator_address=delegator_address,
)
print(withdraw_address)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
delegatorAddress := "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
ctx := context.Background()
res, err := chainClient.FetchDelegatorWithdrawAddress(ctx, delegatorAddress)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
delegator_address | String | The delegator address to query for | Yes |
Response Parameters
Response Example:
{
"withdrawAddress":"inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
}
Paramter | Type | Description |
---|---|---|
withdraw_address | String | The delegator's withdraw address |
CommunityPool
Queries the community pool coins
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
community_pool = await client.fetch_community_pool()
print(community_pool)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchCommunityPool(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
No parameters
Response Parameters
Response Example:
{
"pool":[
{
"denom":"inj",
"amount":"619667912004889463981597377474655365826158034046"
}
]
}
Parameter | Type | Description |
---|---|---|
pool | DecCoin Array | List of coins in the community pool |
DecCoin
Parameter | Type | Description |
---|---|---|
denom | String | The token denom |
amount | String | The amount of tokens |
SetWithdrawAddress
Changes the withdraw address for a delegator (or validator self-delegation)
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective import AsyncClient, PrivateKey
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
composer = await client.composer()
message_broadcaster = MsgBroadcasterWithPk.new_without_simulation(
network=network,
private_key=configured_private_key,
client=client,
composer=composer,
)
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
withdraw_address = "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
message = composer.msg_set_withdraw_address(
delegator_address=address.to_acc_bech32(),
withdraw_address=withdraw_address,
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"encoding/json"
"fmt"
"os"
"github.com/cosmos/cosmos-sdk/x/distribution/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
withdrawAddress := "inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"
msg := &types.MsgSetWithdrawAddress{
DelegatorAddress: senderAddress.String(),
WithdrawAddress: withdrawAddress,
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.AsyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
delegator_address | String | The delegator's injective address | Yes |
withdraw_address | String | The new withdraw address | Yes |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgWithdrawDelegatorReward
Withdraw rewards of a delegator
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective.async_client import AsyncClient
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
composer = await client.composer()
message_broadcaster = MsgBroadcasterWithPk.new_without_simulation(
network=network,
private_key=configured_private_key,
client=client,
composer=composer,
)
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
# prepare tx msg
validator_address = "injvaloper1ultw9r29l8nxy5u6thcgusjn95vsy2caw722q5"
message = composer.msg_withdraw_delegator_reward(
delegator_address=address.to_acc_bech32(), validator_address=validator_address
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"fmt"
"os"
"time"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
msg := new(distributiontypes.MsgWithdrawDelegatorReward)
msg.DelegatorAddress = senderAddress.String()
msg.ValidatorAddress = "injvaloper14gy4acwjm96wd20awm9ar6j54lev5p7espy9ug"
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
delegator_address | String | The delegator's address | Yes |
validator_address | String | The validator's address | Yes |
Response parameters
Response Example:
txhash: "0EDB245FE6F59F9DD8B6F03D56E6F37FE0D53DD85C62476BD7A1F72486D44F8E"
raw_log: "[]"
gas wanted: 191525
gas fee: 0.0000957625 INJ
DEBU[0001] broadcastTx with nonce 1321 fn=func1 src="client/chain/chain.go:598"
DEBU[0003] msg batch committed successfully at height 5215332 fn=func1 src="client/chain/chain.go:619" txHash=A4F9D6998F075E875F611ED279B617EAB4C0332EBC347468EEDAD81DD8236C48
DEBU[0003] nonce incremented to 1322 fn=func1 src="client/chain/chain.go:623"
DEBU[0003] gas wanted: 195046 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.000097523 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
WithdrawValidatorCommission
Withdraws the full commission to the validator address
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective.async_client import AsyncClient
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
composer = await client.composer()
message_broadcaster = MsgBroadcasterWithPk.new_without_simulation(
network=network,
private_key=configured_private_key,
client=client,
composer=composer,
)
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
# prepare tx msg
validator_address = "injvaloper1ultw9r29l8nxy5u6thcgusjn95vsy2caw722q5"
message = composer.msg_withdraw_validator_commission(validator_address=validator_address)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"encoding/json"
"fmt"
"os"
"github.com/cosmos/cosmos-sdk/x/distribution/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
validatorAddress := "injvaloper1ultw9r29l8nxy5u6thcgusjn95vsy2caw722q5"
msg := &types.MsgWithdrawValidatorCommission{
ValidatorAddress: validatorAddress,
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.AsyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
validator_address | String | The validator's address | Yes |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
FundCommunityPool
Allows an account to directly fund the community pool
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
from decimal import Decimal
import dotenv
from pyinjective import AsyncClient, PrivateKey
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
composer = await client.composer()
message_broadcaster = MsgBroadcasterWithPk.new_without_simulation(
network=network,
private_key=configured_private_key,
client=client,
composer=composer,
)
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
amount = composer.create_coin_amount(amount=Decimal("0.1"), token_name="INJ")
message = composer.msg_fund_community_pool(
amounts=[amount],
depositor=address.to_acc_bech32(),
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"encoding/json"
"fmt"
"os"
"cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/types"
distriutiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
amount := types.NewCoin("inj", math.NewInt(1))
msg := &distriutiontypes.MsgFundCommunityPool{
Amount: []types.Coin{amount},
Depositor: senderAddress.String(),
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.AsyncBroadcastMsg(msg)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
amount | Coin Array | The token amounts to transfer | Yes |
depositor | String | The depositor's account | Yes |
Coin
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | The token denom | Yes |
amount | String | The amount of tokens | Yes |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgDelegate
Performs a coins delegation from a delegator to a validator
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
# prepare tx msg
validator_address = "injvaloper1ultw9r29l8nxy5u6thcgusjn95vsy2caw722q5"
amount = 100
msg = composer.MsgDelegate(
delegator_address=address.to_acc_bech32(), validator_address=validator_address, amount=amount
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"fmt"
"os"
"time"
"cosmossdk.io/math"
"github.com/InjectiveLabs/sdk-go/client"
"github.com/InjectiveLabs/sdk-go/client/common"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
sdktypes "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
msg := new(stakingtypes.MsgDelegate)
msg.DelegatorAddress = senderAddress.String()
msg.ValidatorAddress = "injvaloper14gy4acwjm96wd20awm9ar6j54lev5p7espy9ug"
msg.Amount = sdktypes.Coin{
Denom: "inj", Amount: math.NewInt(1000000000000000000), // 1 INJ
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
err = chainClient.QueueBroadcastMsg(msg)
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second * 5)
gasFee, err := chainClient.GetGasFee()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("gas fee:", gasFee, "INJ")
}
Parameter | Type | Description | Required |
---|---|---|---|
delegator_address | String | The delegator's address | Yes |
validator_address | String | The validator's address | Yes |
amount | Coin | The token amount to delegate | Yes |
Coin
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | The token denom | Yes |
amount | String | The amount of tokens | Yes |
Response Parameters
Response Example:
txhash: "0EDB245FE6F59F9DD8B6F03D56E6F37FE0D53DD85C62476BD7A1F72486D44F8E"
raw_log: "[]"
gas wanted: 191525
gas fee: 0.0000957625 INJ
DEBU[0001] broadcastTx with nonce 1318 fn=func1 src="client/chain/chain.go:598"
DEBU[0003] msg batch committed successfully at height 5215234 fn=func1 src="client/chain/chain.go:619" txHash=1714F24FB2BEE871C0A5CED998CCB0C33069FF40F744AE2AEF3720F24893D92A
DEBU[0003] nonce incremented to 1319 fn=func1 src="client/chain/chain.go:623"
DEBU[0003] gas wanted: 207846 fn=func1 src="client/chain/chain.go:624"
gas fee: 0.000103923 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
- Tendermint
Cosmos Tendermint module
GetNodeInfo
Gets the current node info
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
node_info = await client.fetch_node_info()
print(node_info)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchNodeInfo(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
No parameters
Response Parameters
Response Example:
{
"defaultNodeInfo":{
"protocolVersion":{
"p2p":"8",
"block":"11",
"app":"0"
},
"defaultNodeId":"53c19e8ba2deb109ba8d09dd41ae82bbddd74467",
"listenAddr":"tcp://0.0.0.0:26656",
"network":"injective-888",
"version":"0.37.1",
"channels":"QCAhIiMwOGBhAA==",
"moniker":"injective",
"other":{
"txIndex":"on",
"rpcAddress":"tcp://0.0.0.0:26657"
}
},
"applicationVersion":{
"name":"injective",
"appName":"injectived",
"gitCommit":"1f0a39381",
"goVersion":"go version go1.19.13 linux/amd64",
"buildDeps":[
{
"path":"cloud.google.com/go",
"version":"v0.110.4",
"sum":"h1:1JYyxKMN9hd5dR2MYTPWkGUgcoxVVhg0LKNKEo0qvmk="
},
{
"path":"cloud.google.com/go/compute/metadata",
"version":"v0.2.3",
"sum":"h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY="
}
],
"cosmosSdkVersion":"v0.47.5",
"version":"",
"buildTags":""
}
}
Parameter | Type | Description |
---|---|---|
default_node_info | DefaultNodeInfo | Node information |
application_version | VersionInfo | Node version information |
DefaultNodeInfo
Parameter | Type | Description |
---|---|---|
protocol_version | ProtocolVersion | Protocol version information |
default_nod_id | String | Node identifier |
listen_addr | String | URI of the node's listening endpoint |
network | String | The chain network name |
version | String | The version number |
channels | Bytes | Channels information |
moniker | String | |
other | DefaultNodeInfoOther | Extra node information |
ProtocolVersion
Parameter | Type | Description |
---|---|---|
p2p | Integer | |
block | Integer | |
app | Integer |
DefaultNodeInfoOther
Parameter | Type | Description |
---|---|---|
tx_index | String | TX indexing status (on/off) |
rpc_address | String | URI for RPC connections |
VersionInfo
Parameter | Type | Description |
---|---|---|
name | String | The chain name |
app_name | String | Application name |
version | String | Application version |
git_commit | String | Git commit hash |
build_tags | String | Application build tags |
go_version | String | GoLang version used to compile the application |
build_deps | Module Array | Application dependencies |
cosmos_sdk_version | String | Cosmos SDK version used by the application |
Module
Parameter | Type | Description |
---|---|---|
path | String | Module path |
version | String | Module version |
sum | String | Checksum |
GetSyncing
Returns the node's syncing status
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
syncing = await client.fetch_syncing()
print(syncing)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchSyncing(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
No parameters
Response Parameters
Response Example:
{
"syncing":false
}
Parameter | Type | Description |
---|---|---|
syncing | Boolean | Syncing status |
GetLatestBlock
Get the latest block
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
latest_block = await client.fetch_latest_block()
print(latest_block)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchLatestBlock(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
No parameters
Response Parameters
Response Example:
{
"blockId":{
"hash":"bCxPpTR4INvkmf3kAVYi1KhwzX0ySxQuhc8xBBFNmAo=",
"partSetHeader":{
"total":1,
"hash":"6zGn+fBW1y4cpyos4g/tVNQdqS03D/jr/B68SYVvcbQ="
}
},
"block":{
"header":{
"version":{
"block":"11",
"app":"0"
},
"chainId":"injective-888",
"height":"23197636",
"time":"2024-03-14T17:39:19.050602Z",
"lastBlockId":{
"hash":"SglGvXqUCRelE9NtLBiJ0EIBBxTXmztat4fVrYagYlM=",
"partSetHeader":{
"total":1,
"hash":"AsAE1Sdl69RqHqaseeRn3U6N43gG9T710HUjXJi6fyw="
}
},
"lastCommitHash":"EBSqUY4fpGLr2FmmcYsFa01H0PDWQLVuKslws5Un9zU=",
"dataHash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"validatorsHash":"G0AQ0vfNXTLF7UcNXSvk6ZJRWFo09hadwJSm7haFV6I=",
"nextValidatorsHash":"G0AQ0vfNXTLF7UcNXSvk6ZJRWFo09hadwJSm7haFV6I=",
"consensusHash":"5bupI5wNP5Z/jvh5UG/269+5QPiQTXKRNRpGHwCqrU0=",
"appHash":"UoJN/dwHiiDytgSt3xHcb9zkcP8eFZ+qFZWWclQ6SYg=",
"lastResultsHash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"evidenceHash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"proposerAddress":"M5HjW2EATgO+uI+h2rRES5E7174="
},
"data":{
"txs":[
]
},
"evidence":{
"evidence":[
]
},
"lastCommit":{
"height":"23197635",
"blockId":{
"hash":"SglGvXqUCRelE9NtLBiJ0EIBBxTXmztat4fVrYagYlM=",
"partSetHeader":{
"total":1,
"hash":"AsAE1Sdl69RqHqaseeRn3U6N43gG9T710HUjXJi6fyw="
}
},
"signatures":[
{
"blockIdFlag":"BLOCK_ID_FLAG_ABSENT",
"timestamp":"0001-01-01T00:00:00Z",
"validatorAddress":"",
"signature":""
},
{
"blockIdFlag":"BLOCK_ID_FLAG_COMMIT",
"validatorAddress":"ObUXYdS8jfTSNPonUBFPJkft7eA=",
"timestamp":"2024-03-14T17:39:19.050602Z",
"signature":"3ZdA7LqXq4Hj5olf1XKusJ6NHCBkqjpty9pgmsxKyzSG0VL8Uf+Ro0NDuZo8jK4qfLsuctCte3rdGV6lG/cKAA=="
},
{
"blockIdFlag":"BLOCK_ID_FLAG_COMMIT",
"validatorAddress":"M5HjW2EATgO+uI+h2rRES5E7174=",
"timestamp":"2024-03-14T17:39:19.044716221Z",
"signature":"u8QVTQO/QZhNSzAwVCR3bGLUzryi9E+3jQ2COcHi46GfU0SpWOPNBvdbOHsEkRx6EKh0P0acB/hOnDE5JPp5AA=="
},
{
"blockIdFlag":"BLOCK_ID_FLAG_COMMIT",
"validatorAddress":"y8ctJ4QpJ0S7ZTVY7RTE4z1hS2c=",
"timestamp":"2024-03-14T17:39:19.051153172Z",
"signature":"0R/H5GkdKJszELjxfwX9qQlr5nuANTQYN9aTTDvKkUqJDoXW3OwbQPHtegKJlVKU8BT80D2Glng+SnQMO3JSCA=="
}
],
"round":0
}
},
"sdkBlock":{
"header":{
"version":{
"block":"11",
"app":"0"
},
"chainId":"injective-888",
"height":"23197636",
"time":"2024-03-14T17:39:19.050602Z",
"lastBlockId":{
"hash":"SglGvXqUCRelE9NtLBiJ0EIBBxTXmztat4fVrYagYlM=",
"partSetHeader":{
"total":1,
"hash":"AsAE1Sdl69RqHqaseeRn3U6N43gG9T710HUjXJi6fyw="
}
},
"lastCommitHash":"EBSqUY4fpGLr2FmmcYsFa01H0PDWQLVuKslws5Un9zU=",
"dataHash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"validatorsHash":"G0AQ0vfNXTLF7UcNXSvk6ZJRWFo09hadwJSm7haFV6I=",
"nextValidatorsHash":"G0AQ0vfNXTLF7UcNXSvk6ZJRWFo09hadwJSm7haFV6I=",
"consensusHash":"5bupI5wNP5Z/jvh5UG/269+5QPiQTXKRNRpGHwCqrU0=",
"appHash":"UoJN/dwHiiDytgSt3xHcb9zkcP8eFZ+qFZWWclQ6SYg=",
"lastResultsHash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"evidenceHash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"proposerAddress":"injvalcons1xwg7xkmpqp8q804c37sa4dzyfwgnh4a74ll9pz"
},
"data":{
"txs":[
]
},
"evidence":{
"evidence":[
]
},
"lastCommit":{
"height":"23197635",
"blockId":{
"hash":"SglGvXqUCRelE9NtLBiJ0EIBBxTXmztat4fVrYagYlM=",
"partSetHeader":{
"total":1,
"hash":"AsAE1Sdl69RqHqaseeRn3U6N43gG9T710HUjXJi6fyw="
}
},
"signatures":[
{
"blockIdFlag":"BLOCK_ID_FLAG_ABSENT",
"timestamp":"0001-01-01T00:00:00Z",
"validatorAddress":"",
"signature":""
},
{
"blockIdFlag":"BLOCK_ID_FLAG_COMMIT",
"validatorAddress":"ObUXYdS8jfTSNPonUBFPJkft7eA=",
"timestamp":"2024-03-14T17:39:19.050602Z",
"signature":"3ZdA7LqXq4Hj5olf1XKusJ6NHCBkqjpty9pgmsxKyzSG0VL8Uf+Ro0NDuZo8jK4qfLsuctCte3rdGV6lG/cKAA=="
},
{
"blockIdFlag":"BLOCK_ID_FLAG_COMMIT",
"validatorAddress":"M5HjW2EATgO+uI+h2rRES5E7174=",
"timestamp":"2024-03-14T17:39:19.044716221Z",
"signature":"u8QVTQO/QZhNSzAwVCR3bGLUzryi9E+3jQ2COcHi46GfU0SpWOPNBvdbOHsEkRx6EKh0P0acB/hOnDE5JPp5AA=="
},
{
"blockIdFlag":"BLOCK_ID_FLAG_COMMIT",
"validatorAddress":"y8ctJ4QpJ0S7ZTVY7RTE4z1hS2c=",
"timestamp":"2024-03-14T17:39:19.051153172Z",
"signature":"0R/H5GkdKJszELjxfwX9qQlr5nuANTQYN9aTTDvKkUqJDoXW3OwbQPHtegKJlVKU8BT80D2Glng+SnQMO3JSCA=="
}
],
"round":0
}
}
}
Parameter | Type | Description |
---|---|---|
block_id | BlockID | Block identifier |
sdk_block | Block | Block details |
BlockID
Parameter | Type | Description |
---|---|---|
hash | Bytes | Block hash |
part_set_header | PartSetHeader |
PartSetHeader
Parameter | Type | Description |
---|---|---|
total | Integer | |
hash | Bytes |
Block
Parameter | Type | Description |
---|---|---|
header | Header | Header information |
data | Data | Block data |
evidence | EvidenceList | |
last_commit | Commit |
Header
Parameter | Type | Description |
---|---|---|
version | Consensus | |
chain_id | String | Chain identifier |
height | Integer | Block height |
time | Time | Block time |
last_block_id | BlockID | Previous block identifier |
last_commit_hash | Bytes | Last commit hash |
data_hash | Bytes | Block data hash |
validators_hash | Bytes | Validators information hash |
next_validators_hash | Bytes | Validators information hash |
consensus_hash | Bytes | Consensus information hash |
app_hash | Bytes | Application hash |
last_result_hash | Bytes | Last result hash |
evidence_hash | Bytes | Evidence data hash |
proposer_address | String | Block proposer's address |
Consensus
Parameter | Type | Description |
---|---|---|
version | Consensus | |
chain_id | String | Chain identifier |
height | Integer | Block height |
time | Time | Block time |
last_block_id | BlockID | Previous block identifier |
last_commit_hash | Bytes | Last commit hash |
data_hash | Bytes | Block data hash |
validators_hash | Bytes | Validators information hash |
next_validators_hash | Bytes | Validators information hash |
consensus_hash | Bytes | Consensus information hash |
app_hash | Bytes | Application hash |
last_result_hash | Bytes | Last result hash |
evidence_hash | Bytes | Evidence data hash |
proposer_address | String | Block proposer's address |
Data
Parameter | Type | Description |
---|---|---|
txs | Byte Array | Txs that will be applied by state @ block.Height+1. NOTE: not all txs here are valid. We're just agreeing on the order first. This means that block.AppHash does not include these txs. |
EvidenceList
Parameter | Type | Description |
---|---|---|
evidence | Evidence Array | Block evidence |
Evidence
Parameter | Type | Description |
---|---|---|
sum | isEvidence_Sum | Valid types for 'sum' are Evidence_DuplicateVoteEvidence and Evidence_LightClientAttackEvidence |
Commit
Parameter | Type | Description |
---|---|---|
height | Integer | Block height |
round | Integer | Consensus round |
block_id | BlockID | Block identifier |
signatures | CommitSig Array | Sigantures |
CommitSig
Parameter | Type | Description |
---|---|---|
block_id_flag | BlockIDFlag | Block height |
validator_address | Bytes | Validator address |
timestamp | Time | Block time |
signature | Bytes | Block signature |
BlockIDFlag
Code | Name |
---|---|
0 | BLOCK_ID_FLAG_UNKNOWN |
1 | BLOCK_ID_FLAG_ABSENT |
2 | BLOCK_ID_FLAG_COMMIT |
3 | BLOCK_ID_FLAG_NIL |
GetBlockByHeight
Get the block for a given height
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
block = await client.fetch_block_by_height(height=15793860)
print(block)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
height := int64(23040174)
res, err := chainClient.FetchBlockByHeight(ctx, height)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description |
---|---|---|
block_id | BlockID | Block identifier |
sdk_block | Block | Block details |
Response Parameters
Response Example:
{
"blockId":{
"hash":"MNF+X0DQFIsnEJAzyTxHMD8vZChOpW4rQeSnRKBiJ1Y=",
"partSetHeader":{
"total":1,
"hash":"Fqg81sOmF9dqH8lORXGat/mOFyqh52/lSHvsehg9OWk="
}
},
"block":{
"header":{
"version":{
"block":"11",
"app":"0"
},
"chainId":"injective-888",
"height":"15793860",
"time":"2023-09-07T03:59:36.393462082Z",
"lastBlockId":{
"hash":"RRhRSiIf1E08mJAtACM4J1RFSVJ96eR0PBVuoD7rb2c=",
"partSetHeader":{
"total":1,
"hash":"SeO5JkVtLUrhegd0rwDatDbvS5PQf/0Yvn+BmL1MOko="
}
},
"lastCommitHash":"rNxjhSihfCPkPMak9qPlmUYeXRc0weFu1nmmKMUPLAQ=",
"dataHash":"1RjS2VAhrWt2lLnVLozfeI7oAi7PoDILROzeheXN5H0=",
"validatorsHash":"6lDaVNHY4DtceWtHsVS7SdR8XuPSATqQ7qNKWIxcnhg=",
"nextValidatorsHash":"6lDaVNHY4DtceWtHsVS7SdR8XuPSATqQ7qNKWIxcnhg=",
"consensusHash":"ItjUyLlUnqkCxmoaGPck+PeXC45MXx6zsLXxtOHeBTE=",
"appHash":"Sv2MdUKQxwE/glEI8c8RFQKmc4HSyKO7j3sAqySultQ=",
"lastResultsHash":"Le4RmI//Wh43Mq6ro+VMWn7ZbVZRw3HXUAQILODtag8=",
"evidenceHash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"proposerAddress":"ObUXYdS8jfTSNPonUBFPJkft7eA="
},
"data":{
"txs":[
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajF3bGY1NzdtbHd0eW01N3Njem1semtsN2tjdDAycXNsZHN4Z2p2NxIqaW5qMXIyNDh5c3IyeTQwcW0yazgzMHZhbnF4bm02dmNtbGhxcnVtczJlGhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajF3bGY1NzdtbHd0eW01N3Njem1semtsN2tjdDAycXNsZHN4Z2p2NxIqaW5qMXIyNDh5c3IyeTQwcW0yazgzMHZhbnF4bm02dmNtbGhxcnVtczJlGj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMXdsZjU3N21sd3R5bTU3c2N6bWx6a2w3a2N0MDJxc2xkc3hnanY3EippbmoxcjI0OHlzcjJ5NDBxbTJrODMwdmFucXhubTZ2Y21saHFydW1zMmUaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajF3bGY1NzdtbHd0eW01N3Njem1semtsN2tjdDAycXNsZHN4Z2p2NxIqaW5qMXIyNDh5c3IyeTQwcW0yazgzMHZhbnF4bm02dmNtbGhxcnVtczJlGkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMXdsZjU3N21sd3R5bTU3c2N6bWx6a2w3a2N0MDJxc2xkc3hnanY3EippbmoxcjI0OHlzcjJ5NDBxbTJrODMwdmFucXhubTZ2Y21saHFydW1zMmUaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajF3bGY1NzdtbHd0eW01N3Njem1semtsN2tjdDAycXNsZHN4Z2p2NxIqaW5qMXIyNDh5c3IyeTQwcW0yazgzMHZhbnF4bm02dmNtbGhxcnVtczJlGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajF3bGY1NzdtbHd0eW01N3Njem1semtsN2tjdDAycXNsZHN4Z2p2NxIqaW5qMXIyNDh5c3IyeTQwcW0yazgzMHZhbnF4bm02dmNtbGhxcnVtczJlGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajF3bGY1NzdtbHd0eW01N3Njem1semtsN2tjdDAycXNsZHN4Z2p2NxIqaW5qMXIyNDh5c3IyeTQwcW0yazgzMHZhbnF4bm02dmNtbGhxcnVtczJlGkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJz+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohAjr+rkaXrlMyQvUjnSB+viWNMY4CU7VHptUN/MxDVEOVEgQKAggBGLymARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkCHh6hdDRsHw1dfkRZkwLOmP7uNT6RSwNJPIBf8dg1bsnLtzAhpBlAd1nF1V7oWvAvoZ/gVoiNVdzjCWYYcUB/s",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajFwMmh2N2Z6NnY3ZTk5c3dramZhNjllcmhjaGNkeGgya3l4cWp6axIqaW5qMWN6dGw4aDU4bDh6Y3YyM2xtMHpyOGg4cnlzdTVoeGNmZ2Q1MHl1GhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajFwMmh2N2Z6NnY3ZTk5c3dramZhNjllcmhjaGNkeGgya3l4cWp6axIqaW5qMWN6dGw4aDU4bDh6Y3YyM2xtMHpyOGg4cnlzdTVoeGNmZ2Q1MHl1Gj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMXAyaHY3Zno2djdlOTlzd2tqZmE2OWVyaGNoY2R4aDJreXhxanprEippbmoxY3p0bDhoNThsOHpjdjIzbG0wenI4aDhyeXN1NWh4Y2ZnZDUweXUaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajFwMmh2N2Z6NnY3ZTk5c3dramZhNjllcmhjaGNkeGgya3l4cWp6axIqaW5qMWN6dGw4aDU4bDh6Y3YyM2xtMHpyOGg4cnlzdTVoeGNmZ2Q1MHl1GkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMXAyaHY3Zno2djdlOTlzd2tqZmE2OWVyaGNoY2R4aDJreXhxanprEippbmoxY3p0bDhoNThsOHpjdjIzbG0wenI4aDhyeXN1NWh4Y2ZnZDUweXUaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFwMmh2N2Z6NnY3ZTk5c3dramZhNjllcmhjaGNkeGgya3l4cWp6axIqaW5qMWN6dGw4aDU4bDh6Y3YyM2xtMHpyOGg4cnlzdTVoeGNmZ2Q1MHl1GkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFwMmh2N2Z6NnY3ZTk5c3dramZhNjllcmhjaGNkeGgya3l4cWp6axIqaW5qMWN6dGw4aDU4bDh6Y3YyM2xtMHpyOGg4cnlzdTVoeGNmZ2Q1MHl1GkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajFwMmh2N2Z6NnY3ZTk5c3dramZhNjllcmhjaGNkeGgya3l4cWp6axIqaW5qMWN6dGw4aDU4bDh6Y3YyM2xtMHpyOGg4cnlzdTVoeGNmZ2Q1MHl1GkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJz+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohA3SZsAXlR9pzcFHog/kjOFSR1EiYHVqNOnWpNWiq7NcuEgQKAggBGNmNARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkA0yE1i3DE6GGITZpVWhESrrYNgKdPRPYKCAnz9QcAdEkwOLHJ9HgOz2Ok9NhjFN5akpyxZTKRGTFX11//hT3Wd",
"CugFCrgECjgvaW5qZWN0aXZlLmV4Y2hhbmdlLnYxYmV0YTEuTXNnUHJpdmlsZWdlZEV4ZWN1dGVDb250cmFjdBL7AwoqaW5qMWV6dGttMzZ5NmMzZTZ6bXI0aGc0Zzc3YTZ3eWoweGMwZDVneDV2EngxMDIwMDAwMDAwIGZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3VzZGMsIDExMDAgcGVnZ3kweDg3YUIzQjRDODY2MWUwN0Q2MzcyMzYxMjExQjk2ZWQ0RGMzNkIxQjUaKmluajE3cTdkczB5aDdoaHR1c2ZmN2d6OGE1a3gydXd4cnV0dGx4dXI5NiKmAnsiYXJncyI6eyJtc2ciOnsic3Vic2NyaWJlIjp7fX0sInRyYWRlcl9zdWJhY2NvdW50X2lkIjoiMHhjODk3NmRjNzQ0ZDYyMzlkMGI2M2FkZDE1NDdiZGRkMzg5Mjc5YjBmMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwIiwidmF1bHRfc3ViYWNjb3VudF9pZCI6IjB4ZjAzY2Q4M2M5N2Y1ZWViZTQxMjlmMjA0N2VkMmM2NTcxYzYxZjE2YjAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMyJ9LCJuYW1lIjoiVmF1bHRTdWJzY3JpYmUiLCJvcmlnaW4iOiJpbmoxZXp0a20zNnk2YzNlNnptcjRoZzRnNzdhNnd5ajB4YzBkNWd4NXYifRjp/cMH+j+kAQovL2luamVjdGl2ZS50eXBlcy52MWJldGExLkV4dGVuc2lvbk9wdGlvbnNXZWIzVHgScQgFEippbmoxN2drdWV0OGY2cHNzeGQ4bnljbTNxcjlkOXk2OTlydXB2NjM5N3oaQS7bNDH7L/B112pVzWT5OTygLht+2aFCIbvRfdlbaJqFAEXaPzWWgHCwBc4C3bCN22c8OHvjiS4ExPfg9EKkTKgAEn4KXgpUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohAp46ZxDpNDxsP5gvCZkCc84ZllP7P7q0tL57X7fN0WOcEgQKAgh/GGYSHAoWCgNpbmoSDzM2Mjg2MjUwMDAwMDAwMBDdpSwaQXHoIQ/X5yai6B0reASgAArSShjzpxprthDLEyr+zX7GR07Hr+r8UmZftLbafrcZfRX2UwFw8Q8pHaMINsSjckgb",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajE5dXE4Z2Rta3hxZnJnaHRlazQ5d2E4azJmOGhobTN4ZTZ2OXZ4eBIqaW5qMXc5cnY1dTM1NWtlMDdjamY0d2cwd2EyY3ZhdG1keWNkaDZud2czGhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajE5dXE4Z2Rta3hxZnJnaHRlazQ5d2E4azJmOGhobTN4ZTZ2OXZ4eBIqaW5qMXc5cnY1dTM1NWtlMDdjamY0d2cwd2EyY3ZhdG1keWNkaDZud2czGj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMTl1cThnZG1reHFmcmdodGVrNDl3YThrMmY4aGhtM3hlNnY5dnh4EippbmoxdzlydjV1MzU1a2UwN2NqZjR3ZzB3YTJjdmF0bWR5Y2RoNm53ZzMaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajE5dXE4Z2Rta3hxZnJnaHRlazQ5d2E4azJmOGhobTN4ZTZ2OXZ4eBIqaW5qMXc5cnY1dTM1NWtlMDdjamY0d2cwd2EyY3ZhdG1keWNkaDZud2czGkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMTl1cThnZG1reHFmcmdodGVrNDl3YThrMmY4aGhtM3hlNnY5dnh4EippbmoxdzlydjV1MzU1a2UwN2NqZjR3ZzB3YTJjdmF0bWR5Y2RoNm53ZzMaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajE5dXE4Z2Rta3hxZnJnaHRlazQ5d2E4azJmOGhobTN4ZTZ2OXZ4eBIqaW5qMXc5cnY1dTM1NWtlMDdjamY0d2cwd2EyY3ZhdG1keWNkaDZud2czGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajE5dXE4Z2Rta3hxZnJnaHRlazQ5d2E4azJmOGhobTN4ZTZ2OXZ4eBIqaW5qMXc5cnY1dTM1NWtlMDdjamY0d2cwd2EyY3ZhdG1keWNkaDZud2czGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajE5dXE4Z2Rta3hxZnJnaHRlazQ5d2E4azJmOGhobTN4ZTZ2OXZ4eBIqaW5qMXc5cnY1dTM1NWtlMDdjamY0d2cwd2EyY3ZhdG1keWNkaDZud2czGkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJ3+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohA9YRhWDK9v8bR+HRAI7OzzTaeuCFfDffiIO9zTWhbk4cEgQKAggBGMmeARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkBAcshkCtJATtQYYHVorDRUSOGQ7gR1bLp17ZXO5S5aTmB+pRc+/uz8cY3zfP28wpZE4BFa40sSn+vsN7YDc0Ne",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajFocXJzbWZsdjc2dDB3MGZxcm16d3p4dHhxdWUzNG12MzRtc3h2bRIqaW5qMXVsMjM1c2ZwZm55bWNnOGdodXQ5OHV3c251NjlsbnpuYTN6ZGpkGhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajFocXJzbWZsdjc2dDB3MGZxcm16d3p4dHhxdWUzNG12MzRtc3h2bRIqaW5qMXVsMjM1c2ZwZm55bWNnOGdodXQ5OHV3c251NjlsbnpuYTN6ZGpkGj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMWhxcnNtZmx2NzZ0MHcwZnFybXp3enh0eHF1ZTM0bXYzNG1zeHZtEippbmoxdWwyMzVzZnBmbnltY2c4Z2h1dDk4dXdzbnU2OWxuem5hM3pkamQaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajFocXJzbWZsdjc2dDB3MGZxcm16d3p4dHhxdWUzNG12MzRtc3h2bRIqaW5qMXVsMjM1c2ZwZm55bWNnOGdodXQ5OHV3c251NjlsbnpuYTN6ZGpkGkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMWhxcnNtZmx2NzZ0MHcwZnFybXp3enh0eHF1ZTM0bXYzNG1zeHZtEippbmoxdWwyMzVzZnBmbnltY2c4Z2h1dDk4dXdzbnU2OWxuem5hM3pkamQaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFocXJzbWZsdjc2dDB3MGZxcm16d3p4dHhxdWUzNG12MzRtc3h2bRIqaW5qMXVsMjM1c2ZwZm55bWNnOGdodXQ5OHV3c251NjlsbnpuYTN6ZGpkGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFocXJzbWZsdjc2dDB3MGZxcm16d3p4dHhxdWUzNG12MzRtc3h2bRIqaW5qMXVsMjM1c2ZwZm55bWNnOGdodXQ5OHV3c251NjlsbnpuYTN6ZGpkGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajFocXJzbWZsdjc2dDB3MGZxcm16d3p4dHhxdWUzNG12MzRtc3h2bRIqaW5qMXVsMjM1c2ZwZm55bWNnOGdodXQ5OHV3c251NjlsbnpuYTN6ZGpkGkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJ3+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohAimG00m9nDJwqtOiErp8o619mH/3VcEADzWzSqGpnGdIEgQKAggBGLuRARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkCnWeua6pt6p7Te8JuofcIaJWaZEhgiOuFqskm9sjQ9yi5qJkOEQXCmCRFCS5uYBpk0/1tuwYXJwtro9GdxHJMI",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajFnMG04cTNrZHczMzNzeHEyOXc3bmMzNm1mZmN2aDgwZ3ZjZDM5ZBIqaW5qMW45d2ZoN2E2Y2cydWdneWdhZDlhZGxqODNhNHl3ZHp1dmhybXB2GhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajFnMG04cTNrZHczMzNzeHEyOXc3bmMzNm1mZmN2aDgwZ3ZjZDM5ZBIqaW5qMW45d2ZoN2E2Y2cydWdneWdhZDlhZGxqODNhNHl3ZHp1dmhybXB2Gj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMWcwbThxM2tkdzMzM3N4cTI5dzduYzM2bWZmY3ZoODBndmNkMzlkEippbmoxbjl3Zmg3YTZjZzJ1Z2d5Z2FkOWFkbGo4M2E0eXdkenV2aHJtcHYaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajFnMG04cTNrZHczMzNzeHEyOXc3bmMzNm1mZmN2aDgwZ3ZjZDM5ZBIqaW5qMW45d2ZoN2E2Y2cydWdneWdhZDlhZGxqODNhNHl3ZHp1dmhybXB2GkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMWcwbThxM2tkdzMzM3N4cTI5dzduYzM2bWZmY3ZoODBndmNkMzlkEippbmoxbjl3Zmg3YTZjZzJ1Z2d5Z2FkOWFkbGo4M2E0eXdkenV2aHJtcHYaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFnMG04cTNrZHczMzNzeHEyOXc3bmMzNm1mZmN2aDgwZ3ZjZDM5ZBIqaW5qMW45d2ZoN2E2Y2cydWdneWdhZDlhZGxqODNhNHl3ZHp1dmhybXB2GkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFnMG04cTNrZHczMzNzeHEyOXc3bmMzNm1mZmN2aDgwZ3ZjZDM5ZBIqaW5qMW45d2ZoN2E2Y2cydWdneWdhZDlhZGxqODNhNHl3ZHp1dmhybXB2GkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajFnMG04cTNrZHczMzNzeHEyOXc3bmMzNm1mZmN2aDgwZ3ZjZDM5ZBIqaW5qMW45d2ZoN2E2Y2cydWdneWdhZDlhZGxqODNhNHl3ZHp1dmhybXB2GkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJ3+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohAhKZIyozzEpDEuAl3ypUW3R3JoD7AtBIAujqq4wwPfVdEgQKAggBGOufARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkDMNT7feu38IDUKGBHpWaoydtomgYQZjGPXjj7pb8fEj0MshAm2XfDad53SLdLeKmsXMjQ5cXyYyH15EwUxDYSU",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajFueHpoZTk0Z3NjOWpzeXVjM3dxa3Vuanl2czhwNGVtZTBndTRrZRIqaW5qMWxxa2dyZGxoeXFreTN3ZzZybW54ZGo1a3d0ZXI3NGUydWowbWZmGhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajFueHpoZTk0Z3NjOWpzeXVjM3dxa3Vuanl2czhwNGVtZTBndTRrZRIqaW5qMWxxa2dyZGxoeXFreTN3ZzZybW54ZGo1a3d0ZXI3NGUydWowbWZmGj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMW54emhlOTRnc2M5anN5dWMzd3FrdW5qeXZzOHA0ZW1lMGd1NGtlEippbmoxbHFrZ3JkbGh5cWt5M3dnNnJtbnhkajVrd3Rlcjc0ZTJ1ajBtZmYaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajFueHpoZTk0Z3NjOWpzeXVjM3dxa3Vuanl2czhwNGVtZTBndTRrZRIqaW5qMWxxa2dyZGxoeXFreTN3ZzZybW54ZGo1a3d0ZXI3NGUydWowbWZmGkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMW54emhlOTRnc2M5anN5dWMzd3FrdW5qeXZzOHA0ZW1lMGd1NGtlEippbmoxbHFrZ3JkbGh5cWt5M3dnNnJtbnhkajVrd3Rlcjc0ZTJ1ajBtZmYaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFueHpoZTk0Z3NjOWpzeXVjM3dxa3Vuanl2czhwNGVtZTBndTRrZRIqaW5qMWxxa2dyZGxoeXFreTN3ZzZybW54ZGo1a3d0ZXI3NGUydWowbWZmGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFueHpoZTk0Z3NjOWpzeXVjM3dxa3Vuanl2czhwNGVtZTBndTRrZRIqaW5qMWxxa2dyZGxoeXFreTN3ZzZybW54ZGo1a3d0ZXI3NGUydWowbWZmGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajFueHpoZTk0Z3NjOWpzeXVjM3dxa3Vuanl2czhwNGVtZTBndTRrZRIqaW5qMWxxa2dyZGxoeXFreTN3ZzZybW54ZGo1a3d0ZXI3NGUydWowbWZmGkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJ3+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohAxg89Ih7H74zbkYrMXXb55tjKWTQJQ3D2Sk00p5Y0/ZEEgQKAggBGIqVARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkCo/7pJIihg01V2zd+y3WH++KyVIB4m7WC9DAHPRzJIAghGLVJkAJjzGWTHrIGlh7CIira+E0UeSdy1Ag4GMBfS",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajE5Y2hlY3h3enVmZjA5Zm02NmM1MDN4MnJtZmowa3l6emZoM2Z0ZhIqaW5qMWt0djIyYXp2dDVoOG5xejQ4d25ocXNqOTZ1bGU0eHgwZGF3N2pqGhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajE5Y2hlY3h3enVmZjA5Zm02NmM1MDN4MnJtZmowa3l6emZoM2Z0ZhIqaW5qMWt0djIyYXp2dDVoOG5xejQ4d25ocXNqOTZ1bGU0eHgwZGF3N2pqGj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMTljaGVjeHd6dWZmMDlmbTY2YzUwM3gycm1majBreXp6ZmgzZnRmEippbmoxa3R2MjJhenZ0NWg4bnF6NDh3bmhxc2o5NnVsZTR4eDBkYXc3amoaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajE5Y2hlY3h3enVmZjA5Zm02NmM1MDN4MnJtZmowa3l6emZoM2Z0ZhIqaW5qMWt0djIyYXp2dDVoOG5xejQ4d25ocXNqOTZ1bGU0eHgwZGF3N2pqGkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMTljaGVjeHd6dWZmMDlmbTY2YzUwM3gycm1majBreXp6ZmgzZnRmEippbmoxa3R2MjJhenZ0NWg4bnF6NDh3bmhxc2o5NnVsZTR4eDBkYXc3amoaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajE5Y2hlY3h3enVmZjA5Zm02NmM1MDN4MnJtZmowa3l6emZoM2Z0ZhIqaW5qMWt0djIyYXp2dDVoOG5xejQ4d25ocXNqOTZ1bGU0eHgwZGF3N2pqGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajE5Y2hlY3h3enVmZjA5Zm02NmM1MDN4MnJtZmowa3l6emZoM2Z0ZhIqaW5qMWt0djIyYXp2dDVoOG5xejQ4d25ocXNqOTZ1bGU0eHgwZGF3N2pqGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajE5Y2hlY3h3enVmZjA5Zm02NmM1MDN4MnJtZmowa3l6emZoM2Z0ZhIqaW5qMWt0djIyYXp2dDVoOG5xejQ4d25ocXNqOTZ1bGU0eHgwZGF3N2pqGkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJ3+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohAgVaAkMOV5+9OJP2xYw3tKy3aU3SiAIummY3gRAIGDj/EgQKAggBGOihARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkBSSP+Fx12//aSYEjjLjr5gl5X4jOUktkOREMTfArsWVxl4Xl7cyV3f7kYAF7kBbQQqrgMerHsc9KePhRVoXB0k",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajFwMzBra2w2dXh5YWhtOGhmMGVkOGY0MDJmNjdhMmo5eHJjNDJ5ZhIqaW5qMXo1ZzRwYXA3YThoaHhhYXkycG5md2czYXduNWRxcDVyNHN2OGthGhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajFwMzBra2w2dXh5YWhtOGhmMGVkOGY0MDJmNjdhMmo5eHJjNDJ5ZhIqaW5qMXo1ZzRwYXA3YThoaHhhYXkycG5md2czYXduNWRxcDVyNHN2OGthGj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMXAzMGtrbDZ1eHlhaG04aGYwZWQ4ZjQwMmY2N2Eyajl4cmM0MnlmEippbmoxejVnNHBhcDdhOGhoeGFheTJwbmZ3ZzNhd241ZHFwNXI0c3Y4a2EaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajFwMzBra2w2dXh5YWhtOGhmMGVkOGY0MDJmNjdhMmo5eHJjNDJ5ZhIqaW5qMXo1ZzRwYXA3YThoaHhhYXkycG5md2czYXduNWRxcDVyNHN2OGthGkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMXAzMGtrbDZ1eHlhaG04aGYwZWQ4ZjQwMmY2N2Eyajl4cmM0MnlmEippbmoxejVnNHBhcDdhOGhoeGFheTJwbmZ3ZzNhd241ZHFwNXI0c3Y4a2EaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFwMzBra2w2dXh5YWhtOGhmMGVkOGY0MDJmNjdhMmo5eHJjNDJ5ZhIqaW5qMXo1ZzRwYXA3YThoaHhhYXkycG5md2czYXduNWRxcDVyNHN2OGthGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFwMzBra2w2dXh5YWhtOGhmMGVkOGY0MDJmNjdhMmo5eHJjNDJ5ZhIqaW5qMXo1ZzRwYXA3YThoaHhhYXkycG5md2czYXduNWRxcDVyNHN2OGthGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajFwMzBra2w2dXh5YWhtOGhmMGVkOGY0MDJmNjdhMmo5eHJjNDJ5ZhIqaW5qMXo1ZzRwYXA3YThoaHhhYXkycG5md2czYXduNWRxcDVyNHN2OGthGkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJ3+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohAl0obf7huaZwDxwoKhqdWfwakrBU8rFlrc/Ihiquc4P5EgQKAggBGIOAARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkCGyhKBN8mu+4qID3ZzBPskvusEorT6TXytayPg3k6UpGMaLx38dXS9wmX2yrLrn4G67rihS/fKVCG2yMhdwk4y",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajE0dDVmOTRtNWZnNHY2ZHJzNHFxa2QzZDczM3k2c3MwbGp5eXFsbRIqaW5qMWhtOXVobWhrZHRyeXd6MG1xazh2YTQwMmUzdWQweXBqbHFmcjNqGhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajE0dDVmOTRtNWZnNHY2ZHJzNHFxa2QzZDczM3k2c3MwbGp5eXFsbRIqaW5qMWhtOXVobWhrZHRyeXd6MG1xazh2YTQwMmUzdWQweXBqbHFmcjNqGj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMTR0NWY5NG01Zmc0djZkcnM0cXFrZDNkNzMzeTZzczBsanl5cWxtEippbmoxaG05dWhtaGtkdHJ5d3owbXFrOHZhNDAyZTN1ZDB5cGpscWZyM2oaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajE0dDVmOTRtNWZnNHY2ZHJzNHFxa2QzZDczM3k2c3MwbGp5eXFsbRIqaW5qMWhtOXVobWhrZHRyeXd6MG1xazh2YTQwMmUzdWQweXBqbHFmcjNqGkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMTR0NWY5NG01Zmc0djZkcnM0cXFrZDNkNzMzeTZzczBsanl5cWxtEippbmoxaG05dWhtaGtkdHJ5d3owbXFrOHZhNDAyZTN1ZDB5cGpscWZyM2oaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajE0dDVmOTRtNWZnNHY2ZHJzNHFxa2QzZDczM3k2c3MwbGp5eXFsbRIqaW5qMWhtOXVobWhrZHRyeXd6MG1xazh2YTQwMmUzdWQweXBqbHFmcjNqGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajE0dDVmOTRtNWZnNHY2ZHJzNHFxa2QzZDczM3k2c3MwbGp5eXFsbRIqaW5qMWhtOXVobWhrZHRyeXd6MG1xazh2YTQwMmUzdWQweXBqbHFmcjNqGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajE0dDVmOTRtNWZnNHY2ZHJzNHFxa2QzZDczM3k2c3MwbGp5eXFsbRIqaW5qMWhtOXVobWhrZHRyeXd6MG1xazh2YTQwMmUzdWQweXBqbHFmcjNqGkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJ3+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohA4fTy5A+DmuZfsXgjM48ntVqTXlOBW287TjXr91D0VGREgQKAggBGLuVARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkBdYIUr7S8ky4p9g+WWi2Ef8Cnq9W5eRsQ6Q6YNcnr0rhzy6lgo31o9tJg6XB0ZHtaJb00qBdU8/igNmfhEZXqk",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajFhNHc5OXo0cWdxY2Q2bDZ1NGRqZnlsY3VjdDUzZHVxa3VxbnI1ZBIqaW5qMTUyNmszNmNrM2xodm1yZzhzeXlhODd0eTY5dXBsOHl6enJrNWZxGhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajFhNHc5OXo0cWdxY2Q2bDZ1NGRqZnlsY3VjdDUzZHVxa3VxbnI1ZBIqaW5qMTUyNmszNmNrM2xodm1yZzhzeXlhODd0eTY5dXBsOHl6enJrNWZxGj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMWE0dzk5ejRxZ3FjZDZsNnU0ZGpmeWxjdWN0NTNkdXFrdXFucjVkEippbmoxNTI2azM2Y2szbGh2bXJnOHN5eWE4N3R5Njl1cGw4eXp6cms1ZnEaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajFhNHc5OXo0cWdxY2Q2bDZ1NGRqZnlsY3VjdDUzZHVxa3VxbnI1ZBIqaW5qMTUyNmszNmNrM2xodm1yZzhzeXlhODd0eTY5dXBsOHl6enJrNWZxGkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMWE0dzk5ejRxZ3FjZDZsNnU0ZGpmeWxjdWN0NTNkdXFrdXFucjVkEippbmoxNTI2azM2Y2szbGh2bXJnOHN5eWE4N3R5Njl1cGw4eXp6cms1ZnEaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFhNHc5OXo0cWdxY2Q2bDZ1NGRqZnlsY3VjdDUzZHVxa3VxbnI1ZBIqaW5qMTUyNmszNmNrM2xodm1yZzhzeXlhODd0eTY5dXBsOHl6enJrNWZxGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFhNHc5OXo0cWdxY2Q2bDZ1NGRqZnlsY3VjdDUzZHVxa3VxbnI1ZBIqaW5qMTUyNmszNmNrM2xodm1yZzhzeXlhODd0eTY5dXBsOHl6enJrNWZxGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajFhNHc5OXo0cWdxY2Q2bDZ1NGRqZnlsY3VjdDUzZHVxa3VxbnI1ZBIqaW5qMTUyNmszNmNrM2xodm1yZzhzeXlhODd0eTY5dXBsOHl6enJrNWZxGkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJ3+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohArGVpE2Qtw7Pq625UTe8FZfqFAGc7IaBTZYPusGkLfnlEgQKAggBGMmAARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkDk8e2Du8ReB4Jz73ZkpdaWHIBSo5x0XtILIMecnJzbQ3TykogSC6OQ+tWOCFQp9mUhff++iCbVpFwAx08k+zYS",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajFnZHZ0ZGtsdjNxZzQzM3Z1bjlqYXBhZGFucjk2MHgwdTI0cWtxbBIqaW5qMWFlYTRtOGZhcnc5ZHI5Y204N2FnN2QwejZtY2ZwMm54bnYyOGE3GhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajFnZHZ0ZGtsdjNxZzQzM3Z1bjlqYXBhZGFucjk2MHgwdTI0cWtxbBIqaW5qMWFlYTRtOGZhcnc5ZHI5Y204N2FnN2QwejZtY2ZwMm54bnYyOGE3Gj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMWdkdnRka2x2M3FnNDMzdnVuOWphcGFkYW5yOTYweDB1MjRxa3FsEippbmoxYWVhNG04ZmFydzlkcjljbTg3YWc3ZDB6Nm1jZnAybnhudjI4YTcaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajFnZHZ0ZGtsdjNxZzQzM3Z1bjlqYXBhZGFucjk2MHgwdTI0cWtxbBIqaW5qMWFlYTRtOGZhcnc5ZHI5Y204N2FnN2QwejZtY2ZwMm54bnYyOGE3GkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMWdkdnRka2x2M3FnNDMzdnVuOWphcGFkYW5yOTYweDB1MjRxa3FsEippbmoxYWVhNG04ZmFydzlkcjljbTg3YWc3ZDB6Nm1jZnAybnhudjI4YTcaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFnZHZ0ZGtsdjNxZzQzM3Z1bjlqYXBhZGFucjk2MHgwdTI0cWtxbBIqaW5qMWFlYTRtOGZhcnc5ZHI5Y204N2FnN2QwejZtY2ZwMm54bnYyOGE3GkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFnZHZ0ZGtsdjNxZzQzM3Z1bjlqYXBhZGFucjk2MHgwdTI0cWtxbBIqaW5qMWFlYTRtOGZhcnc5ZHI5Y204N2FnN2QwejZtY2ZwMm54bnYyOGE3GkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajFnZHZ0ZGtsdjNxZzQzM3Z1bjlqYXBhZGFucjk2MHgwdTI0cWtxbBIqaW5qMWFlYTRtOGZhcnc5ZHI5Y204N2FnN2QwejZtY2ZwMm54bnYyOGE3GkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJ3+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohAz+Zjrtxo20HOm1w4l5I57H9MAmt+87msPR5/1R/D1McEgQKAggBGMSqARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkDhGCp0+Crr0dfoCZrTb5otuTMtIxxTj9tWfxrfN7cnBTEgKFXVDlsXbay4Wlxz4QBVX4Fb6gtUgQbtDrazOEj9",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajFobm1kbGVhdHR1N3RldHU2ZWt3dzlybTBjbTAzZXpnNWpsdHJxehIqaW5qMW02M3U1eWtzYWdzc2o3d2N4Zmw1czd0NHU4N2s3MGpmeW5uazJqGhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajFobm1kbGVhdHR1N3RldHU2ZWt3dzlybTBjbTAzZXpnNWpsdHJxehIqaW5qMW02M3U1eWtzYWdzc2o3d2N4Zmw1czd0NHU4N2s3MGpmeW5uazJqGj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMWhubWRsZWF0dHU3dGV0dTZla3d3OXJtMGNtMDNlemc1amx0cnF6EippbmoxbTYzdTV5a3NhZ3Nzajd3Y3hmbDVzN3Q0dTg3azcwamZ5bm5rMmoaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajFobm1kbGVhdHR1N3RldHU2ZWt3dzlybTBjbTAzZXpnNWpsdHJxehIqaW5qMW02M3U1eWtzYWdzc2o3d2N4Zmw1czd0NHU4N2s3MGpmeW5uazJqGkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMWhubWRsZWF0dHU3dGV0dTZla3d3OXJtMGNtMDNlemc1amx0cnF6EippbmoxbTYzdTV5a3NhZ3Nzajd3Y3hmbDVzN3Q0dTg3azcwamZ5bm5rMmoaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFobm1kbGVhdHR1N3RldHU2ZWt3dzlybTBjbTAzZXpnNWpsdHJxehIqaW5qMW02M3U1eWtzYWdzc2o3d2N4Zmw1czd0NHU4N2s3MGpmeW5uazJqGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFobm1kbGVhdHR1N3RldHU2ZWt3dzlybTBjbTAzZXpnNWpsdHJxehIqaW5qMW02M3U1eWtzYWdzc2o3d2N4Zmw1czd0NHU4N2s3MGpmeW5uazJqGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajFobm1kbGVhdHR1N3RldHU2ZWt3dzlybTBjbTAzZXpnNWpsdHJxehIqaW5qMW02M3U1eWtzYWdzc2o3d2N4Zmw1czd0NHU4N2s3MGpmeW5uazJqGkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJ3+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohA+OlGuxc2hUmrU+iVLb2MDnHy6W4exQyJrbMie9/Sv27EgQKAggBGJqQARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkBTfe9A/RDSoHQCDunT60QgdtBrz3eIGvIgLEISRMAh/2w3+A9UB5SoDNGZNUfpNsxZyyq2Emi6pXuVpFzUCjI5"
]
},
"evidence":{
"evidence":[
]
},
"lastCommit":{
"height":"15793859",
"blockId":{
"hash":"RRhRSiIf1E08mJAtACM4J1RFSVJ96eR0PBVuoD7rb2c=",
"partSetHeader":{
"total":1,
"hash":"SeO5JkVtLUrhegd0rwDatDbvS5PQf/0Yvn+BmL1MOko="
}
},
"signatures":[
{
"blockIdFlag":"BLOCK_ID_FLAG_COMMIT",
"validatorAddress":"y8ctJ4QpJ0S7ZTVY7RTE4z1hS2c=",
"timestamp":"2023-09-07T03:59:36.496584825Z",
"signature":"AxnPc5AEa6jizZuKhXUAkNi4vic6miF9emyAx+uSMco7oKVwoXGDJ6L0wneNGYOqpKkMVMQm4hcnWgDBjiBLAA=="
},
{
"blockIdFlag":"BLOCK_ID_FLAG_COMMIT",
"validatorAddress":"M5HjW2EATgO+uI+h2rRES5E7174=",
"timestamp":"2023-09-07T03:59:36.293269404Z",
"signature":"mjODCd7P7xHo6Gn+6Qi6/u+FI72noRs9/vcbvpiqz7Hr5hRNhk2a2Jj2tw59GC6cURd2Q6c/CdZhXHgVqzMdAg=="
},
{
"blockIdFlag":"BLOCK_ID_FLAG_COMMIT",
"validatorAddress":"Nv8cuLE25L4mgnBx8shCmG68xfc=",
"timestamp":"2023-09-07T03:59:36.393462082Z",
"signature":"NyTk5W6WLxEbouVJ7LxSwV88FnH/CtmXkr6JczPqEehdrymqrGqT02OJLutGVsBmrPEkMhwa2BegkqvmPLJrBQ=="
},
{
"blockIdFlag":"BLOCK_ID_FLAG_COMMIT",
"validatorAddress":"ObUXYdS8jfTSNPonUBFPJkft7eA=",
"timestamp":"2023-09-07T03:59:36.296674286Z",
"signature":"OAwmf7pEjsXbwIWMD5HbzWiae6OAn0ME49FbXaRLvKIYKWSDKv9f0gprsgRJznOdj60SontlntwmvV+23MV6DQ=="
}
],
"round":0
}
},
"sdkBlock":{
"header":{
"version":{
"block":"11",
"app":"0"
},
"chainId":"injective-888",
"height":"15793860",
"time":"2023-09-07T03:59:36.393462082Z",
"lastBlockId":{
"hash":"RRhRSiIf1E08mJAtACM4J1RFSVJ96eR0PBVuoD7rb2c=",
"partSetHeader":{
"total":1,
"hash":"SeO5JkVtLUrhegd0rwDatDbvS5PQf/0Yvn+BmL1MOko="
}
},
"lastCommitHash":"rNxjhSihfCPkPMak9qPlmUYeXRc0weFu1nmmKMUPLAQ=",
"dataHash":"1RjS2VAhrWt2lLnVLozfeI7oAi7PoDILROzeheXN5H0=",
"validatorsHash":"6lDaVNHY4DtceWtHsVS7SdR8XuPSATqQ7qNKWIxcnhg=",
"nextValidatorsHash":"6lDaVNHY4DtceWtHsVS7SdR8XuPSATqQ7qNKWIxcnhg=",
"consensusHash":"ItjUyLlUnqkCxmoaGPck+PeXC45MXx6zsLXxtOHeBTE=",
"appHash":"Sv2MdUKQxwE/glEI8c8RFQKmc4HSyKO7j3sAqySultQ=",
"lastResultsHash":"Le4RmI//Wh43Mq6ro+VMWn7ZbVZRw3HXUAQILODtag8=",
"evidenceHash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"proposerAddress":"injvalcons18x63wcw5hjxlf535lgn4qy20yer7mm0qedu0la"
},
"data":{
"txs":[
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajF3bGY1NzdtbHd0eW01N3Njem1semtsN2tjdDAycXNsZHN4Z2p2NxIqaW5qMXIyNDh5c3IyeTQwcW0yazgzMHZhbnF4bm02dmNtbGhxcnVtczJlGhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajF3bGY1NzdtbHd0eW01N3Njem1semtsN2tjdDAycXNsZHN4Z2p2NxIqaW5qMXIyNDh5c3IyeTQwcW0yazgzMHZhbnF4bm02dmNtbGhxcnVtczJlGj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMXdsZjU3N21sd3R5bTU3c2N6bWx6a2w3a2N0MDJxc2xkc3hnanY3EippbmoxcjI0OHlzcjJ5NDBxbTJrODMwdmFucXhubTZ2Y21saHFydW1zMmUaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajF3bGY1NzdtbHd0eW01N3Njem1semtsN2tjdDAycXNsZHN4Z2p2NxIqaW5qMXIyNDh5c3IyeTQwcW0yazgzMHZhbnF4bm02dmNtbGhxcnVtczJlGkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMXdsZjU3N21sd3R5bTU3c2N6bWx6a2w3a2N0MDJxc2xkc3hnanY3EippbmoxcjI0OHlzcjJ5NDBxbTJrODMwdmFucXhubTZ2Y21saHFydW1zMmUaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajF3bGY1NzdtbHd0eW01N3Njem1semtsN2tjdDAycXNsZHN4Z2p2NxIqaW5qMXIyNDh5c3IyeTQwcW0yazgzMHZhbnF4bm02dmNtbGhxcnVtczJlGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajF3bGY1NzdtbHd0eW01N3Njem1semtsN2tjdDAycXNsZHN4Z2p2NxIqaW5qMXIyNDh5c3IyeTQwcW0yazgzMHZhbnF4bm02dmNtbGhxcnVtczJlGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajF3bGY1NzdtbHd0eW01N3Njem1semtsN2tjdDAycXNsZHN4Z2p2NxIqaW5qMXIyNDh5c3IyeTQwcW0yazgzMHZhbnF4bm02dmNtbGhxcnVtczJlGkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJz+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohAjr+rkaXrlMyQvUjnSB+viWNMY4CU7VHptUN/MxDVEOVEgQKAggBGLymARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkCHh6hdDRsHw1dfkRZkwLOmP7uNT6RSwNJPIBf8dg1bsnLtzAhpBlAd1nF1V7oWvAvoZ/gVoiNVdzjCWYYcUB/s",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajFwMmh2N2Z6NnY3ZTk5c3dramZhNjllcmhjaGNkeGgya3l4cWp6axIqaW5qMWN6dGw4aDU4bDh6Y3YyM2xtMHpyOGg4cnlzdTVoeGNmZ2Q1MHl1GhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajFwMmh2N2Z6NnY3ZTk5c3dramZhNjllcmhjaGNkeGgya3l4cWp6axIqaW5qMWN6dGw4aDU4bDh6Y3YyM2xtMHpyOGg4cnlzdTVoeGNmZ2Q1MHl1Gj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMXAyaHY3Zno2djdlOTlzd2tqZmE2OWVyaGNoY2R4aDJreXhxanprEippbmoxY3p0bDhoNThsOHpjdjIzbG0wenI4aDhyeXN1NWh4Y2ZnZDUweXUaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajFwMmh2N2Z6NnY3ZTk5c3dramZhNjllcmhjaGNkeGgya3l4cWp6axIqaW5qMWN6dGw4aDU4bDh6Y3YyM2xtMHpyOGg4cnlzdTVoeGNmZ2Q1MHl1GkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMXAyaHY3Zno2djdlOTlzd2tqZmE2OWVyaGNoY2R4aDJreXhxanprEippbmoxY3p0bDhoNThsOHpjdjIzbG0wenI4aDhyeXN1NWh4Y2ZnZDUweXUaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFwMmh2N2Z6NnY3ZTk5c3dramZhNjllcmhjaGNkeGgya3l4cWp6axIqaW5qMWN6dGw4aDU4bDh6Y3YyM2xtMHpyOGg4cnlzdTVoeGNmZ2Q1MHl1GkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFwMmh2N2Z6NnY3ZTk5c3dramZhNjllcmhjaGNkeGgya3l4cWp6axIqaW5qMWN6dGw4aDU4bDh6Y3YyM2xtMHpyOGg4cnlzdTVoeGNmZ2Q1MHl1GkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajFwMmh2N2Z6NnY3ZTk5c3dramZhNjllcmhjaGNkeGgya3l4cWp6axIqaW5qMWN6dGw4aDU4bDh6Y3YyM2xtMHpyOGg4cnlzdTVoeGNmZ2Q1MHl1GkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJz+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohA3SZsAXlR9pzcFHog/kjOFSR1EiYHVqNOnWpNWiq7NcuEgQKAggBGNmNARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkA0yE1i3DE6GGITZpVWhESrrYNgKdPRPYKCAnz9QcAdEkwOLHJ9HgOz2Ok9NhjFN5akpyxZTKRGTFX11//hT3Wd",
"CugFCrgECjgvaW5qZWN0aXZlLmV4Y2hhbmdlLnYxYmV0YTEuTXNnUHJpdmlsZWdlZEV4ZWN1dGVDb250cmFjdBL7AwoqaW5qMWV6dGttMzZ5NmMzZTZ6bXI0aGc0Zzc3YTZ3eWoweGMwZDVneDV2EngxMDIwMDAwMDAwIGZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3VzZGMsIDExMDAgcGVnZ3kweDg3YUIzQjRDODY2MWUwN0Q2MzcyMzYxMjExQjk2ZWQ0RGMzNkIxQjUaKmluajE3cTdkczB5aDdoaHR1c2ZmN2d6OGE1a3gydXd4cnV0dGx4dXI5NiKmAnsiYXJncyI6eyJtc2ciOnsic3Vic2NyaWJlIjp7fX0sInRyYWRlcl9zdWJhY2NvdW50X2lkIjoiMHhjODk3NmRjNzQ0ZDYyMzlkMGI2M2FkZDE1NDdiZGRkMzg5Mjc5YjBmMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwIiwidmF1bHRfc3ViYWNjb3VudF9pZCI6IjB4ZjAzY2Q4M2M5N2Y1ZWViZTQxMjlmMjA0N2VkMmM2NTcxYzYxZjE2YjAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMyJ9LCJuYW1lIjoiVmF1bHRTdWJzY3JpYmUiLCJvcmlnaW4iOiJpbmoxZXp0a20zNnk2YzNlNnptcjRoZzRnNzdhNnd5ajB4YzBkNWd4NXYifRjp/cMH+j+kAQovL2luamVjdGl2ZS50eXBlcy52MWJldGExLkV4dGVuc2lvbk9wdGlvbnNXZWIzVHgScQgFEippbmoxN2drdWV0OGY2cHNzeGQ4bnljbTNxcjlkOXk2OTlydXB2NjM5N3oaQS7bNDH7L/B112pVzWT5OTygLht+2aFCIbvRfdlbaJqFAEXaPzWWgHCwBc4C3bCN22c8OHvjiS4ExPfg9EKkTKgAEn4KXgpUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohAp46ZxDpNDxsP5gvCZkCc84ZllP7P7q0tL57X7fN0WOcEgQKAgh/GGYSHAoWCgNpbmoSDzM2Mjg2MjUwMDAwMDAwMBDdpSwaQXHoIQ/X5yai6B0reASgAArSShjzpxprthDLEyr+zX7GR07Hr+r8UmZftLbafrcZfRX2UwFw8Q8pHaMINsSjckgb",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajE5dXE4Z2Rta3hxZnJnaHRlazQ5d2E4azJmOGhobTN4ZTZ2OXZ4eBIqaW5qMXc5cnY1dTM1NWtlMDdjamY0d2cwd2EyY3ZhdG1keWNkaDZud2czGhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajE5dXE4Z2Rta3hxZnJnaHRlazQ5d2E4azJmOGhobTN4ZTZ2OXZ4eBIqaW5qMXc5cnY1dTM1NWtlMDdjamY0d2cwd2EyY3ZhdG1keWNkaDZud2czGj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMTl1cThnZG1reHFmcmdodGVrNDl3YThrMmY4aGhtM3hlNnY5dnh4EippbmoxdzlydjV1MzU1a2UwN2NqZjR3ZzB3YTJjdmF0bWR5Y2RoNm53ZzMaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajE5dXE4Z2Rta3hxZnJnaHRlazQ5d2E4azJmOGhobTN4ZTZ2OXZ4eBIqaW5qMXc5cnY1dTM1NWtlMDdjamY0d2cwd2EyY3ZhdG1keWNkaDZud2czGkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMTl1cThnZG1reHFmcmdodGVrNDl3YThrMmY4aGhtM3hlNnY5dnh4EippbmoxdzlydjV1MzU1a2UwN2NqZjR3ZzB3YTJjdmF0bWR5Y2RoNm53ZzMaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajE5dXE4Z2Rta3hxZnJnaHRlazQ5d2E4azJmOGhobTN4ZTZ2OXZ4eBIqaW5qMXc5cnY1dTM1NWtlMDdjamY0d2cwd2EyY3ZhdG1keWNkaDZud2czGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajE5dXE4Z2Rta3hxZnJnaHRlazQ5d2E4azJmOGhobTN4ZTZ2OXZ4eBIqaW5qMXc5cnY1dTM1NWtlMDdjamY0d2cwd2EyY3ZhdG1keWNkaDZud2czGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajE5dXE4Z2Rta3hxZnJnaHRlazQ5d2E4azJmOGhobTN4ZTZ2OXZ4eBIqaW5qMXc5cnY1dTM1NWtlMDdjamY0d2cwd2EyY3ZhdG1keWNkaDZud2czGkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJ3+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohA9YRhWDK9v8bR+HRAI7OzzTaeuCFfDffiIO9zTWhbk4cEgQKAggBGMmeARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkBAcshkCtJATtQYYHVorDRUSOGQ7gR1bLp17ZXO5S5aTmB+pRc+/uz8cY3zfP28wpZE4BFa40sSn+vsN7YDc0Ne",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajFocXJzbWZsdjc2dDB3MGZxcm16d3p4dHhxdWUzNG12MzRtc3h2bRIqaW5qMXVsMjM1c2ZwZm55bWNnOGdodXQ5OHV3c251NjlsbnpuYTN6ZGpkGhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajFocXJzbWZsdjc2dDB3MGZxcm16d3p4dHhxdWUzNG12MzRtc3h2bRIqaW5qMXVsMjM1c2ZwZm55bWNnOGdodXQ5OHV3c251NjlsbnpuYTN6ZGpkGj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMWhxcnNtZmx2NzZ0MHcwZnFybXp3enh0eHF1ZTM0bXYzNG1zeHZtEippbmoxdWwyMzVzZnBmbnltY2c4Z2h1dDk4dXdzbnU2OWxuem5hM3pkamQaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajFocXJzbWZsdjc2dDB3MGZxcm16d3p4dHhxdWUzNG12MzRtc3h2bRIqaW5qMXVsMjM1c2ZwZm55bWNnOGdodXQ5OHV3c251NjlsbnpuYTN6ZGpkGkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMWhxcnNtZmx2NzZ0MHcwZnFybXp3enh0eHF1ZTM0bXYzNG1zeHZtEippbmoxdWwyMzVzZnBmbnltY2c4Z2h1dDk4dXdzbnU2OWxuem5hM3pkamQaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFocXJzbWZsdjc2dDB3MGZxcm16d3p4dHhxdWUzNG12MzRtc3h2bRIqaW5qMXVsMjM1c2ZwZm55bWNnOGdodXQ5OHV3c251NjlsbnpuYTN6ZGpkGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFocXJzbWZsdjc2dDB3MGZxcm16d3p4dHhxdWUzNG12MzRtc3h2bRIqaW5qMXVsMjM1c2ZwZm55bWNnOGdodXQ5OHV3c251NjlsbnpuYTN6ZGpkGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajFocXJzbWZsdjc2dDB3MGZxcm16d3p4dHhxdWUzNG12MzRtc3h2bRIqaW5qMXVsMjM1c2ZwZm55bWNnOGdodXQ5OHV3c251NjlsbnpuYTN6ZGpkGkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJ3+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohAimG00m9nDJwqtOiErp8o619mH/3VcEADzWzSqGpnGdIEgQKAggBGLuRARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkCnWeua6pt6p7Te8JuofcIaJWaZEhgiOuFqskm9sjQ9yi5qJkOEQXCmCRFCS5uYBpk0/1tuwYXJwtro9GdxHJMI",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajFnMG04cTNrZHczMzNzeHEyOXc3bmMzNm1mZmN2aDgwZ3ZjZDM5ZBIqaW5qMW45d2ZoN2E2Y2cydWdneWdhZDlhZGxqODNhNHl3ZHp1dmhybXB2GhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajFnMG04cTNrZHczMzNzeHEyOXc3bmMzNm1mZmN2aDgwZ3ZjZDM5ZBIqaW5qMW45d2ZoN2E2Y2cydWdneWdhZDlhZGxqODNhNHl3ZHp1dmhybXB2Gj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMWcwbThxM2tkdzMzM3N4cTI5dzduYzM2bWZmY3ZoODBndmNkMzlkEippbmoxbjl3Zmg3YTZjZzJ1Z2d5Z2FkOWFkbGo4M2E0eXdkenV2aHJtcHYaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajFnMG04cTNrZHczMzNzeHEyOXc3bmMzNm1mZmN2aDgwZ3ZjZDM5ZBIqaW5qMW45d2ZoN2E2Y2cydWdneWdhZDlhZGxqODNhNHl3ZHp1dmhybXB2GkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMWcwbThxM2tkdzMzM3N4cTI5dzduYzM2bWZmY3ZoODBndmNkMzlkEippbmoxbjl3Zmg3YTZjZzJ1Z2d5Z2FkOWFkbGo4M2E0eXdkenV2aHJtcHYaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFnMG04cTNrZHczMzNzeHEyOXc3bmMzNm1mZmN2aDgwZ3ZjZDM5ZBIqaW5qMW45d2ZoN2E2Y2cydWdneWdhZDlhZGxqODNhNHl3ZHp1dmhybXB2GkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFnMG04cTNrZHczMzNzeHEyOXc3bmMzNm1mZmN2aDgwZ3ZjZDM5ZBIqaW5qMW45d2ZoN2E2Y2cydWdneWdhZDlhZGxqODNhNHl3ZHp1dmhybXB2GkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajFnMG04cTNrZHczMzNzeHEyOXc3bmMzNm1mZmN2aDgwZ3ZjZDM5ZBIqaW5qMW45d2ZoN2E2Y2cydWdneWdhZDlhZGxqODNhNHl3ZHp1dmhybXB2GkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJ3+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohAhKZIyozzEpDEuAl3ypUW3R3JoD7AtBIAujqq4wwPfVdEgQKAggBGOufARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkDMNT7feu38IDUKGBHpWaoydtomgYQZjGPXjj7pb8fEj0MshAm2XfDad53SLdLeKmsXMjQ5cXyYyH15EwUxDYSU",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajFueHpoZTk0Z3NjOWpzeXVjM3dxa3Vuanl2czhwNGVtZTBndTRrZRIqaW5qMWxxa2dyZGxoeXFreTN3ZzZybW54ZGo1a3d0ZXI3NGUydWowbWZmGhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajFueHpoZTk0Z3NjOWpzeXVjM3dxa3Vuanl2czhwNGVtZTBndTRrZRIqaW5qMWxxa2dyZGxoeXFreTN3ZzZybW54ZGo1a3d0ZXI3NGUydWowbWZmGj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMW54emhlOTRnc2M5anN5dWMzd3FrdW5qeXZzOHA0ZW1lMGd1NGtlEippbmoxbHFrZ3JkbGh5cWt5M3dnNnJtbnhkajVrd3Rlcjc0ZTJ1ajBtZmYaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajFueHpoZTk0Z3NjOWpzeXVjM3dxa3Vuanl2czhwNGVtZTBndTRrZRIqaW5qMWxxa2dyZGxoeXFreTN3ZzZybW54ZGo1a3d0ZXI3NGUydWowbWZmGkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMW54emhlOTRnc2M5anN5dWMzd3FrdW5qeXZzOHA0ZW1lMGd1NGtlEippbmoxbHFrZ3JkbGh5cWt5M3dnNnJtbnhkajVrd3Rlcjc0ZTJ1ajBtZmYaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFueHpoZTk0Z3NjOWpzeXVjM3dxa3Vuanl2czhwNGVtZTBndTRrZRIqaW5qMWxxa2dyZGxoeXFreTN3ZzZybW54ZGo1a3d0ZXI3NGUydWowbWZmGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFueHpoZTk0Z3NjOWpzeXVjM3dxa3Vuanl2czhwNGVtZTBndTRrZRIqaW5qMWxxa2dyZGxoeXFreTN3ZzZybW54ZGo1a3d0ZXI3NGUydWowbWZmGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajFueHpoZTk0Z3NjOWpzeXVjM3dxa3Vuanl2czhwNGVtZTBndTRrZRIqaW5qMWxxa2dyZGxoeXFreTN3ZzZybW54ZGo1a3d0ZXI3NGUydWowbWZmGkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJ3+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohAxg89Ih7H74zbkYrMXXb55tjKWTQJQ3D2Sk00p5Y0/ZEEgQKAggBGIqVARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkCo/7pJIihg01V2zd+y3WH++KyVIB4m7WC9DAHPRzJIAghGLVJkAJjzGWTHrIGlh7CIira+E0UeSdy1Ag4GMBfS",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajE5Y2hlY3h3enVmZjA5Zm02NmM1MDN4MnJtZmowa3l6emZoM2Z0ZhIqaW5qMWt0djIyYXp2dDVoOG5xejQ4d25ocXNqOTZ1bGU0eHgwZGF3N2pqGhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajE5Y2hlY3h3enVmZjA5Zm02NmM1MDN4MnJtZmowa3l6emZoM2Z0ZhIqaW5qMWt0djIyYXp2dDVoOG5xejQ4d25ocXNqOTZ1bGU0eHgwZGF3N2pqGj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMTljaGVjeHd6dWZmMDlmbTY2YzUwM3gycm1majBreXp6ZmgzZnRmEippbmoxa3R2MjJhenZ0NWg4bnF6NDh3bmhxc2o5NnVsZTR4eDBkYXc3amoaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajE5Y2hlY3h3enVmZjA5Zm02NmM1MDN4MnJtZmowa3l6emZoM2Z0ZhIqaW5qMWt0djIyYXp2dDVoOG5xejQ4d25ocXNqOTZ1bGU0eHgwZGF3N2pqGkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMTljaGVjeHd6dWZmMDlmbTY2YzUwM3gycm1majBreXp6ZmgzZnRmEippbmoxa3R2MjJhenZ0NWg4bnF6NDh3bmhxc2o5NnVsZTR4eDBkYXc3amoaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajE5Y2hlY3h3enVmZjA5Zm02NmM1MDN4MnJtZmowa3l6emZoM2Z0ZhIqaW5qMWt0djIyYXp2dDVoOG5xejQ4d25ocXNqOTZ1bGU0eHgwZGF3N2pqGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajE5Y2hlY3h3enVmZjA5Zm02NmM1MDN4MnJtZmowa3l6emZoM2Z0ZhIqaW5qMWt0djIyYXp2dDVoOG5xejQ4d25ocXNqOTZ1bGU0eHgwZGF3N2pqGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajE5Y2hlY3h3enVmZjA5Zm02NmM1MDN4MnJtZmowa3l6emZoM2Z0ZhIqaW5qMWt0djIyYXp2dDVoOG5xejQ4d25ocXNqOTZ1bGU0eHgwZGF3N2pqGkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJ3+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohAgVaAkMOV5+9OJP2xYw3tKy3aU3SiAIummY3gRAIGDj/EgQKAggBGOihARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkBSSP+Fx12//aSYEjjLjr5gl5X4jOUktkOREMTfArsWVxl4Xl7cyV3f7kYAF7kBbQQqrgMerHsc9KePhRVoXB0k",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajFwMzBra2w2dXh5YWhtOGhmMGVkOGY0MDJmNjdhMmo5eHJjNDJ5ZhIqaW5qMXo1ZzRwYXA3YThoaHhhYXkycG5md2czYXduNWRxcDVyNHN2OGthGhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajFwMzBra2w2dXh5YWhtOGhmMGVkOGY0MDJmNjdhMmo5eHJjNDJ5ZhIqaW5qMXo1ZzRwYXA3YThoaHhhYXkycG5md2czYXduNWRxcDVyNHN2OGthGj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMXAzMGtrbDZ1eHlhaG04aGYwZWQ4ZjQwMmY2N2Eyajl4cmM0MnlmEippbmoxejVnNHBhcDdhOGhoeGFheTJwbmZ3ZzNhd241ZHFwNXI0c3Y4a2EaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajFwMzBra2w2dXh5YWhtOGhmMGVkOGY0MDJmNjdhMmo5eHJjNDJ5ZhIqaW5qMXo1ZzRwYXA3YThoaHhhYXkycG5md2czYXduNWRxcDVyNHN2OGthGkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMXAzMGtrbDZ1eHlhaG04aGYwZWQ4ZjQwMmY2N2Eyajl4cmM0MnlmEippbmoxejVnNHBhcDdhOGhoeGFheTJwbmZ3ZzNhd241ZHFwNXI0c3Y4a2EaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFwMzBra2w2dXh5YWhtOGhmMGVkOGY0MDJmNjdhMmo5eHJjNDJ5ZhIqaW5qMXo1ZzRwYXA3YThoaHhhYXkycG5md2czYXduNWRxcDVyNHN2OGthGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFwMzBra2w2dXh5YWhtOGhmMGVkOGY0MDJmNjdhMmo5eHJjNDJ5ZhIqaW5qMXo1ZzRwYXA3YThoaHhhYXkycG5md2czYXduNWRxcDVyNHN2OGthGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajFwMzBra2w2dXh5YWhtOGhmMGVkOGY0MDJmNjdhMmo5eHJjNDJ5ZhIqaW5qMXo1ZzRwYXA3YThoaHhhYXkycG5md2czYXduNWRxcDVyNHN2OGthGkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJ3+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohAl0obf7huaZwDxwoKhqdWfwakrBU8rFlrc/Ihiquc4P5EgQKAggBGIOAARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkCGyhKBN8mu+4qID3ZzBPskvusEorT6TXytayPg3k6UpGMaLx38dXS9wmX2yrLrn4G67rihS/fKVCG2yMhdwk4y",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajE0dDVmOTRtNWZnNHY2ZHJzNHFxa2QzZDczM3k2c3MwbGp5eXFsbRIqaW5qMWhtOXVobWhrZHRyeXd6MG1xazh2YTQwMmUzdWQweXBqbHFmcjNqGhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajE0dDVmOTRtNWZnNHY2ZHJzNHFxa2QzZDczM3k2c3MwbGp5eXFsbRIqaW5qMWhtOXVobWhrZHRyeXd6MG1xazh2YTQwMmUzdWQweXBqbHFmcjNqGj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMTR0NWY5NG01Zmc0djZkcnM0cXFrZDNkNzMzeTZzczBsanl5cWxtEippbmoxaG05dWhtaGtkdHJ5d3owbXFrOHZhNDAyZTN1ZDB5cGpscWZyM2oaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajE0dDVmOTRtNWZnNHY2ZHJzNHFxa2QzZDczM3k2c3MwbGp5eXFsbRIqaW5qMWhtOXVobWhrZHRyeXd6MG1xazh2YTQwMmUzdWQweXBqbHFmcjNqGkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMTR0NWY5NG01Zmc0djZkcnM0cXFrZDNkNzMzeTZzczBsanl5cWxtEippbmoxaG05dWhtaGtkdHJ5d3owbXFrOHZhNDAyZTN1ZDB5cGpscWZyM2oaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajE0dDVmOTRtNWZnNHY2ZHJzNHFxa2QzZDczM3k2c3MwbGp5eXFsbRIqaW5qMWhtOXVobWhrZHRyeXd6MG1xazh2YTQwMmUzdWQweXBqbHFmcjNqGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajE0dDVmOTRtNWZnNHY2ZHJzNHFxa2QzZDczM3k2c3MwbGp5eXFsbRIqaW5qMWhtOXVobWhrZHRyeXd6MG1xazh2YTQwMmUzdWQweXBqbHFmcjNqGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajE0dDVmOTRtNWZnNHY2ZHJzNHFxa2QzZDczM3k2c3MwbGp5eXFsbRIqaW5qMWhtOXVobWhrZHRyeXd6MG1xazh2YTQwMmUzdWQweXBqbHFmcjNqGkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJ3+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohA4fTy5A+DmuZfsXgjM48ntVqTXlOBW287TjXr91D0VGREgQKAggBGLuVARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkBdYIUr7S8ky4p9g+WWi2Ef8Cnq9W5eRsQ6Q6YNcnr0rhzy6lgo31o9tJg6XB0ZHtaJb00qBdU8/igNmfhEZXqk",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajFhNHc5OXo0cWdxY2Q2bDZ1NGRqZnlsY3VjdDUzZHVxa3VxbnI1ZBIqaW5qMTUyNmszNmNrM2xodm1yZzhzeXlhODd0eTY5dXBsOHl6enJrNWZxGhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajFhNHc5OXo0cWdxY2Q2bDZ1NGRqZnlsY3VjdDUzZHVxa3VxbnI1ZBIqaW5qMTUyNmszNmNrM2xodm1yZzhzeXlhODd0eTY5dXBsOHl6enJrNWZxGj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMWE0dzk5ejRxZ3FjZDZsNnU0ZGpmeWxjdWN0NTNkdXFrdXFucjVkEippbmoxNTI2azM2Y2szbGh2bXJnOHN5eWE4N3R5Njl1cGw4eXp6cms1ZnEaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajFhNHc5OXo0cWdxY2Q2bDZ1NGRqZnlsY3VjdDUzZHVxa3VxbnI1ZBIqaW5qMTUyNmszNmNrM2xodm1yZzhzeXlhODd0eTY5dXBsOHl6enJrNWZxGkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMWE0dzk5ejRxZ3FjZDZsNnU0ZGpmeWxjdWN0NTNkdXFrdXFucjVkEippbmoxNTI2azM2Y2szbGh2bXJnOHN5eWE4N3R5Njl1cGw4eXp6cms1ZnEaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFhNHc5OXo0cWdxY2Q2bDZ1NGRqZnlsY3VjdDUzZHVxa3VxbnI1ZBIqaW5qMTUyNmszNmNrM2xodm1yZzhzeXlhODd0eTY5dXBsOHl6enJrNWZxGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFhNHc5OXo0cWdxY2Q2bDZ1NGRqZnlsY3VjdDUzZHVxa3VxbnI1ZBIqaW5qMTUyNmszNmNrM2xodm1yZzhzeXlhODd0eTY5dXBsOHl6enJrNWZxGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajFhNHc5OXo0cWdxY2Q2bDZ1NGRqZnlsY3VjdDUzZHVxa3VxbnI1ZBIqaW5qMTUyNmszNmNrM2xodm1yZzhzeXlhODd0eTY5dXBsOHl6enJrNWZxGkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJ3+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohArGVpE2Qtw7Pq625UTe8FZfqFAGc7IaBTZYPusGkLfnlEgQKAggBGMmAARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkDk8e2Du8ReB4Jz73ZkpdaWHIBSo5x0XtILIMecnJzbQ3TykogSC6OQ+tWOCFQp9mUhff++iCbVpFwAx08k+zYS",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajFnZHZ0ZGtsdjNxZzQzM3Z1bjlqYXBhZGFucjk2MHgwdTI0cWtxbBIqaW5qMWFlYTRtOGZhcnc5ZHI5Y204N2FnN2QwejZtY2ZwMm54bnYyOGE3GhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajFnZHZ0ZGtsdjNxZzQzM3Z1bjlqYXBhZGFucjk2MHgwdTI0cWtxbBIqaW5qMWFlYTRtOGZhcnc5ZHI5Y204N2FnN2QwejZtY2ZwMm54bnYyOGE3Gj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMWdkdnRka2x2M3FnNDMzdnVuOWphcGFkYW5yOTYweDB1MjRxa3FsEippbmoxYWVhNG04ZmFydzlkcjljbTg3YWc3ZDB6Nm1jZnAybnhudjI4YTcaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajFnZHZ0ZGtsdjNxZzQzM3Z1bjlqYXBhZGFucjk2MHgwdTI0cWtxbBIqaW5qMWFlYTRtOGZhcnc5ZHI5Y204N2FnN2QwejZtY2ZwMm54bnYyOGE3GkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMWdkdnRka2x2M3FnNDMzdnVuOWphcGFkYW5yOTYweDB1MjRxa3FsEippbmoxYWVhNG04ZmFydzlkcjljbTg3YWc3ZDB6Nm1jZnAybnhudjI4YTcaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFnZHZ0ZGtsdjNxZzQzM3Z1bjlqYXBhZGFucjk2MHgwdTI0cWtxbBIqaW5qMWFlYTRtOGZhcnc5ZHI5Y204N2FnN2QwejZtY2ZwMm54bnYyOGE3GkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFnZHZ0ZGtsdjNxZzQzM3Z1bjlqYXBhZGFucjk2MHgwdTI0cWtxbBIqaW5qMWFlYTRtOGZhcnc5ZHI5Y204N2FnN2QwejZtY2ZwMm54bnYyOGE3GkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajFnZHZ0ZGtsdjNxZzQzM3Z1bjlqYXBhZGFucjk2MHgwdTI0cWtxbBIqaW5qMWFlYTRtOGZhcnc5ZHI5Y204N2FnN2QwejZtY2ZwMm54bnYyOGE3GkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJ3+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohAz+Zjrtxo20HOm1w4l5I57H9MAmt+87msPR5/1R/D1McEgQKAggBGMSqARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkDhGCp0+Crr0dfoCZrTb5otuTMtIxxTj9tWfxrfN7cnBTEgKFXVDlsXbay4Wlxz4QBVX4Fb6gtUgQbtDrazOEj9",
"CvMLCpUBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnUKKmluajFobm1kbGVhdHR1N3RldHU2ZWt3dzlybTBjbTAzZXpnNWpsdHJxehIqaW5qMW02M3U1eWtzYWdzc2o3d2N4Zmw1czd0NHU4N2s3MGpmeW5uazJqGhsKA2luahIUMTAwMDAwMDAwMDAwMDAwMDAwMDAKuQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSmAEKKmluajFobm1kbGVhdHR1N3RldHU2ZWt3dzlybTBjbTAzZXpnNWpsdHJxehIqaW5qMW02M3U1eWtzYWdzc2o3d2N4Zmw1czd0NHU4N2s3MGpmeW5uazJqGj4KL3BlZ2d5MHg4N2FCM0I0Qzg2NjFlMDdENjM3MjM2MTIxMUI5NmVkNERjMzZCMUI1EgsxMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMWhubWRsZWF0dHU3dGV0dTZla3d3OXJtMGNtMDNlemc1amx0cnF6EippbmoxbTYzdTV5a3NhZ3Nzajd3Y3hmbDVzN3Q0dTg3azcwamZ5bm5rMmoaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvdXNkYxILMTAwMDAwMDAwMDAKxQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSpAEKKmluajFobm1kbGVhdHR1N3RldHU2ZWt3dzlybTBjbTAzZXpnNWpsdHJxehIqaW5qMW02M3U1eWtzYWdzc2o3d2N4Zmw1czd0NHU4N2s3MGpmeW5uazJqGkoKL3BlZ2d5MHg0NEMyMWFmQWFGMjBjMjcwRUJiRjU5MTRDZmMzYjUwMjIxNzNGRUI3EhcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMArBAQocL2Nvc21vcy5iYW5rLnYxYmV0YTEuTXNnU2VuZBKgAQoqaW5qMWhubWRsZWF0dHU3dGV0dTZla3d3OXJtMGNtMDNlemc1amx0cnF6EippbmoxbTYzdTV5a3NhZ3Nzajd3Y3hmbDVzN3Q0dTg3azcwamZ5bm5rMmoaRgo3ZmFjdG9yeS9pbmoxN3Z5dGR3cWN6cXo3Mmo2NXNhdWtwbHJrdGQ0Z3lmbWU1YWdmNmMvYWF2ZRILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFobm1kbGVhdHR1N3RldHU2ZWt3dzlybTBjbTAzZXpnNWpsdHJxehIqaW5qMW02M3U1eWtzYWdzc2o3d2N4Zmw1czd0NHU4N2s3MGpmeW5uazJqGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2NydhILMTAwMDAwMDAwMDAKwAEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSnwEKKmluajFobm1kbGVhdHR1N3RldHU2ZWt3dzlybTBjbTAzZXpnNWpsdHJxehIqaW5qMW02M3U1eWtzYWdzc2o3d2N4Zmw1czd0NHU4N2s3MGpmeW5uazJqGkUKNmZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL2N2eBILMTAwMDAwMDAwMDAKwQEKHC9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQSoAEKKmluajFobm1kbGVhdHR1N3RldHU2ZWt3dzlybTBjbTAzZXpnNWpsdHJxehIqaW5qMW02M3U1eWtzYWdzc2o3d2N4Zmw1czd0NHU4N2s3MGpmeW5uazJqGkYKN2ZhY3RvcnkvaW5qMTd2eXRkd3FjenF6NzJqNjVzYXVrcGxya3RkNGd5Zm1lNWFnZjZjL3NoaWISCzEwMDAwMDAwMDAwGJ3+wwcSggEKYApUCi0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohA+OlGuxc2hUmrU+iVLb2MDnHy6W4exQyJrbMie9/Sv27EgQKAggBGJqQARIeChcKA2luahIQMTYwMDAwMDAwMDAwMDAwMBCAqMMBGkBTfe9A/RDSoHQCDunT60QgdtBrz3eIGvIgLEISRMAh/2w3+A9UB5SoDNGZNUfpNsxZyyq2Emi6pXuVpFzUCjI5"
]
},
"evidence":{
"evidence":[
]
},
"lastCommit":{
"height":"15793859",
"blockId":{
"hash":"RRhRSiIf1E08mJAtACM4J1RFSVJ96eR0PBVuoD7rb2c=",
"partSetHeader":{
"total":1,
"hash":"SeO5JkVtLUrhegd0rwDatDbvS5PQf/0Yvn+BmL1MOko="
}
},
"signatures":[
{
"blockIdFlag":"BLOCK_ID_FLAG_COMMIT",
"validatorAddress":"y8ctJ4QpJ0S7ZTVY7RTE4z1hS2c=",
"timestamp":"2023-09-07T03:59:36.496584825Z",
"signature":"AxnPc5AEa6jizZuKhXUAkNi4vic6miF9emyAx+uSMco7oKVwoXGDJ6L0wneNGYOqpKkMVMQm4hcnWgDBjiBLAA=="
},
{
"blockIdFlag":"BLOCK_ID_FLAG_COMMIT",
"validatorAddress":"M5HjW2EATgO+uI+h2rRES5E7174=",
"timestamp":"2023-09-07T03:59:36.293269404Z",
"signature":"mjODCd7P7xHo6Gn+6Qi6/u+FI72noRs9/vcbvpiqz7Hr5hRNhk2a2Jj2tw59GC6cURd2Q6c/CdZhXHgVqzMdAg=="
},
{
"blockIdFlag":"BLOCK_ID_FLAG_COMMIT",
"validatorAddress":"Nv8cuLE25L4mgnBx8shCmG68xfc=",
"timestamp":"2023-09-07T03:59:36.393462082Z",
"signature":"NyTk5W6WLxEbouVJ7LxSwV88FnH/CtmXkr6JczPqEehdrymqrGqT02OJLutGVsBmrPEkMhwa2BegkqvmPLJrBQ=="
},
{
"blockIdFlag":"BLOCK_ID_FLAG_COMMIT",
"validatorAddress":"ObUXYdS8jfTSNPonUBFPJkft7eA=",
"timestamp":"2023-09-07T03:59:36.296674286Z",
"signature":"OAwmf7pEjsXbwIWMD5HbzWiae6OAn0ME49FbXaRLvKIYKWSDKv9f0gprsgRJznOdj60SontlntwmvV+23MV6DQ=="
}
],
"round":0
}
}
}
Parameter | Type | Description |
---|---|---|
block_id | BlockID | Block identifier |
sdk_block | Block | Block details |
BlockID
Parameter | Type | Description |
---|---|---|
hash | Bytes | Block hash |
part_set_header | PartSetHeader |
PartSetHeader
Parameter | Type | Description |
---|---|---|
total | Integer | |
hash | Bytes |
Block
Parameter | Type | Description |
---|---|---|
header | Header | Header information |
data | Data | Block data |
evidence | EvidenceList | |
last_commit | Commit |
Header
Parameter | Type | Description |
---|---|---|
version | Consensus | |
chain_id | String | Chain identifier |
height | Integer | Block height |
time | Time | Block time |
last_block_id | BlockID | Previous block identifier |
last_commit_hash | Bytes | Last commit hash |
data_hash | Bytes | Block data hash |
validators_hash | Bytes | Validators information hash |
next_validators_hash | Bytes | Validators information hash |
consensus_hash | Bytes | Consensus information hash |
app_hash | Bytes | Application hash |
last_result_hash | Bytes | Last result hash |
evidence_hash | Bytes | Evidence data hash |
proposer_address | String | Block proposer's address |
Consensus
Parameter | Type | Description |
---|---|---|
version | Consensus | |
chain_id | String | Chain identifier |
height | Integer | Block height |
time | Time | Block time |
last_block_id | BlockID | Previous block identifier |
last_commit_hash | Bytes | Last commit hash |
data_hash | Bytes | Block data hash |
validators_hash | Bytes | Validators information hash |
next_validators_hash | Bytes | Validators information hash |
consensus_hash | Bytes | Consensus information hash |
app_hash | Bytes | Application hash |
last_result_hash | Bytes | Last result hash |
evidence_hash | Bytes | Evidence data hash |
proposer_address | String | Block proposer's address |
Data
Parameter | Type | Description |
---|---|---|
txs | Byte Array | Txs that will be applied by state @ block.Height+1. NOTE: not all txs here are valid. We're just agreeing on the order first. This means that block.AppHash does not include these txs. |
EvidenceList
Parameter | Type | Description |
---|---|---|
evidence | Evidence Array | Block evidence |
Evidence
Parameter | Type | Description |
---|---|---|
sum | isEvidence_Sum | Valid types for 'sum' are Evidence_DuplicateVoteEvidence and Evidence_LightClientAttackEvidence |
Commit
Parameter | Type | Description |
---|---|---|
height | Integer | Block height |
round | Integer | Consensus round |
block_id | BlockID | Block identifier |
signatures | CommitSig Array | Sigantures |
CommitSig
Parameter | Type | Description |
---|---|---|
block_id_flag | BlockIDFlag | Block height |
validator_address | Bytes | Validator address |
timestamp | Time | Block time |
signature | Bytes | Block signature |
BlockIDFlag
Code | Name |
---|---|
0 | BLOCK_ID_FLAG_UNKNOWN |
1 | BLOCK_ID_FLAG_ABSENT |
2 | BLOCK_ID_FLAG_COMMIT |
3 | BLOCK_ID_FLAG_NIL |
GetLatestValidatorSet
Get the latest validator-set
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
validator_set = await client.fetch_latest_validator_set()
print(validator_set)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchLatestValidatorSet(ctx)
if err != nil {
fmt.Println(err)
}
fmt.Print(res.String())
}
No parameters
Response Parameters
Response Example:
{
"blockHeight":"23201498",
"validators":[
{
"address":"injvalcons1xml3ew93xmjtuf5zwpcl9jzznphte30hvdre9a",
"pubKey":{
"@type":"/cosmos.crypto.ed25519.PubKey",
"key":"Bi/7vbVB1uj/zz40/aozZOvVBFkV6hLqqxBIQr5kSc4="
},
"votingPower":"200001152291153",
"proposerPriority":"234447499678197"
},
{
"address":"injvalcons18x63wcw5hjxlf535lgn4qy20yer7mm0qedu0la",
"pubKey":{
"@type":"/cosmos.crypto.ed25519.PubKey",
"key":"WlL4lTR+iTbd0rn3xP6oH0juOnGRZ+Hh73Oj6/Lt/Wg="
},
"votingPower":"200000153326260",
"proposerPriority":"-270628320740096"
},
{
"address":"injvalcons1xwg7xkmpqp8q804c37sa4dzyfwgnh4a74ll9pz",
"pubKey":{
"@type":"/cosmos.crypto.ed25519.PubKey",
"key":"Puku/I45dAZ4wKeN+rbYKnmuUUA7Yh7/TrKX3ZoTmk4="
},
"votingPower":"199859452893177",
"proposerPriority":"-192489141052575"
},
{
"address":"injvalcons1e0rj6fuy9yn5fwm9x4vw69xyuv7kzjm8rvw5r3",
"pubKey":{
"@type":"/cosmos.crypto.ed25519.PubKey",
"key":"1mF7OEpB9A60O0e+64pICbqS/nN8VnsVfoySMEW2w1Q="
},
"votingPower":"199826816954736",
"proposerPriority":"228669962114476"
}
],
"pagination":{
"total":"4",
"nextKey":""
}
}
Parameter | Type | Description |
---|---|---|
block_height | Integer | Block height |
validators | Validator Array | List of validators |
pagination | PageResponse | Pagination information in the response |
Validator
Parameter | Type | Description |
---|---|---|
address | String | Validator's address |
pub_key | Any | Validator's public key |
voting_power | Integer | Validator's voting power |
proposer_priority | Integer |
PageResponse
Parameter | Type | Description |
---|---|---|
next_key | Byte Array | The key to be passed to PageRequest.key to query the next page most efficiently. It will be empty if there are no more results. |
total | Integer | Total number of results available if PageRequest.count_total was set, its value is undefined otherwise |
GetValidatorSetByHeight
Get the validator-set at a given height
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from google.protobuf import symbol_database
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
pagination = PaginationOption(skip=2, limit=4)
validator_set = await client.fetch_validator_set_by_height(height=23040174, pagination=pagination)
print(validator_set)
if __name__ == "__main__":
symbol_db = symbol_database.Default()
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"fmt"
"github.com/cosmos/cosmos-sdk/types/query"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
height := int64(23040174)
pagination := query.PageRequest{Offset: 2, Limit: 10}
res, err := chainClient.FetchValidatorSetByHeight(ctx, height, &pagination)
if err != nil {
fmt.Println(err)
}
fmt.Print(res.String())
}
Parameter | Type | Description | Required |
---|---|---|---|
height | Integer | Block height | Yes |
pagination | PageRequest | The optional pagination for the request | No |
PageRequest
Parameter | Type | Description | Required |
---|---|---|---|
key | Byte Array | Key is a value returned in PageResponse.next_key to begin querying the next page most efficiently. Only one of offset or key should be set | No |
offset | Integer | Numeric offset that can be used when key is unavailable. It is less efficient than using key. Only one of offset or key should be set | No |
limit | Integer | Total number of results to be returned in the result page | No |
count_total | Boolean | Set to true to indicate that the result set should include a count of the total number of items available for pagination in UIs. It is only respected when offset is used. It is ignored when key is set | No |
reverse | Boolean | Reverse is set to true if results are to be returned in the descending order | No |
Response Parameters
Response Example:
{
"blockHeight":"23040174",
"validators":[
{
"address":"injvalcons1xml3ew93xmjtuf5zwpcl9jzznphte30hvdre9a",
"pubKey":{
"@type":"/cosmos.crypto.ed25519.PubKey",
"key":"Bi/7vbVB1uj/zz40/aozZOvVBFkV6hLqqxBIQr5kSc4="
},
"votingPower":"200001152291142",
"proposerPriority":"-117113073985972"
},
{
"address":"injvalcons18x63wcw5hjxlf535lgn4qy20yer7mm0qedu0la",
"pubKey":{
"@type":"/cosmos.crypto.ed25519.PubKey",
"key":"WlL4lTR+iTbd0rn3xP6oH0juOnGRZ+Hh73Oj6/Lt/Wg="
},
"votingPower":"200000153326249",
"proposerPriority":"-30678774375098"
},
{
"address":"injvalcons1xwg7xkmpqp8q804c37sa4dzyfwgnh4a74ll9pz",
"pubKey":{
"@type":"/cosmos.crypto.ed25519.PubKey",
"key":"Puku/I45dAZ4wKeN+rbYKnmuUUA7Yh7/TrKX3ZoTmk4="
},
"votingPower":"199859452893172",
"proposerPriority":"358858430481236"
},
{
"address":"injvalcons1e0rj6fuy9yn5fwm9x4vw69xyuv7kzjm8rvw5r3",
"pubKey":{
"@type":"/cosmos.crypto.ed25519.PubKey",
"key":"1mF7OEpB9A60O0e+64pICbqS/nN8VnsVfoySMEW2w1Q="
},
"votingPower":"199826816954540",
"proposerPriority":"504834849146021"
}
],
"pagination":{
"total":"7",
"nextKey":""
}
}
Parameter | Type | Description |
---|---|---|
block_height | Integer | Block height |
validators | Validator Array | List of validators |
pagination | PageResponse | Pagination information in the response |
Validator
Parameter | Type | Description |
---|---|---|
address | String | Validator's address |
pub_key | Any | Validator's public key |
voting_power | Integer | Validator's voting power |
proposer_priority | Integer |
PageResponse
Parameter | Type | Description |
---|---|---|
next_key | Byte Array | The key to be passed to PageRequest.key to query the next page most efficiently. It will be empty if there are no more results. |
total | Integer | Total number of results available if PageRequest.count_total was set, its value is undefined otherwise |
ABCIQuery
Defines a query handler that supports ABCI queries directly to the application, bypassing Tendermint completely. The ABCI query must contain a valid and supported path, including app, custom, p2p, and store.
IP rate limit group: chain
Request Parameters
Request Example:
Parameter | Type | Description | Required |
---|---|---|---|
data | Bytes | Query data | No |
path | String | Query path | Yes |
haight | Integer | Block height | No |
prove | Boolean | No |
Response Parameters
Response Example:
Parameter | Type | Description |
---|---|---|
code | Integer | Query result code (zero: success, non-zero: error |
log | String | |
info | String | |
index | Integer | |
key | Bytes | |
value | Bytes | |
proof_ops | ProofOps | |
height | Integer | Block height |
codespace | String |
ProofOps
Parameter | Type | Description |
---|---|---|
ops | ProofOp Array |
ProofOp
Parameter | Type | Description |
---|---|---|
type | String | |
key | Bytes | |
data | Bytes |
- Tokenfactory
Tokenfactory module
DenomAuthorityMetadata
Gets the authority metadata for tokens by their creator address
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
metadata = await client.fetch_denom_authority_metadata(
creator="inj1uv6psuupldve0c9n3uezqlecadszqexv5vxx04",
sub_denom="position",
)
print(metadata)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
creator := "inj1uv6psuupldve0c9n3uezqlecadszqexv5vxx04"
subDenom := "position"
ctx := context.Background()
res, err := chainClient.FetchDenomAuthorityMetadata(ctx, creator, subDenom)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
creator | String | The denom creator address | Yes |
sub_denom | String | The token subdenom | No |
Response Parameters
Response Example:
{'authorityMetadata': {'admin': 'inj1uv6psuupldve0c9n3uezqlecadszqexv5vxx04'}}
{
"authority_metadata": {
"admin": "inj1uv6psuupldve0c9n3uezqlecadszqexv5vxx04"
}
}
Parameter | Type | Description |
---|---|---|
authority_metadata | DenomAuthorityMetadata | The denom authority information |
DenomAuthorityMetadata
Parameter | Type | Description |
---|---|---|
admin | String | The denom admin |
DenomsFromCreator
Gets all the tokens created by a specific admin/creator
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
denoms = await client.fetch_denoms_from_creator(creator="inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3")
print(denoms)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
creator := "inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3"
ctx := context.Background()
res, err := chainClient.FetchDenomsFromCreator(ctx, creator)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
creator | String | The denom creator address | Yes |
Response Parameters
Response Example:
{
"denoms":[
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/Stake-0",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/Talis",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/Talis-2",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/Talis-3",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/Talis-4",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/Vote-0",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/banana",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/bananas",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/stake-token",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/stake-token10",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/stake-token2",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/stake-token3",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/stake-token4",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/stake-token5",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/stake-token6",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/stake-token7",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/stake-token8",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/stake-token9",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/talis-5",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/talis-6",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/talis-7",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/talis-8",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/vote-token",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/vote-token10",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/vote-token2",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/vote-token3",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/vote-token4",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/vote-token5",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/vote-token6",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/vote-token7",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/vote-token8",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/vote-token9",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/xTalis-4",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/xbanana",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/xtalis-5",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/xtalis-6",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/xtalis-7",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/xtalis-8"
]
}
{
"denoms": [
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/Stake-0",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/Talis",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/Talis-2",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/Talis-3",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/Talis-4",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/Vote-0",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/banana",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/bananas",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/stake-token",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/stake-token10",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/stake-token2",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/stake-token3",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/stake-token4",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/stake-token5",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/stake-token6",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/stake-token7",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/stake-token8",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/stake-token9",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/talis-5",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/talis-6",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/talis-7",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/talis-8",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/vote-token",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/vote-token10",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/vote-token2",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/vote-token3",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/vote-token4",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/vote-token5",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/vote-token6",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/vote-token7",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/vote-token8",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/vote-token9",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/xTalis-4",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/xbanana",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/xtalis-5",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/xtalis-6",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/xtalis-7",
"factory/inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3/xtalis-8"
]
}
Parameter | Type | Description |
---|---|---|
denoms | String Array | List of denoms |
TokenfactoryModuleState
Retrieves the entire auctions module's state
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
state = await client.fetch_tokenfactory_module_state()
print(state)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
ctx := context.Background()
res, err := chainClient.FetchTokenfactoryModuleState(ctx)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
No parameters
Response Parameters
Response Example:
{
"state":{
"params":{
"denomCreationFee":[
{
"denom":"inj",
"amount":"1000000000000000000"
}
]
},
"factoryDenoms":[
{
"denom":"factory/inj10gcvfpnn4932kzk56h5kp77mrfdqas8z63qr7n/BITS",
"authorityMetadata":{
"admin":"inj10gcvfpnn4932kzk56h5kp77mrfdqas8z63qr7n"
},
"name":"BITS",
"symbol":"BITS"
},
{
"denom":"factory/inj10hmmvlqq6rrlf2c2v982d6xqsns4m3sy086r27/position",
"authorityMetadata":{
"admin":"inj10hmmvlqq6rrlf2c2v982d6xqsns4m3sy086r27"
},
"name":"",
"symbol":""
},
{
"denom":"factory/inj10jmp6sgh4cc6zt3e8gw05wavvejgr5pw6m8j75/ak",
"authorityMetadata":{
"admin":"inj10jmp6sgh4cc6zt3e8gw05wavvejgr5pw6m8j75"
},
"name":"AKCoin",
"symbol":"AK"
}
]
}
}
{
"state":{
"params":{
"denomCreationFee":[
{
"denom":"inj",
"amount":"1000000000000000000"
}
]
},
"factoryDenoms":[
{
"denom":"factory/inj10gcvfpnn4932kzk56h5kp77mrfdqas8z63qr7n/BITS",
"authorityMetadata":{
"admin":"inj10gcvfpnn4932kzk56h5kp77mrfdqas8z63qr7n"
},
"name":"BITS",
"symbol":"BITS"
},
{
"denom":"factory/inj10hmmvlqq6rrlf2c2v982d6xqsns4m3sy086r27/position",
"authorityMetadata":{
"admin":"inj10hmmvlqq6rrlf2c2v982d6xqsns4m3sy086r27"
},
"name":"",
"symbol":""
},
{
"denom":"factory/inj10jmp6sgh4cc6zt3e8gw05wavvejgr5pw6m8j75/ak",
"authorityMetadata":{
"admin":"inj10jmp6sgh4cc6zt3e8gw05wavvejgr5pw6m8j75"
},
"name":"AKCoin",
"symbol":"AK"
}
]
}
}
Parameter | Type | Description |
---|---|---|
state | GenesisState | The state details |
GenesisState
Parameter | Type | Description |
---|---|---|
params | Params | Module parameters |
factory_denoms | GenesisDenom Array | Module parameters |
Params
Parameter | Type | Description |
---|---|---|
denoms_creation_fee | Coin Array | Fee required to create a denom |
Coin
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | The token denom | Yes |
amount | String | The amount of tokens | Yes |
GenesisDenom
Parameter | Type | Description |
---|---|---|
denom | String | Token denom |
authority_metadata | DenomAuthorityMetadata | Token authority metadata |
name | String | Token name |
symbol | String | Token symbol |
DenomAuthorityMetadata
Parameter | Type | Description |
---|---|---|
admin | String | The denom admin |
CreateDenom
Create a new denom
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
private_key_in_hexa = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
composer = ProtoMsgComposer(network=network.string())
message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
network=network,
private_key=private_key_in_hexa,
)
priv_key = PrivateKey.from_hex(private_key_in_hexa)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
message = composer.msg_create_denom(
sender=address.to_acc_bech32(),
subdenom="inj_test",
name="Injective Test Token",
symbol="INJTEST",
decimals=18,
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"encoding/json"
"fmt"
"os"
tokenfactorytypes "github.com/InjectiveLabs/sdk-go/chain/tokenfactory/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
fmt.Println(err)
return
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
message := new(tokenfactorytypes.MsgCreateDenom)
message.Sender = senderAddress.String()
message.Subdenom = "inj_test"
message.Name = "Injective Test Token"
message.Symbol = "INJTEST"
message.Decimals = 18
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.AsyncBroadcastMsg(message)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | Sender Injective address | Yes |
subdenom | String | New token subdenom | Yes |
name | String | New token name | Yes |
symbol | String | New token symbol | Yes |
decimals | Integer | Number of decimals use to represent token amount on chain | Yes |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgMint
Allows a token admin's account to mint more units
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
private_key_in_hexa = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
composer = ProtoMsgComposer(network=network.string())
message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
network=network,
private_key=private_key_in_hexa,
)
priv_key = PrivateKey.from_hex(private_key_in_hexa)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
amount = composer.coin(amount=1_000_000_000, denom="factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test")
message = composer.msg_mint(
sender=address.to_acc_bech32(),
amount=amount,
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"encoding/json"
"fmt"
"os"
"cosmossdk.io/math"
tokenfactorytypes "github.com/InjectiveLabs/sdk-go/chain/tokenfactory/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
sdktypes "github.com/cosmos/cosmos-sdk/types"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
fmt.Println(err)
return
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
message := new(tokenfactorytypes.MsgMint)
message.Sender = senderAddress.String()
message.Amount = sdktypes.Coin{
Denom: "factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test",
Amount: math.NewInt(1000000000),
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.AsyncBroadcastMsg(message)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | Sender Injective address | Yes |
amount | Coin | Amount to mint | Yes |
Coin
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | The token denom | Yes |
amount | String | The amount of tokens | Yes |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgBurn
Allows a token admin's account to burn circulating units
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
private_key_in_hexa = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
composer = ProtoMsgComposer(network=network.string())
message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
network=network,
private_key=private_key_in_hexa,
)
priv_key = PrivateKey.from_hex(private_key_in_hexa)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
amount = composer.coin(amount=100, denom="factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test")
message = composer.msg_burn(
sender=address.to_acc_bech32(),
amount=amount,
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"encoding/json"
"fmt"
"os"
"cosmossdk.io/math"
tokenfactorytypes "github.com/InjectiveLabs/sdk-go/chain/tokenfactory/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
sdktypes "github.com/cosmos/cosmos-sdk/types"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
fmt.Println(err)
return
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
message := new(tokenfactorytypes.MsgBurn)
message.Sender = senderAddress.String()
message.Amount = sdktypes.Coin{
Denom: "factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test",
Amount: math.NewInt(100),
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.AsyncBroadcastMsg(message)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | Sender Injective address | Yes |
amount | Coin | Amount to burn | Yes |
Coin
Parameter | Type | Description | Required |
---|---|---|---|
denom | String | The token denom | Yes |
amount | String | The amount of tokens | Yes |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgSetDenomMetadata
Allows a token admin's account to set the token metadata
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
private_key_in_hexa = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
composer = ProtoMsgComposer(network=network.string())
message_broadcaster = MsgBroadcasterWithPk.new_without_simulation(
network=network,
private_key=private_key_in_hexa,
)
priv_key = PrivateKey.from_hex(private_key_in_hexa)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
sender = address.to_acc_bech32()
description = "Injective Test Token"
subdenom = "inj_test"
denom = "factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test"
token_decimals = 6
name = "Injective Test"
symbol = "INJTEST"
uri = "http://injective-test.com/icon.jpg"
uri_hash = ""
message = composer.msg_set_denom_metadata(
sender=sender,
description=description,
denom=denom,
subdenom=subdenom,
token_decimals=token_decimals,
name=name,
symbol=symbol,
uri=uri,
uri_hash=uri_hash,
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"encoding/json"
"fmt"
"os"
tokenfactorytypes "github.com/InjectiveLabs/sdk-go/chain/tokenfactory/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
fmt.Println(err)
return
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
denom := "factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test"
subdenom := "inj_test"
tokenDecimals := uint32(6)
microDenomUnit := banktypes.DenomUnit{
Denom: denom,
Exponent: 0,
Aliases: []string{fmt.Sprintf("micro%s", subdenom)},
}
denomUnit := banktypes.DenomUnit{
Denom: subdenom,
Exponent: tokenDecimals,
Aliases: []string{subdenom},
}
metadata := banktypes.Metadata{
Description: "Injective Test Token",
DenomUnits: []*banktypes.DenomUnit{µDenomUnit, &denomUnit},
Base: denom,
Display: subdenom,
Name: "Injective Test",
Symbol: "INJTEST",
URI: "http://injective-test.com/icon.jpg",
URIHash: "",
Decimals: tokenDecimals,
}
message := new(tokenfactorytypes.MsgSetDenomMetadata)
message.Sender = senderAddress.String()
message.Metadata = metadata
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.AsyncBroadcastMsg(message)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | Sender Injective address | Yes |
metadata | Metadata | Token metadata | Yes |
Metadata
Parameter | Type | Description |
---|---|---|
description | String | Token description |
denom_units | DenomUnit Array | All token units |
base | String | The base token denom |
display | String | Suggested denom that should be displayed in clients |
name | String | Token name |
symbol | String | Token symbol |
uri | String | URI to a document (on or off-chain) that contains additional information. Optional |
uri_hash | String | URIHash is a sha256 hash of a document pointed by URI. It's used to verify that the document didn't change. Optional |
decimals | Integer | Number of decimals use to represent token amount on chain |
DenomUnit
Parameter | Type | Description |
---|---|---|
denom | String | Name of the denom unit |
exponent | Integer | Exponent represents power of 10 exponent that one must raise the base_denom to in order to equal the given DenomUnit's denom 1 denom = 10^exponent base_denom (e.g. with a base_denom of uatom, one can create a DenomUnit of 'atom' with exponent = 6, thus: 1 atom = 10^6 uatom) |
aliases | String Array | List of aliases for the denom |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgChangeAdmin
Allows a token admin's account to transfer administrative privileged to other account
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from pyinjective.composer import Composer as ProtoMsgComposer
from pyinjective.core.broadcaster import MsgBroadcasterWithPk
from pyinjective.core.network import Network
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
private_key_in_hexa = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
composer = ProtoMsgComposer(network=network.string())
message_broadcaster = MsgBroadcasterWithPk.new_without_simulation(
network=network,
private_key=private_key_in_hexa,
)
priv_key = PrivateKey.from_hex(private_key_in_hexa)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
message = composer.msg_change_admin(
sender=address.to_acc_bech32(),
denom="factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test",
new_admin="inj1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqe2hm49", # This is the zero address to remove admin permissions
)
# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(result)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"encoding/json"
"fmt"
"os"
tokenfactorytypes "github.com/InjectiveLabs/sdk-go/chain/tokenfactory/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
fmt.Println(err)
return
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
message := new(tokenfactorytypes.MsgChangeAdmin)
message.Sender = senderAddress.String()
message.Denom = "factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test"
// This is the zero address to remove admin permissions
message.NewAdmin = "inj1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqe2hm49"
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.AsyncBroadcastMsg(message)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | Sender Injective address | Yes |
denom | String | Token denom | Yes |
new_admin | String | New admin Injective address | Yes |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
- Wasm
CosmWasm smart contract interactions.
ContractInfo
Queries validator commission and self-delegation rewards for validator
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
address = "inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7"
contract_info = await client.fetch_contract_info(address=address)
print(contract_info)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
address := "inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7"
ctx := context.Background()
res, err := chainClient.FetchContractInfo(ctx, address)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
address | String | Contract address | Yes |
Response Parameters
Response Example:
{
"address":"inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7",
"contractInfo":{
"codeId":"290",
"creator":"inj1h3gepa4tszh66ee67he53jzmprsqc2l9npq3ty",
"label":"CounterTestInstance",
"created":{
"blockHeight":"6232017",
"txIndex":"145751"
},
"admin":"",
"ibcPortId":""
}
}
{
"address": "inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7",
"code_id": 290,
"creator": "inj1h3gepa4tszh66ee67he53jzmprsqc2l9npq3ty",
"label": "CounterTestInstance",
"created": {
"block_height": 6232017,
"tx_index": 145751
}
}
Parameter | Type | Description |
---|---|---|
address | String | Contract address |
contract_info | ContractInfo | Contract metadata |
ContractInfo
Parameter | Type | Description |
---|---|---|
code_id | Int | ID of the stored wasm code |
creator | String | Address that instantiated the contract |
admin | String | Address that can execute migrations |
label | String | Contract label |
created | AbsoluteTxPosition | Tx position when the contract was instantiated |
ibc_port_id | String |
AbsoluteTxPosition | Parameter | Type | Description | | ------------ | ---- | ------------------------------------------------ | | block_height | Int | Block number when the contract was created | | tx_index | Int | Transaction index where the contract was created |
ContractHistory
Gets the contract code history
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
address = "inj18pp4vjwucpgg4nw3rr4wh4zyjg9ct5t8v9wqgj"
limit = 2
pagination = PaginationOption(limit=limit)
contract_history = await client.fetch_contract_history(address=address, pagination=pagination)
print(contract_history)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/cosmos/cosmos-sdk/types/query"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
address := "inj18pp4vjwucpgg4nw3rr4wh4zyjg9ct5t8v9wqgj"
pagination := query.PageRequest{Limit: 2}
ctx := context.Background()
res, err := chainClient.FetchContractHistory(ctx, address, &pagination)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
address | String | Contract address | Yes |
pagination | Paging | Pagination of results | No |
Response Parameters
Response Example:
{
"entries":[
{
"operation":"CONTRACT_CODE_HISTORY_OPERATION_TYPE_INIT",
"codeId":"3770",
"updated":{
"blockHeight":"20210946",
"txIndex":"2196537"
},
"msg":"eyJhZG1pbiI6ImluajFtYWV5dnhmYW10bjhsZnl4cGpjYThrdXZhdXVmMnFldTZndHhtMyIsImNvZGVJZCI6IjM3NzAiLCJsYWJlbCI6IlRhbGlzIGNhbmR5IG1hY2hpbmUiLCJtc2ciOiIiLCJzZW5kZXIiOiJpbmoxandsbmN1dTY3NnQzcWZqZGxjd3NkZ3gwZ2c2anBhOHNuZXM0eHQiLCJmdW5kc0xpc3QiOltdLCJjb250cmFjdF9hZGRyZXNzIjoiaW5qMWd2emdneGc1NGRmd2FlcnpsZWdqdnFlZzN1ZTk3ZHEydmV0OTJ6Iiwib3duZXIiOiJpbmoxandsbmN1dTY3NnQzcWZqZGxjd3NkZ3gwZ2c2anBhOHNuZXM0eHQiLCJmZWVfY29sbGVjdG9yIjoiaW5qMW1hZXl2eGZhbXRuOGxmeXhwamNhOGt1dmF1dWYycWV1Nmd0eG0zIiwib3BlcmF0b3JfcHVia2V5IjoiQSsxQkVrWXVTQjJQa1IwWDVJMnZzQnNuTldHMVlPRDJUUTJJUHZnelJVVXYiLCJwcml2YXRlX3BoYXNlcyI6W3siaWQiOjAsInByaXZhdGUiOnRydWUsInN0YXJ0IjoxNzA0MTM4NTQwLCJlbmQiOjE3MDQxNDIxNDAsInByaWNlIjp7Im5hdGl2ZSI6W3siZGVub20iOiJpbmoiLCJhbW91bnQiOiIwIn1dfSwid2xfbWVya2xlX3Jvb3QiOiI1NGE5Yzg0MmE5MmY4ZGQ3Zjg3ZTZhZDM0MGEwMWI5ZmVhZWE0MjQyOThjYTA1NmY3NGNmZTAyNzFkZDExYjIwIn0seyJpZCI6MSwicHJpdmF0ZSI6dHJ1ZSwic3RhcnQiOjE3MDQxNDIxNDIsImVuZCI6MTcwNDE0NTc0MCwicHJpY2UiOnsibmF0aXZlIjpbeyJkZW5vbSI6ImluaiIsImFtb3VudCI6IjEwMDAwMDAwMDAwMDAwMDAwMCJ9XX0sIndsX21lcmtsZV9yb290IjoiZjU4YTIwZmUyMWUyYzRkNzE0OTRhMGMyOWQyZWRmZDRjZGJiNzgwOTlmZDQ1NWFkZjg0MjdjMjdiMjFiOGQ3YiJ9XSwicHVibGljX3BoYXNlIjp7ImlkIjoyLCJwcml2YXRlIjpmYWxzZSwic3RhcnQiOjE3MDQxNDU3NDIsImVuZCI6MTcwNDE0OTM0MCwicHJpY2UiOnsibmF0aXZlIjpbeyJkZW5vbSI6ImluaiIsImFtb3VudCI6IjQ1MDAwMDAwMDAwMDAwMDAwMCJ9XX0sIm1pbnRfbGltaXQiOjEwfSwicmVzZXJ2ZWRfdG9rZW5zIjo3NywidG90YWxfdG9rZW5zIjo3Nzd9"
}
],
"pagination":{
"nextKey":"",
"total":"0"
}
}
{
"entries": [
{
"operation": 1,
"code_id": 3770,
"updated": {
"block_height": 20210946,
"tx_index": 2196537
},
"msg": {
"admin": "inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3",
"codeId": "3770",
"label": "Talis candy machine",
"msg": "",
"sender": "inj1jwlncuu676t3qfjdlcwsdgx0gg6jpa8snes4xt",
"fundsList": [],
"contract_address": "inj1gvzggxg54dfwaerzlegjvqeg3ue97dq2vet92z",
"owner": "inj1jwlncuu676t3qfjdlcwsdgx0gg6jpa8snes4xt",
"fee_collector": "inj1maeyvxfamtn8lfyxpjca8kuvauuf2qeu6gtxm3",
"operator_pubkey": "A+1BEkYuSB2PkR0X5I2vsBsnNWG1YOD2TQ2IPvgzRUUv",
"private_phases": [
{
"id": 0,
"private": true,
"start": 1704138540,
"end": 1704142140,
"price": {
"native": [
{
"denom": "inj",
"amount": "0"
}
]
},
"wl_merkle_root": "54a9c842a92f8dd7f87e6ad340a01b9feaea424298ca056f74cfe0271dd11b20"
},
{
"id": 1,
"private": true,
"start": 1704142142,
"end": 1704145740,
"price": {
"native": [
{
"denom": "inj",
"amount": "100000000000000000"
}
]
},
"wl_merkle_root": "f58a20fe21e2c4d71494a0c29d2edfd4cdbb78099fd455adf8427c27b21b8d7b"
}
],
"public_phase": {
"id": 2,
"private": false,
"start": 1704145742,
"end": 1704149340,
"price": {
"native": [
{
"denom": "inj",
"amount": "450000000000000000"
}
]
},
"mint_limit": 10
},
"reserved_tokens": 77,
"total_tokens": 777
}
}
],
"pagination": {}
}
Parameter | Type | Description |
---|---|---|
entries | ContractCodeHistoryEntry Array | Contract code history |
pagination | PageResponse | Pagination of results |
ContractCodeHistoryEntry
Parameter | Type | Description |
---|---|---|
operation | ContractCodeHistoryOperationType | Contract creation operation type |
code_id | Int | ID of the store wasm code |
updated | AbsoluteTxPosition | Contract update info |
msg | RawContractMessage | Contract update message |
AbsoluteTxPosition | Parameter | Type | Description | | ------------ | ---- | ------------------------------------------------ | | block_height | Int | Block number when the contract was created | | tx_index | Int | Transaction index where the contract was created |
ContractCodeHistoryOperationType | ID | Type | | --- | ------------------------------------------- | | 0 | ContractCodeHistoryOperationTypeUnspecified | | 1 | ContractCodeHistoryOperationTypeInit | | 2 | ContractCodeHistoryOperationTypeMigrate | | 3 | ContractCodeHistoryOperationTypeGenesis |
ContractsByCode
Get all smart contracts for a code id
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
code_id = 3770
limit = 2
pagination = PaginationOption(limit=limit)
contracts = await client.fetch_contracts_by_code(code_id=code_id, pagination=pagination)
print(contracts)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/cosmos/cosmos-sdk/types/query"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
codeId := uint64(3770)
pagination := query.PageRequest{Limit: 2}
ctx := context.Background()
res, err := chainClient.FetchContractsByCode(ctx, codeId, &pagination)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
code_id | Int | ID of the stored wasm code | Yes |
pagination | Paging | Pagination of results | No |
Response Parameters
Response Example:
{
"contracts":[
"inj1z4l7jc8dj3y9484aqcrmf6y8mcctvkmm9zkf7n",
"inj18jead47nj8j20kxq5j2rm6l9fmf45f8ey9muuh"
],
"pagination":{
"nextKey":"AAAAAAEWkNYAAAAAAAAAAEnOwG7FHHD7R+iyNAZCsoHr5hA1",
"total":"0"
}
}
{
"contracts": [
"inj1z4l7jc8dj3y9484aqcrmf6y8mcctvkmm9zkf7n",
"inj18jead47nj8j20kxq5j2rm6l9fmf45f8ey9muuh"
],
"pagination": {
"next_key": "AAAAAAEWkNYAAAAAAAAAAEnOwG7FHHD7R+iyNAZCsoHr5hA1"
}
}
Parameter | Type | Description |
---|---|---|
contracts | String Array | Array of contracts addresses |
pagination | PageResponse | Pagination of results |
AllContractState
Gets all raw store data for a single contract
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
address = "inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7"
limit = 2
pagination = PaginationOption(limit=limit)
contract_history = await client.fetch_all_contracts_state(address=address, pagination=pagination)
print(contract_history)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/cosmos/cosmos-sdk/types/query"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
address := "inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7"
pagination := query.PageRequest{Limit: 2}
ctx := context.Background()
res, err := chainClient.FetchAllContractsState(ctx, address, &pagination)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
address | String | Contract address | Yes |
pagination | Paging | Pagination of results | No |
Response Parameters
Response Example:
{
"models":[
{
"key":"Y29udHJhY3RfaW5mbw==",
"value":"eyJjb250cmFjdCI6ImNyYXRlcy5pbzpjdy1jb3VudGVyIiwidmVyc2lvbiI6IjAuMS4wIn0="
},
{
"key":"c3RhdGU=",
"value":"eyJjb3VudCI6MTA0MSwib3duZXIiOiJpbmoxaDNnZXBhNHRzemg2NmVlNjdoZTUzanptcHJzcWMybDlucHEzdHkifQ=="
}
],
"pagination":{
"nextKey":"",
"total":"0"
}
}
{
"models": [
{
"key": "636F6E74726163745F696E666F",
"value": "eyJjb250cmFjdCI6ImNyYXRlcy5pbzpjdy1jb3VudGVyIiwidmVyc2lvbiI6IjAuMS4wIn0="
},
{
"key": "7374617465",
"value": "eyJjb3VudCI6MTA0MSwib3duZXIiOiJpbmoxaDNnZXBhNHRzemg2NmVlNjdoZTUzanptcHJzcWMybDlucHEzdHkifQ=="
}
],
"pagination": {}
}
Parameter | Type | Description |
---|---|---|
models | Model Array | Array of contracts' models |
pagination | PageResponse | Pagination of results |
Model | Parameter | Type | Description | | --------- | ---------- | ------------------------------------------ | | key | String | Hexadecimal representation of the byte key | | Value | Byte Array | Raw value in base64 encoding |
RawContractState
Gets single key from the raw store data of a contract
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
address = "inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7"
query_data = '{"get_count": {}}'
contract_state = await client.fetch_raw_contract_state(address=address, query_data=query_data)
print(contract_state)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
address := "inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7"
queryData := []byte("{\"get_count\": {}}")
ctx := context.Background()
res, err := chainClient.RawContractState(ctx, address, queryData)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
address | String | Contract address | Yes |
query_data | Byte Array | Key of the data to retrieve | Yes |
Response Parameters
Response Example:
Parameter | Type | Description |
---|---|---|
Data | Byte Array | Raw data in base64 encoding |
SmartContractState
Get smart query result from the contract
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
address = "inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7"
query_data = '{"get_count": {}}'
contract_state = await client.fetch_smart_contract_state(address=address, query_data=query_data)
print(contract_state)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
address := "inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7"
queryData := []byte("{\"get_count\": {}}")
ctx := context.Background()
res, err := chainClient.SmartContractState(ctx, address, queryData)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
address | String | Contract address | Yes |
query_data | Byte Array | Query to execute in the contract | Yes |
Response Parameters
Response Example:
{'data': 'eyJjb3VudCI6MTA0MX0='}
{
"data": {
"count": 1041
}
}
Parameter | Type | Description |
---|---|---|
Data | Byte Array | Raw data in base64 encoding |
Code
Gets the binary code and metadata for a contract
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import base64
from pyinjective.async_client import AsyncClient
from pyinjective.core.network import Network
async def main() -> None:
network = Network.testnet()
client = AsyncClient(network)
response = await client.fetch_code(code_id=290)
print(response)
code = base64.b64decode(response["data"]).decode(encoding="utf-8", errors="replace")
print(f"\n\n\n{code}")
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
codeId := uint64(290)
ctx := context.Background()
res, err := chainClient.FetchCode(ctx, codeId)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
code_id | Int | ID of the contract code | Yes |
Response Parameters
Response Example:
{
"codeInfo":{
"codeId":"290",
"creator":"inj1h3gepa4tszh66ee67he53jzmprsqc2l9npq3ty",
"dataHash":"+OdoniOsDJ1T9EqP2YxobCCwFAqNdtYA4sVGv7undY0=",
"instantiatePermission":{
"permission":"ACCESS_TYPE_EVERYBODY",
"addresses":[
]
}
},
"data":"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Qf8BcQshBgJAAkACQCAEIAZyIgZB/wFxIgVBAkcEQCAGQQFxDQEgC0UNAiADQfACakG5gcAAQQcQGCARRQ0KDAkLIAsNCiADQdACakG5gcAAQQcQFiADKALQAkEVRgRAIAMoAtwCIRQgAygC2AIhESADKALUAiELDAsLIANB+AJqIANB2AJqKQMANwMAIAMgAykD0AI3A/ACDAkLIANB0AJqIA4QjgECQCADKALQAiIPQRVHBEAgFyAYKQIANwIAIBdBCGogGEEIaigCADYCACADIA82AoADDAELIANBgANqIA4QFyADKAKAA0EVRg0CCyADQfgCaiADQYgDaikDADcDACADIAMpA4ADNwPwAgwGCyADQdACaiAOEI4BIAMoAtACIgRBFUcNAiADQdACaiAOEBogAygC3AIhFCADKALYAiERIAMoAtQCIQsgAygC0AIiBEEVRw0JCyADQbABaiAOEJABIAMtALEBIQQgAy0AsAFBAXENAAsMAgsgAygC3AIhFCADKALYAiERIAMoAtQCIQsMBgsgC0H/AXEhC0EEIQQMBQsgAyAJNgL8AiADIAQ2AvgCIAMgBTYC9AIgAyABNgLwAgsgC0UgEUVyDQELIAsQqwELIAMoAvwCIRQgAygC+AIhESADKAL0AiELIAMoAvACIgRBFUcNAQsgA0HQAmogCBCNASADKALQAiIEQRVGDQIgAygC3AIhFCADKALYAiADKALUAiEBIBEEQCALEKsBCyERIAEhCwsgAyAUNgKkAiADIBE2AqACIAMgCzYCnAIgAyAENgKYAgwJCyAhQiiIpyEKICFCIIinIRUgIachGyAJIRYLIANBCGogCBCQASADLQAJIQEgAy0ACEEBcQ0AC0ECIQQMAwtBACENDAMLIANBoAJqIANB2AJqKQMANwMAIAMgAykD0AI3A5gCIBZFDQUgDRCrAQwFCyADIBQ2AsgCIAMpA8gCISAgA0GYAmogA0GIAmoQjQEgAygCmAIiAUEVRwRAIAMtAJ8CQRB0IQkgAy8AnQIgAykDoAIhICADLQCcAiEMIBYEQCANEKsBCyAJciECIBFFDQYgCxCrAQwGCyADQZgCaiADQYgCahCLASADKAKYAiIBQRVHBEAgAy0AnwJBEHQhCSADLwCdAiADKQOgAiEgIAMtAJwCIQwgFgRAIA0QqwELIAlyIQIg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aigCACIENgIAIAMgCykCACIMNwMwIAlBCGogBDYCACAJIAw3AgAMAQsgA0EgaiAHEBcgAygCICIFQRVGDQELIAMoAiwhCSADKAIoIQggAy0AJCEEIAMvACUgAy0AJ0EQdHIMBgsgAyAHEJABIAMtAAEhBSADLQAAQQFxDQALCyAEQf8BcSEEQQIhBQwCCyAKQRU2AgAMAwsgAygCTCEJIAYhBAsgBEEIdgsiBjsABSAKIAk2AAwgCiAINgAIIAogBDoABCAKIAU2AgAgCkEHaiAGQRB2OgAACyADQdAAaiQAIAIoAlAiBEEVRw0KIAJB0ABqIAEQjQEgAigCUCIBQRVGBEAgAEEVNgIADAwLIAJByABqIAJB3ABqKAIAIgQ2AgAgAiACKQJUIgw3A0AgAEEMaiAENgIAIAAgDDcCBCAAIAE2AgAMCwsgAEELNgIADAoLIABBFTYCAAwJCyAAQQA7AAUgAEEENgIAIABBB2pBADoAAAwICyAAQQ42AgAMBwsgAikCVCEMIAAgAigCXDYCDCAAIAw3AgQgACABNgIADAYLIABBADsABSAAQQQ2AgAgAEEHakEAOgAADAULIABBDjYCAAwECyACQcgAaiACQdwAaigCACIBNgIAIAIgAikCVCIMNwNAIABBDGogATYCACAAIAw3AgQgACAENgIADAMLIABBADsABSAAQQQ2AgAgAEEHakEAOgAADAILIABBDjYCAAwBCyACQcgAaiACQdwAaigCACIBNgIAIAIgAikCVCIMNwNAIABBDGogATYCACAAIAw3AgQgACAENgIACyACQeAAaiQAC8UBAQF/IwBB8ABrIgMkACADIAI2AgwgAyABNgIIIANBJGpBATYCACADQgI3AhQgA0GUi8AANgIQIANBATYCLCADIANBKGo2AiAgAyADQQhqNgIoIANBADYCOCADQgE3AzAgA0FAayIBIANBMGpBqIXAABDyASADQRBqIAEQ6AEEQEHAhcAAQTcgA0HoAGpB+IXAAEHUhsAAEOkBAAsgACADKQMwNwIEIABBFDYCACAAQQxqIANBOGooAgA2AgAgA0HwAGokAAuFBAIFfwJ+IwBB4ABrIgMkACADIAI2AgwgAyABNgIIIwBBEGsiBiQAIANBEGoiBAJ/AkACQCACRQRAIARBADoAAQwBCwJAAkACQCABLQAAQStrDgMBAgACCyACQQFGDQMMAQsgAkEBayICRQ0CIAFBAWohAQsCQAJAAkAgAkERTwRAA0AgBiAIQgBCChCMAiABLQAAQTBrIgVBCUsNBiAGKQMIQgBSDQQgBikDACIJIAUgByAFQQpJG618IgggCVQNAyABQQFqIQEgBSEHIAJBAWsiAg0ACwwBCwNAIAEtAABBMGsiBUEJSw0FIAFBAWohASAFrSAIQgp+fCEIIAJBAWsiAg0ACwsgBCAINwMIQQAMBAsgBEECOgABDAELIARBAjoAAQtBAQwBCyAEQQE6AAFBAQs6AAAgBkEQaiQAAkAgAy0AEEUEQCAAIAMpAxg3AwggAEEVNgIADAELIAMgAy0AEToAJyADQcQAakECNgIAIANBATYCPCADIANBJ2o2AkAgAyADQQhqNgI4IANBAjYCXCADQgI3AkwgA0Hci8AANgJIIAMgA0E4ajYCWCADQShqIgEgA0HIAGoiAhDQASACQQRyIAEQ0QEgA0EUNgJIIAMoAiwEQCADKAIoEKsBCyAAIAMpA0g3AgAgAEEIaiADQdAAaikDADcCAAsgA0HgAGokAAvFAgIEfwF+IwBBIGsiAiQAIAJBCGogARCQAQJAAkACQAJAAkAgAi0ACEEBcQRAIAItAAlBIkcNASABEIoBIAJBEGogARCPASACKAIQIgFBFUcNAiACQRxqKAIAIQEgAkEYaigCACEDIAIoAhQiBEUEQAJAIAFFBEBBASEEDAELIAFBf0oiBUUNBSABIAUQPSIERQ0GCyAEIAMgARCLAiEDIABBDGogATYCACAAQQhqIAE2AgAgACADNgIEIABBFTYCAAwGCyAAIAQ2AgQgAEEVNgIAIABBDGogATYCACAAQQhqIAM2AgAMBQsgAEEAOwAFIABBBDYCACAAQQdqQQA6AAAMBAsgAEEONgIADAMLIAIpAhQhBiAAIAIoAhw2AgwgACAGNwIEIAAgATYCAAwCCxDPAQALIAEgBRDOAQALIAJBIGokAAv3AQEDfyMAQUBqIgQkAAJAAkACQAJAIAJFBEBBASEFDAELIAJBf0oiBkUNASACIAYQPSIFRQ0CCyAFIAEgAhCLAiEBIARBADYCCCAEQgE3AwAgBEEQaiIFIARBqIXAABDyASADIAUQhwENAiAAQQxqIAI2AgAgAEEIaiACNgIAIAAgATYCBCAAIAQpAwA3AhAgAEEINgIAIABBGGogBEEIaigCADYCAAJAIAMoAgBBFEkNACADQQhqKAIARQ0AIAMoAgQQqwELIARBQGskAA8LEM8BAAsgAiAGEM4BAAtBwIXAAEE3IARBOGpB+IXAAEHUhsAAEOkBAAvwIwIbfwN+IwBBkAJrIgMkACADQZABaiIHIAEgAhCJASADQYgBaiAHEJABQQAhAgJAAkACQCADLQCIAUEBcUUEQEEEIQEMAQsgAy0AiQFB+wBHBEBBDiEBDAELIANBkAFqIgEQigEgA0GAAWogARCIASADLQCEASEEIANB+ABqIAMoAoABIgwQkAECQAJAAkACQAJAIAMtAHhBAXFFBEBBAiECDAELIAMtAHkhAiAEQQFxIRcgA0HoAWpBBHIhESADQYACakEEciEUIANB8AFqIRggA0HUAWohHCADQfMBaiEdA0ACfwJAAkACfwJAIAJB/wFxIgRBLEcEQCAEQf0ARwRAIBcNAkEJDAMLIA1BgH5xIQJBAwwFC0EQIBcNARogDBCKASADQfAAaiAMEJABIAMtAHBBAXFFDQIgAy0AcSECCyACQf8BcSIEQSJGDQJBECAEQf0ARw0AGkETCyECIA0hCwwECyANQf8BcSELQQQhAgwDCyADQegAaiAMEJABIAMtAGhBAXFFBEBBBCECQQAhCwwDCyADLQBpQSJHBEBBDiECDAMLIAwQigEgA0HIAWogDBCPASADKALUASEFIAMoAtABIQQgAygCzAEhCyADKALIASICQRVHDQICQCALRQRAQQIhAgJAAkAgBUEFaw4CAQADCyAEQa6BwABBBhCNAkEAR0EBdCECDAILQQJBASAEQbSBwABBBRCNAhshAgwBC0ECIQICQAJAAkAgBUEFaw4CAQACCyALQa6BwABBBhCNAkEAR0EBdCECDAELQQJBASALQbSBwABBBRCNAhshAgsgBEUNACALEKsBC0EAIRcgDUGAfnELIQQCQAJAAkACQAJAAkACQCACIARyIg1B/wFxIgtBA0cEQCALDgIDAgELIBkhDQJAIBIiB0UEQCADQcgBakGugcAAQQYQFiADKALIAUEVRw0BIANB1AFqKAIAIRUgAygCzAEhByADQdABaigCACENCwJAIAZFBEAgA0HIAWpBtIHAAEEFEBYgAygCyAFBFUcNASADQdABaigCACEJIAMoAswBIQYgA0HUAWooAgAhCAsgAyAJNgKwASADIAY2AqwBIAMgFTYCqAEgAyANNgKkASADIAc2AqABIAdFDQ4gA0HIAWogA0GQAWoQjQEgAygCyAEiAUEVRg0FIAMoAswBIQsgAygC1AEhBCADKALQASEFIA0EQCAHEKsBCyAIBEAgCEEFdCEHIAZBEGohAgNAIAJBBGooAgAEQCACKAIAEKsBCyACQSBqIQIgB0EgayIHDQALCyALQQh2IQIgCUUNDyAGEKsBDA8LIBJFIQIgA0GsAWogA0HQAWopAwA3AgAgAyADKQPIATcCpAEgDUUNDCAHEKsBDAwLIANBrAFqIANB0AFqKQMANwIAIAMgAykDyAE3AqQBQQAhEiAGDQkMCgsgA0HIAWogDBCOAQJAIAMoAsgBIgFBFUcEQCADQfQBaiADQdQBaigCADYCACADIAMpAswBNwLsASADIAE2AugBDAELIANB6AFqIAwQFyADKALoAUEVRg0GCyADQawBaiADQfABaikDADcCACADIAMpA+gBNwKkASADQQA2AqABIAYNCAwJCyAGRQ0DIANBoAFqQQRyQbSBwABBBRAYIANBADYCoAEMBwsgEkUNASADQaABakEEckGugcAAQQYQGCADQQA2AqABIAYNBgwHCyADQcgBaiADQZABahCLASADKALIASIBQRVHBEAgAygC1AEhBCADKALQASEFIAMoAswBIQIgDQRAIAcQqwELIAgEQCAIQQV0IQcgBkEQaiELA0AgC0EEaigCAARAIAsoAgAQqwELIAtBIGohCyAHQSBrIgcNAAsLIAlFDQsgBhCrAQwLCyAAQRhqIAg2AgAgAEEUaiAJNgIAIABBEGogBjYCACAAQQxqIBU2AgAgAEEIaiANNgIAIAAgBzYCBCAAQQ02AgAMCwsgA0HIAWogDBCOAQJ/IAMoAsgBIgJBFUYEQCADQcgBaiAMEBogAygC1AEhFSADKALMASESIAMoAtABIgQgAygCyAEiAkEVRw0BGiAEIRkMAwsgAygC1AEhFSADKALMASESIAMoAtABCyEBIANBsAFqIBU2AgAgA0GsAWogATYCACADQagBaiASNgIAIAMgAjYCpAFBACESIANBADYCoAEgBg0EDAULIANByAFqIAwQjgECQAJAAkACQAJAAkACQAJAAkAgAygC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IAMgCEEBaiIINgLAASADQQhqIBAQkAEgAy0ACSECIAMtAAhBAXENCEEAIQYMEAsgA0EONgLsAQwECyADIA82AvgBIAMgCjYC9AEgAyAFNgLwASADIBY2AuwBDAMLIBggFCkCADcCACAYQQhqIBRBCGooAgA2AgAgAyAFNgLsAQwCCyADQcgBakGlgMAAQQYQGCADQQA2AtgBQQEhAgwJCyADQegBaiAOEI4BAkACQCADKALoASIFQRVHBEAgFCARKQIANwIAIBRBCGogEUEIaigCADYCACADIAU2AoACDAELIANBgAJqIA4QGiADKAKAAkEVRg0BCyADQdABaiADQYgCaikDADcDACADIAMpA4ACNwPIAQwKCyADKAKMAiEbIAMoAogCIRogAygChAIhAQwBCyADQdABaiARQQhqKQIANwMAIANBADYC2AEgAyARKQIANwPIAUEBIQIMBwsgA0EQaiAOEJABIAMtABEhBSADLQAQQQFxDQALCwwDCyAGQf8BcSEGQQQhCgwJCyADKALUASEIIAMoAtABIQkgAygCzAEhBgwICyADKAK8ASEJIAMoArgBIQYMBgsgAyAKNgLUASADIAk2AtABIAMgBDYCzAEgAyACNgLIAUEBIQILIBpFIAFFIAJFcnINACABEKsBCyADKQPIASIeQiCIpyEGIANB0AFqKQMAIh9CIIinIRAgHqchCiAfpyEJDAELQQAhBkEAIRALIAMoArgBIQcgCARAIAhBBXQhAUEAIQIDQCACIAdqIgRBFGooAgAiBQRAIARBEGooAgAQqwELIAEgAkEgaiICRw0ACwsgECEICyADKAK8AQRAIAcQqwELIApBFUcNAQsgA0HIAWogDBCMASADKALIASIKQRVGDQEgAygC1AEgAygC0AEhDSADKALMASAIBEAgCEEFdCEBIAZBEGohAgNAIAJBBGooAgAEQCACKAIAEKsBCyACQSBqIQIgAUEgayIBDQALCyAJBEAgBhCrAQshBiEIIA0hCQsgA0GwAWogCDYCACADQawBaiAJNgIAIANBqAFqIAY2AgAgAyAKNgKkAQwECyADIAwQkAEgAy0AASECIAMtAABBAXENAAtBAiECCyADQbABaiAFNgIAIANBrAFqIAQ2AgAgA0GoAWogCzYCACADIAI2AqQBIAZFDQELIAgEQCAIQQV0IQEg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A2pB+wA6AAAgAkHQAWogBEGYg8AAQQYQlwECQAJAIAIoAtABRQRAIAQoAggiAyAHKAIARgRAIAQgAxAQIAQoAgghAwsgBCADQQFqNgIIIAQoAgAgA2pBOjoAACACQdABaiAEEJsBIAIoAtABRQ0BIAJBzAFqIAVBCGooAgA2AgAgAiAFKQIANwLEAQwCCyACQZABaiACQdwBaigCADYCACACIAIpAtQBNwOIAQwSCyACQcABaiACKALUASACLQDYARCTASACKALAAUUNAwsgAkGQAWogAkHMAWooAgA2AgAgAiACKQLEATcDiAEMEAsgBygCACADRgRAIAQgAxAQIAQoAgghAwsgBCADQQFqNgIIIAQoAgAgA2pB+wA6AAAgAkHQAWogBEGUg8AAQQQQlwEgAigC0AENBCAEKAIIIgMgBygCAEYEQCAEIAMQECAEKAIIIQMLIAQgA0EBajYCCCAEKAIAIANqQTo6AAACQAJAAkACQAJAIAlBAWsOBAMCAQAECyACQdABaiAEQcKDwABBCxCcASACKALQAQ0HIAIgAi0A2AE6AKQBIAIgAigC1AE2AqABIAJB0AFqIAJBoAFqQc2DwABBDSAIQRRrKAIAIAhBDGsoAgAQDyACKALQAUUEQCACQcABaiACKAKgASACLQCkARCUAQwPCyAGIAUpAgA3AgAgBkEIaiAFQQhqKAIANgIADAsLIAJB0AFqIARB2oPAAEEMEJwBIAIoAtABBEAgBiAFKQIANwIAIAZBCGogBUEIaigCADYCAAwLCyACIAItANgBOgCkASACIAIoAtQBNgKgASACQdABaiACQaABakHNg8AAQQ0gCEEUaygCACAIQQxrKAIAEA8gAigC0AEEQCAGIAUpAgA3AgAgBkEIaiAFQQhqKAIANgIADAsLIAJB0AFqIAJBoAFqQeaDwABBBSAIQQhrKAIAIAgoAgAQDyACKALQAUUNDCAGIAUpAgA3AgAgBkEIaiAFQQhqKAIANgIADAoLIAJB0AFqIARB64PAAEEHEJwBIAIoAtABBEAgBiAFKQIANwIAIAZBCGogBUEIaigCADYCAAwKCyACIAItANgBOgCkASACIAIoAtQBNgKgASACQdABaiACQaABakHNg8AAQQ0gCEEUaygCACAIQQxrKAIAEA8gAigC0AEEQCAGIAUpAgA3AgAgBkEIaiAFQQhqKAIANgIADAoLIAJB0AFqIAJBoAFqQfKDwABBCyAIQQhqKQMAEBIgAigC0AEEQCAGIAUpAgA3AgAgBkEIaiAFQQhqKAIANgIADAoLIAJB0AFqIAJBoAFqIAhBCGsQEyACKALQAUUNCiAGIAUpAgA3AgAgBkEIaiAFQQhqKAIANgIADAkLIAJB0AFqIARBgITAAEELEJwBIAIoAtABRQ0HIAYgBSkCADcCACAGQQhqIAVBCGooAgA2AgAMCAsgAkHQAWogBEGXhMAAQQcQnAEgAigC0AEEQCAGIAUpAgA3AgAgBkEIaiAFQQhqKAIANgIADAgLIAIgAi0A2AE6AKQBIAIgAigC1AE2AqABIAJB0AFqIAJBoAFqQc2DwABBDSAIQRRrKAIAIAhBDGsoAgAQDyACKALQAQRAIAYgBSkCADcCACAGQQhqIAVBCGooAgA2AgAMCAsgAkHQAWogAkGgAWogCEEIaxATIAIoAtABBEAgBiAFKQIANwIAIAZBCGogBUEIaigCADYCAAwICyACQdABaiACQaABakG0gcAAQQUgCEEEaigCACAIQQxqKAIAEBQgAigC0AFFDQUgBiAFKQIANwIAIAZBCGogBUEIaigCADYCAAwHCyACQbwBaiACQdwBaigCADYCACACIAIpAtQBNwK0AQwaCyAEKAIIIgMgBygCAEYNCwwMCyACQZABaiACQdwBaigCADYCACACIAIpAtQBNwOIAQwMCyAGIAUpAgA3AgAgBkEIaiAFQQhqKAIANgIADAMLIAJBkAFqIAJB3AFqKAIANgIAIAIgAikC1AE3A4gBDAoLIAJBwAFqIAIoAqABIAItAKQBEJQBDAQLIAIgAigC1AEiAzYCmAEgCEEMaygCACEPIAhBFGsoAgAhDQJAIAItANgBBEAgAygCCCEJDAELIAMoAggiCiADKAIERgRAIAMgChAQIAMoAgghCgsgAyAKQQFqIgk2AgggAygCACAKakEsOgAACyACQQA6AJwBIANBBGoiCigCACAJRgRAIAMgCRAQIAMoAgghCQsgAygCACAJakEiOgAAIAMgCUEBaiIJNgIIIAooAgAgCWtBBE0EQCADIAlBBRARIAMoAgghCQsgAygCACAJaiIQQeaDwAAoAAA2AAAgEEEEakHqg8AALQAAOgAAIAMgCUEFaiIJNgIIIAooAgAgCWtBAU0EQCADIAlBAhARIAMoAgghCQsgAygCACAJakGi9AA7AAAgAyAJQQJqNgIIAkAgDUUEQCACQdABaiADEJgBDAELIAJB0AFqIAMgDSAPEJcBCwJAAkACQAJAIAIoAtABRQRAIAJB0AFqIAJBmAFqQYuEwABBByAIQSBqKQMAEBIgAigC0AENASACQdABaiACQZgBaiAIQQhrEBMgAigC0AENAiACQdABaiACQZgBakG0gcAAQQUgCEEEaigCACAIQQxqKAIAEBQgAigC0AENAyACQdABaiACQZgBakGShMAAQQUgCEEQaigCACAIQRhqKAIAEA8gAigC0AENBCACQcABaiACKAKYASACLQCcARCUAQwICyACQagBaiAFQQhqKAIAIgM2AgAgAiAFKQIAIhE3A6ABIAZBCGogAzYCACAGIBE3AgAMBAsgBiAFKQIANwIAIAZBCGogBUEIaigCADYCAAwDCyAGIAUpAgA3AgAgBkEIaiAFQQhqKAIANgIADAILIAYgBSkCADcCACAGQQhqIAVBCGooAgA2AgAMAQsgBiAFKQIANwIAIAZBCGogBUEIaigCADYCAAsgAkEBNgLAAQwCCyACQcABaiACKAKgASACLQCkARCUAQwBCyACQcABaiACKAKgASACLQCkARCUAQsgAigCwAFFBEAgBCgCCCIDIAcoAgBHDQQMAwsgAkGQAWogBkEIaigCADYCACACIAYpAgA3A4gBDAQLIAYgBSkCADcCACAGQQhqIAVBCGooAgA2AgAgAkEBNgLAAQsgAigCwAFFBEAgBCgCCCIDIAcoAgBGDQEMAgsgAkGQAWogBkEIaigCADYCACACIAYpAgA3A4gBDAILIAQgAxAQIAQoAgghAwsgBCgCACADakH9ADoAACAEIANBAWoiAzYCCCAMQdAAaikDACERIAxByABqKQMAIRIgAyAHKAIARw0BIAQgAxAQIAQoAgghAwwBCyACQbwBaiACQZABaigCADYCACACIAIpA4gBNwK0AQwLCyAEKAIAIANqQSw6AAAgBCADQQFqIgM2AgggBygCACADRgRAIAQgAxAQIAQoAgghAwsgBCgCACADakEiOgAAIAQgA0EBaiIDNgIIIAcoAgAgA2tBCE0EQCAEIANBCRARIAQoAgghAwsgBCgCACADaiIJQaSEwAApAAA3AAAgCUEIakGshMAALQAAOgAAIAQgA0EJaiIDNgIIIAcoAgAgA2tBAU0EQCAEIANBAhARIAQoAgghAwsgBCgCACADakGi9AA7AAAgBCADQQJqNgIIAkAgElAEQCACQdABaiAEEJgBDAELIAJB0AFqIAQgERCWAQsgAigC0AENAiAMQdgAai0AACEJIAQoAggiAyAHKAIARgRAIAQgAxAQIAQoAgghAwsgBCgCACADakEsOgAAIAQgA0EBaiIDNgIIIAcoAgAgA0YEQCAEIAMQECAEKAIIIQMLIAQoAgAgA2pBIjoAACAEIANBAWoiAzYCCCAHKAIAIANrQQdNBEAgBCADQQgQESAEKAIIIQMLIAQoAgAgA2pC8srB45bv17fuADcAACAEIANBCGoiAzYCCCAHKAIAIANrQQFNBEAgBCADQQIQESAEKAIIIQMLIAQoAgAgA2pBovQAOwAAIAQgA0ECajYCCAJAAkACQAJAAkAgCUEBaw4DAQIDAAsgAkHQAWogBEHFhMAAQQYQmQEMAwsgAkHQAWogBEHAhMAAQQUQmQEMAgsgAkHQAWogBEG5hMAAQQcQmQEMAQsgAkHQAWogBEG0hMAAQQUQmQELIAIoAtABBEAgAkG8AWogAkHcAWooAgA2AgAgAiACKQLUATcCtAEMCwsgAkGwAWogBEEAEJMBIAIoArABDQogCEHgAGohCEEBIQMgDEHgAGogDkcNAAtBAAUgAwtB/wFxQQBHEJIBIAIoAlgNCSACQdABaiACQUBrIAFBDGooAgAgAUEUaigCABAgIAIoAtABBEAgAkE8aiACQdwBaigCADYCACACIAIpAtQBNwI0DAsLIAFBIGooAgAhBiABQRhqKAIAIQcgAigCQCEEIAItAEQEQCAEKAIIIQMMAgsgBCgCCCIFIAQoAgRGBEAgBCAFEBAgBCgCCCEFCyAEIAVBAWoiAzYCCCAEKAIAIAVqQSw6AAAMAQsgAkG8AWogAkHcAWooAgA2AgAgAiACKQLUATcCtAEMBwsgAkEAOgBEIARBBGoiBSgCACADRgRAIAQgAxAQIAQoAgghAwsgBCgCACADakEiOgAAIAQgA0EBaiIDNgIIIAUoAgAgA2tBBU0EQCAEIANBBhARIAQoAgghAwsgBCgCACADaiIFQf6EwAAoAAA2AAAgBUEEakGChcAALwAAOwAAIAQgA0EGaiIDNgIIIARBBGooAgAgA2tBAU0EQCAEIANBAhARIAQoAgghAwsgBCgCACADakGi9AA7AAAgBCADQQJqNgIIIAJB0AFqIAQQmgEgAigC0AENAiACQdgBai0AACEDAkACQAJAIAJBsAFqIAIoAtQBIgUgBgR/IAcgBkEYbGohCCADRSEDIAJB0AFqQQRyIQYDQCADQQFxBEAgBSgCCCIDIAUoAgRGBEAgBSADEBAgBSgCCCEDCyAFIANBAWo2AgggBSgCACADakEsOgAACyACQdABaiAFEJsBIAIoAtABDQIgAiACLQDYAToAjAEgAiACKALUATYCiAEgAkHQAWogAkGIAWpB14TAAEEEIAcoAgAgB0EIaigCABAPIAIoAtABDQYgAkHQAWogAkGIAWogB0EMaigCACAHQRRqKAIAECAgAigC0AEEQCACQcwBaiACQdwBaigCADYCACACIAIpAtQBNwLEAQwJCyACQcABaiACKAKIASACLQCMARCTASACKALAAQ0IQQEhAyAHQRhqIgcgCEcNAAtBAAUgAwtB/wFxQQBHEJIBIAIoArABDQcgBCgCCCIHIARBBGoiAygCAEYEQCAEIAcQECAEKAIIIQcLIAQoAgAgB2pBLDoAACAEIAdBAWoiBzYCCCACQQA6AEQgAygCACAHRgRAIAQgBxAQIAQoAgghBwsgBCgCACAHakEiOgAAIAQgB0EBaiIHNgIIIAFBJGohAyAEQQRqIgUoAgAgB2tBA00EQCAEIAdBBBARIAQoAgghBwsgBCgCACAHakHkwtGLBjYAACAEIAdBBGoiATYCCCAFKAIAIAFrQQFNBEAgBCABQQIQESAEKAIIIQELIAQoAgAgAWpBovQAOwAAIAQgAUECajYCCCADKAIADQEgAkHQAWogBBCYAQwCCyACQcwBaiAGQQhqKAIANgIAIAIgBikCADcCxAEMBQsgAkHAAWogAxBqIAJB0AFqIAQgAigCwAEiASACKALIARCXASACKALEAUUNACABEKsBCyACKALQAQRAIAJBPGogAkHcAWooAgA2AgAgAiACKQLUATcCNAwJCyACQTBqIARBABCTASACKAIwDQggAigCCCIDIAIoAgRGBEAgAiADEBAgAigCCCEDCyACKAIAIANqQf0AOgAAIAIgA0EBajYCCAsgAkHIAWogAkEIaigCACIBNgIAIAIgAikDACIRNwPAASAAQQxqIAE2AgAgACARNwIEIABBDTYCAAwJCyACQcwBaiACQdwBaigCADYCACACIAIpAtQBNwLEAQwBCyACQbwBaiACQdwBaigCADYCACACIAIpAtQBNwK0AQwBCyACQbwBaiACQcwBaigCADYCACACIAIpAsQBNwK0AQsgAkE8aiACQbwBaigCADYCACACIAIpArQBNwI0DAMLIAJB5ABqIAJB3AFqKAIANgIAIAIgAikC1AE3AlwMAQsgAkHkAGogAkG8AWooAgA2AgAgAiACKQK0ATcCXAsgAkE8aiACQeQAaigCADYCACACIAIpAlw3AjQLIAJBHGogAkE8aigCADYCACACIAIpAjQ3AhQLIAJByAFqIgEgAkEcaigCADYCACACIAIpAhQ3A8ABIAIoAgQEQCACKAIAEKsBCyACQdgBaiABKAIANgIAIAIgAikDwAE3A9ABIABBuYfAAEHhACACQdABahAhCyACQeABaiQAC+ACAgJ/AX4jAEEgayIFJAAgASgCCCIEIAEoAgRGBEAgASAEEBAgASgCCCEECyABIARBAWo2AgggASgCACAEakH7ADoAACAFQRBqIAFBwITAAEEFEJcBAkACQCAFKAIQRQRAIAEoAggiBCABKAIERgRAIAEgBBAQIAEoAgghBAsgASAEQQFqNgIIIAEoAgAgBGpBOjoAACAFQRBqIAEgAiADEJcBIAUoAhANASABKAIIIgQgASgCBEYEQCABIAQQECABKAIIIQQLIABBADYCACABIARBAWo2AgggASgCACAEakH9ADoAAAwCCyAFQQhqIAVBHGooAgAiATYCACAFIAUpAhQiBjcDACAAQQxqIAE2AgAgACAGNwIEIABBATYCAAwBCyAFQQhqIAVBHGooAgAiATYCACAFIAUpAhQiBjcDACAAQQxqIAE2AgAgACAGNwIEIABBATYCAAsgBUEgaiQAC9QGAgR/AX4jAEHgAGsiBCQAIAEoAgAhBgJAIAEtAAQEQCAGKAIIIQUMAQsgBigCCCIHIAYoAgRGBEAgBiAHEBAgBigCCCEHCyAGIAdBAWoiBTYCCCAGKAIAIAdqQSw6AAALIAFBADoABCAGQQRqIgEoAgAgBUYEQCAGIAUQECAGKAIIIQULIAYoAgAgBWpBIjoAACAGIAVB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QT9xQYABcjoADyACIAFBBnZBP3FBgAFyOgAOIAIgAUEMdkE/cUGAAXI6AA0gAiABQRJ2QQdxQfABcjoADEEEDAELIAIgAUE/cUGAAXI6AA4gAiABQQx2QeABcjoADCACIAFBBnZBP3FBgAFyOgANQQMLIQEgASAAQQRqKAIAIAAoAggiA2tLBEAgACADIAEQESAAKAIIIQMLIAAoAgAgA2ogAkEMaiABEIsCGiAAIAEgA2o2AggLIAJBEGokAEEAC1oBAX8jAEEgayICJAAgAiAAKAIANgIEIAJBGGogAUEQaikCADcDACACQRBqIAFBCGopAgA3AwAgAiABKQIANwMIIAJBBGpB9InAACACQQhqEN4BIAJBIGokAAtKAQF/IAIgACgCACIAQQRqKAIAIAAoAggiA2tLBEAgACADIAIQESAAKAIIIQMLIAAoAgAgA2ogASACEIsCGiAAIAIgA2o2AghBAAvGBAICfwF+IwBBsAFrIgIkACACQQhqIAFBDGopAgA3AwAgAkEQaiABQRRqKQIANwMAIAJBGGogAUEcaikCADcDACACQSBqIAFBJGooAgA2AgAgAiABKQIENwMAAkACQCABKAIAIgMEQCABKQMoIQQgACADNgIAIAAgBDcCKCAAIAFBBGoiASkCADcCBCAAQQxqIAFBCGopAgA3AgAgAEEUaiABQRBqKQIANwIAIABBHGogAUEYaikCADcCACAAQSRqIAFBIGooAgA2AgAMAQsgAkFAayACQRxqKQIANwMAIAJBOGogAkEUaikCADcDACACQTBqIAJBDGopAgA3AwAgAiACKQIENwMoIAJBADYCUCACQgE3A0ggAkHYAGogAkHIAGpBqIXAABDyASACKAIoQQ1GBEAgAkGkAWpBADYCACACQYyKwAA2AqABIAJCATcClAEgAkGEjcAANgKQASACQdgAaiACQZABahD3AQ0CIAAgAikDSDcCBCAAQQA2AgAgAEEMaiACQdAAaigCADYCAAwBCyACQaQBakEBNgIAIAJCATcClAEgAkGMjcAANgKQASACQQM2AoQBIAIgAkGAAWo2AqABIAIgAkGMAWo2AoABIAIgAkEoajYCjAEgAkHYAGogAkGQAWoQ9wENASACKAIoIABBDGogAkHQAGooAgA2AgAgACACKQNINwIEIABBADYCAEENRg0AIAJB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yAFBDUcNASADKALMASEBCyADQfQCakH0gMAANgIAIANB7AJqQciAwAA2AgAgA0HkAmpBrIDAADYCACADQbACaiADQcABaikDADcDACADQcgCaiADQbABaikDADcDACADQYwDaiAGNgIAIANBiANqIA02AgAgA0GEA2ogCDYCACADQYADaiATNgIAIANB/AJqIA82AgAgA0HwAmogA0GYA2oiADYCACADQegCaiAANgIAIAMgAykDuAE3A6gCIAMgCjYCvAIgAyAJNgK4AiADIAMpA6gBNwPAAiADIAE2ApADIAMgEDYC+AIgAyAWNwPYAiADIAw2AtQCIAMgCzYC0AIgAyAANgLgAiADQegBaiINIQIgA0GoAmohB0EAIQojAEHgAWsiACQAIAAgATYCDCAAQfAAaiADQfgCaiIEENEBIABBHGogAEH4AGooAgA2AgAgACABNgIQIAAgACkDcDcCFCADQeACaiIBKAIEIQsgASgCACEMAkACQAJAAkACQAJAAkACQAJAQRRBARA9IgEEQCABQRBqQd2MwAAoAAA2AAAgAUEIakHVjMAAKQAANwAAIAFBzYzAACkAADcAAEEFQQEQPSIFRQ0IIAVBBGpB5YzAAC0AADoAACAFQeGMwAAoAAA2AAAgAEGwAWoiBhCVASAAQUBrIAYQmwEgACgCQA0BIAAgACgCRDYCwAEgACAAQcgAai0AADoAxAEgAEFAayAAQcABakGUgcAAQQggAUEUEA8gACgCQA0CIABBQGsgAEHAAWpBk4XAAEEHIAVBBRAPIAAoAkAEQCAAQdQBaiAAQcwAaigCADYCACAAIAApAkQ3AswBDAULIABByAFqIAAoAsABIAAtAMQBEJMBIAAoAsgBRQ0DDAQLQRRBARDOAQALIABB1AFqIABBzABqKAIANgIAIAAgACkCRDcCzAEMAgsgAEHUAWogAEHMAGooAgA2AgAgACAAKQJENwLMAQwBCyAAQfwAaiAAQbgBaigCADYCACAAIAApA7ABNwJ0DAELIABBqAFqIgYgAEHUAWooAgA2AgAgACAAKQLMATcDoAEgACgCtAEEQCAAKAKwARCrAQsgAEHIAGogBigCADYCACAAIAApA6ABNwNAIABB8ABqQd2JwABBFCAAQUBrECEgACgCcCIGQQ1HDQELIABB+ABqKAIAIQhBDSEGIAxBmoXAAEENIAAoAnQiCSAAQfwAaigCACALKAIUEQcAIAhFDQEgCRCrAQwBCyAAQThqIABBiAFqKQMANwMAIAAgACkDgAE3AzAgACgCfCEIIAAoAnghCSAAKAJ0IQoLIAEQqwEgBRCrAQJAAkACQAJAAkACQCAGQQ1GBEAgAEHwAGogDCALIABBEGoQJiAAKAJwIgFBDUYNAiAAQdgAaiAAQYwBaigCACIFNgIAIABB0ABqIABBhAFqKQIAIhU3AwAgAEHIAGogAEH8AGopAgAiFjcDACAAIAApAnQiFzcDQCACQSRqIAU2AgAgAkEcaiAVNwIAIAJBFGogFjcCACACQQxqIBc3AgAgAiABNgIIDAELIABBKGogAEE4aikDACIVNwMAIAAgACkDMCIWNwMgIAJBIGogFTcCACACQRhqIBY3AgAgAkEUaiAINgIAIAJBEGogCTYCACACQQxqIAo2AgAgAiAGNgIICyACQQA2AgAgAEEYaigCAARAIAAoAhQQqwELIARBBGooAgAEQCAEKAIAEKsBCyAEQRRqKAIAIgEEQCABQQV0IQEgBEEMaigCAEEQaiECA0AgAkEEaigCAARAIAIoAgAQqwELIAJBIGohAiABQSBrIgENAAsLIARBEGooAgAEQCAEKAIMEKsBCyAHQRRqKAIABEAgBygCEBCrAQsgB0EsaigCAA0BDAILIABBkAFqQgA3AwAgAEGAAWpCADcDACAAQgQ3A4gBIABCgICAgMAANwN4IABCCDcDcCAAQUBrIABB8ABqQeaMwABBgITAAEELECIgAEE4aiIFIARBCGooAgA2AgAgACAEKQIANwMwQQVBARA9IgFFDQQgAUEEakHwjMAALQAAOgAAIAFB7IzAACgAADYAACAAQfgAaiAFKAIANgIAIAAgACkDMDcDcCAAQdQBaiIFIABB8ABqIgYpAgA3AgAgBUEIaiAGQQhqKAIANgIAIABChYCAgNAANwLMASAAIAE2AsgBIABB1ABqKAIAIgEgAEHQAGooAgBGBEAgAEHMAGogARAjIAAoAlQhAQsgACgCTCABQRhsaiIFIAApA8gBNwIAIAVBCGogAEHQAWopAwA3AgAgBUEQaiAAQdgBaikDADcCACAAQfgAaiAAQcgAaikDADcDACAAQYgBaiAAQdgAaikDADcDACAAQZABaiAAQeAAaikDADcDACAAQZgBaiAAQegAaikDADcDACAAIAFBAWo2AlQgAEGAAWogAEHQAGopAwA3AwAgACAAKQNANwNwIABBADYC0AEgAEIBNwPIASAAQUBrIgUgAEHIAWpBqIXAABDyASAAQQxqKAIAIgGtQgAgAax9IAFBf0oiARsgASAFEIUCDQJBBUEBED0iBUUNAyAFQQRqQfWMwAAtAAA6AAAgBUHxjMAAKAAANgAAIABBhAFqKAIAIgEgAEGAAWoiCCgCAEYEQCAAQfwAaiABECMgACgChAEhAQsgACgCfCABQRhsaiIGQoWAgIDQADcCBCAGIAU2AgAgAiAAKQNwNwIAIAJBCGogAEH4AGopAwA3AgAgAkEYaiAAQYgBaikDADcCACACQSBqIABBkAFqKQMANwIAIAJBKGogAEGYAWopAwA3AgAgACABQQFqNgKEASACQRBqIAgpAwA3AgAgBiAAKQPIATcCDCAGQRRqIABB0AFqKAIANgIAIABBGGooAgAEQCAAKAIUEKsBCyAEQRRqKAIAIgEEQCABQQV0IQEgBEEMaigCAEEQaiECA0AgAkEEaigCAARAIAIoAgAQqwELIAJBIGohAiABQSBrIgENAAsLIARBEGooAgAEQCAEKAIMEKsBCyAHQRRqKAIABEAgBygCEBCrAQsgB0EsaigCAEUNAQsgBygCKBCrAQsgAEHgAWokAAwDC0HAhcAAQTcgAEEwakH4hcAAQdSGwAAQ6QEACwtBBUEBEM4BAAsgA0HIAGogDRAzIAMoApwBBEAgFBCrAQsgAygCjAEEQCASEKsBCyADKAJ8RQ0DIA4QqwEMAwsgA0GAAmogA0HgAWopAwA3AwAgA0H4AWogA0HYAWopAwA3AwAgA0HwAWogA0HQAWopAwA3AwAgAyADKQPIATcD6AEgA0EANgKgAiADQgE3A5gCIANBqAJqIgAgA0GYAmpBqIXAABDyASADQegBaiAAEH1FBEAgA0HUAGogA0GgAmooAgA2AgAgAyADKQOYAjcCTCADQQA2AkggA0HoAWoQLiAPBEAgEBCrAQsgBgRAIAZBBXQhASAIQRBqIQADQCAAQQRqKAIABEAgACgCABCrAQsgAEEgaiEAIAFBIGsiAQ0ACwsgDUUNASAIEKsBDAELDAMLIAoEQCAJEKsBCyAMRQ0AIAsQqwELIAMoApwBBEAgAygCmAEQqwELIAMoAowBBEAgAygCiAEQqwELIAMoAnxFDQAgDhCrAQsgA0HoAWogA0HIAGoQHiADKALoAUENRgRAIANB0AFqIANB9AFqKAIAIgA2AgAgAyADKQLsASIVNwPIASADQbACaiAANgIAIAMgFTcDqAIgA0GoAmoQfiADQcgAahArIANBoANqJAAPCyADQcACaiADQYACaikDADcDACADQbgCaiADQfgBaikDADcDACADQbACaiADQfABaikDADcDACADIAMpA+gBNwOoAkHFgcAAQSsgA0GoAmpB8IHAAEH0gsAAEOkBAAtBwIXAAEE3IANBmANqQfiFwABB1IbAABDpAQALnSoCE38CfiMAQdADayIDJAAQrQEgA0GoAWogABB/IANBuAFqIAEQfyADQcgBaiACEH8gA0HYAmogAygCqAEiEyADKAKwARAVAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJ/AkACfwJAAkACQAJAAkACQAJAAkACQAJAIAMoAvgCQQJHBEAgA0HwAWogA0HgAmopAwA3AwAgA0HgAWogA0H4AmopAwA3AwAgAyADKQPYAjcD6AEgAyADKQPwAjcD2AEgAygC6AIhESADKALsAiEOIAMoAoADIQ8gAygChAMhEiADKQOIAyEWIANB+AFqIAMoArgBIhQgAygCwAEQHCADKAL4AUENRw0CIANBkAJqKAIAIQwgA0GMAmooAgAhCiADQYgCaigCACEJIANBhAJqKAIAIQIgA0GAAmooAgAhDSADKAL8ASEQIANByAJqIgAgAygCyAEiFSADKALQARCJASADQfAAaiAAEJABIAMtAHBBAXENAQwUCyADQZACaiADQfACaikDADcDACADQYgCaiADQegCaikDADcDACADQYACaiADQeACaikDADcDACADIAMpA9gCNwP4ASADQQA2AtACIANCATcDyAIgA0GYAmoiACADQcgCakGohcAAEPIBIANB+AFqIAAQfQ0aIANBhAFqIANB0AJqKAIANgIAIAMgAykDyAI3AnwgA0EANgJ4IANB+AFqEC4MGAsgAy0AcSIAQfsARwRAIABBIkcEQEEKIQAMFQsgA0HYAmogA0HIAmoQOCADKALYAiIAQRVHDQ9BDiEADBQLIANByAJqIgQQigEgA0HYAmogBBA4AkACfyAD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AEEiRw0GIANBCGogBRCQAUEEIQAgAy0ACEEBcUUNB0EOIQAgAy0ACUEiRw0HIAUQigEgA0HYAmogBRCPASADKALYAiIAQRVHDQEgA0HkAmooAgAhByADQeACaigCACEAIAMoAtwCIgVFBEAgA0GYAmogACAHQYyKwABBABA2DAMLIANBmAJqIAUgB0GMisAAQQAQNiAARQ0CIAUQqwEMAgtBEyEADAYLIAMgAygC5AI2AqQCIAMgAykC3AI3ApwCIAMgADYCmAILIAMoApgCIgBBFUYNACADLwCdAiADLQCfAkEQdHIhByADKQOgAiEXIAMtAJwCIQUMBAsgA0HYAmogBBCNASADKALYAiIAQRVHBEAgAygC3AIiAUEIdiEHIAMoAuQCIQUgAygC4AIhBgwFCyADIAQQkAEgAy0AAEEBcUUNBUELIQAgAy0AAUH9AEcNBgsgBBCKASADQdgCaiADQcgCahCLASADKALYAiIAQRVGDQYLIAMoAuQCIQUgAygC4AIhBiADKALcAiEHDAQLQRAhAAsgBUH/AXEhASAXQiCIpyEFIBenIQYLIAFB/wFxIAdBCHRyIQcMAQtBBCEAQQAhBwsgAyAFNgLkAiADIAY2AuACIAMgBzYC3AIgAyAANgLYAiADQfgBakHkhsAAQRsgA0HYAmoQGyADKAL4AUENRw0BIANBgAJqKAIAIQEgAygC/AEhCAsgA0GkA2pB9IDAADYCACADQZwDakHIgMAANgIAIANBlANqQayAwAA2AgAgA0HgAmogA0HwAWopAwA3AwAgA0H4AmogA0HgAWopAwA3AwAgA0HEA2ogATYCACADQbwDaiAMNgIAIANBuANqIAo2AgAgA0G0A2ogCTYCACADQbADaiACNgIAIANBrANqIA02AgAgA0GgA2ogA0HIA2oiADYCACADQZgDaiAANgIAIAMgAykD6AE3A9gCIAMgDjYC7AIgAyARNgLoAiADIAMpA9gBNwPwAiADIAg2AsADIAMgEDYCqAMgAyAWNwOIAyADIBI2AoQDIAMgDzYCgAMgAyAANgKQAyADQZgCaiISIQogA0GQA2ohACADQdgCaiERIANBqANqIQkgASECIwBBMGsiCyQAAkAgCEUEQCALQShqIABBEGopAgA3AwAgC0EgaiAAQQhqKQIANwMAIAsgACkCADcDGCMAQeAAayIEJAAgBEEgaiALQRhqIgAoAgAiECAAKAIEIgJBDGooAgAQJAJAAkACQAJAIAQoAiAiDUENRgRAIAQoAiQiAUEBaiIAIAFIDQMgBEEsaigCACEOIARBKGooAgAhDyAEIARBMGooAgA2AlwgBCAONgJYIAQgDzYCVCAEIAA2AlAgBEEgaiAQIAIgBEHQAGoQJiAEKAIgIg1BDUcEQCAEQRhqIARBPGooAgA2AgAgBCAEKQI0NwMQIAQoAjAhAiAEKAIsIQEgBCgCKCEIIAQoAiQhDCAORQ0CIA8QqwEMAgsgDgRAIA8QqwELIARBQGtCADcDACAEQTBqQgA3AwAgBEIENwM4IARCgICAgMAANwMoIARCCDcDICAKIARBIGpBmIzAAEGejMAAQQkQIgwCCyAEQRhqIARBPGooAgA2AgAgBCAEKQI0NwMQIAQoAjAhAiAEKAIsIQEgBCgCKCEIIAQoAiQhDAsgBEEIaiAEQRhqKAIAIgA2AgAgBCAEKQMQIhY3AwAgCkEkaiAANgIAIApBHGogFjcCACAKQRhqIAI2AgAgCkEUaiABNgIAIApBEGogCDYCACAKQQxqIAw2AgAgCiANNgIIIApBADYCAAsgBEHgAGokAAwBC0GAgMAAQRxBuIzAABDZAQALIAlBBGooAgAEQCAJKAIAEKsBCyAJQQxqKAIAIQIgCUEUaigCACIABEAgAEEFdCEAIAJBEGohAQNAIAFBBGooAgAEQCABKAIAEKsBCyABQSBqIQEgAEEgayIADQALCyAJQRBqKAIARQ0BIAIQqwEMAQsgC0EQaiAAQRBqKQIANwMAIAtBCGogAEEIaikCADcDACALIAApAgA3AwAgC0EoaiAJQRBqKQIANwMAIAtBIGogCUEIaikCADcDACALIAkpAgA3AxgjAEHgAGsiBCQAIAtBGGoiCUEIaigCACEOIAkoAgAhDyAEQSBqIAsoAgAiDSALKAIEIgFBDGooAgAQJAJAAkACQAJAIAQoAiAiCEENRgRAIARBLGooAgAhECAEQShqKAIAIQACQCAOIARBMGooAgAiDEYEQCAPIAAgDhCNAkUNAQtBDSEIIBAEQCAQIQ0gACEBDAMLQQAhDSAAIQEMAwsgBCAONgJcIAQgEDYCWCAEIAA2AlQgBCACNgJQIARBIGogDSABIARB0ABqECYgBCgCICIIQQ1HBEAgBEEYaiAEQTxqKAIANgIAIAQgBCkCNDcDECAEKAIwIQwgBCgCLCENIAQoAighASAEKAIkIQIgEA0CDAMLIBAEQCAAEKsBCyAEQUBrQgA3AwAgBEEwakIANwMAIARCBDcDOCAEQoCAgIDAADcDKCAEQgg3AyAgCiAEQSBqQZiMwABByIzAAEEFECIgCUEEaigCAARAIA8QqwELIAlBDGooAgAhDCAJQRRqKAIAIgAEQCAAQQV0IQggDEEQaiEAA0AgAEEEaigCAARAIAAoAgAQqwELIABBIGohACAIQSBrIggNAAsLIAlBEGooAgANAwwECyAEQRhqIARBPGooAgA2AgAgBCAEKQI0NwMQIAQoAjAhDCAEKAIsIQ0gBCgCKCEBIAQoAiQhAgwBCyAAEKsBCyAEQQhqIARBGGooAgAiADYCACAEIAQpAxAiFjcDACAKQSRqIAA2AgAgCkEcaiAWNwIAIApBGGogDDYCACAKQRRqIA02AgAgCkEQaiABNgIAIApBDGogAjYCACAKIAg2AgggCkEANgIAIAlBBGooAgAEQCAPEKsBCyAJQQxqKAIAIQwgCUEUaigCACIABEAgAEEFdCEIIAxBEGohAANAIABBBGooAgAEQCAAKAIAEKsBCyAAQSBqIQAgCEEgayIIDQALCyAJQRBqKAIARQ0BCyAMEKsBCyAEQeAAaiQACyARQRRqKAIABEAgESgCEBCrAQsgEUEsaigCAARAIBEoAigQqwELIAtBMGokACADQfgAaiASEDMgAygCzAEEQCAVEKsBCyADKAK8AQRAIBQQqwELIAMoAqwBRQ0DIBMQqwEMAwsgA0GwAmogA0GQAmopAwA3AwAgA0GoAmogA0GIAmopAwA3AwAgA0GgAmogA0GAAmopAwA3AwAgAyADKQP4ATcDmAIgA0EANgLQAiADQgE3A8gCIANB2AJqIgAgA0HIAmpBqIXAABDyASADQZgCaiAAEH1FBEAgA0GEAWogA0HQAmooAgA2AgAgAyADKQPIAjcCfCADQQA2AnggA0GYAmoQLiANBEAgEBCrAQsgDARAIAxBBXQhASAJQRBqIQADQCAAQQRqKAIABEAgACgCABCrAQsgAEEgaiEAIAFBIGsiAQ0ACwsgCkUNASAJEKsBDAELDAMLIA4EQCAREKsBCyASRQ0AIA8QqwELIAMoAswBBEAgAygCyAEQqwELIAMoArwBBEAgAygCuAEQqwELIAMoAqwBRQ0AIBMQqwELIANBmAJqIANB+ABqEB4gAygCmAJBDUYEQCADQYACaiADQaQCaigCACIANgIAIAMgAykCnAIiFjcD+AEgA0HgAmogADYCACADIBY3A9gCIANB2AJqEH4gA0H4AGoQKyADQdADaiQADwsgA0HwAmogA0GwAmopAwA3AwAgA0HoAmogA0GoAmopAwA3AwAgA0HgAmogA0GgAmopAwA3AwAgAyADKQOYAjcD2AJBxYHAAEErIANB2AJqQfCBwABB5ILAABDpAQALQcCFwABBNyADQcgDakH4hcAAQdSGwAAQ6QEAC+kZAgx/A34jAEHAAmsiAiQAEK0BIAJB0ABqIAAQfyACQZgCaiABEH8gAkHIAWogAigCUCIHIAIoAlgQFQJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCACKALoAUECRwRAIAJB+ABqIAJB0AFqKQMANwMAIAJB6ABqIAJB6AFqKQMANwMAIAIgAikDyAE3A3AgAiACKQPgATcDYCACKALYASEEIAIoAtwBIQYgAigC8AEhCCACKAL0ASEJIAIpA/gBIQ8gAkFAayIAIAIoApgCIgwgAigCoAIQiQEgAkE4aiAAEJABIAItADhBAXFFDQMCQCACLQA5IgBB+wBHBEAgAEEiRwRAQQohAQwHCyACQcgBaiACQUBrEDkgAigCyAEiAUEVRw0BQQ4hAQwGCyACQUBrIgMQigEgAkHIAWogAxA5IAIoAsgBIgFBFUcNACACQcgBaiADEI4BIAIoAsgBIgFBFUcNACACQTBqIAMQkAFBBCEBIAItADBBAXFFDQMgAi0AMUH7AEcEQEEOIQEMBAsgAxCKASACQShqIAMQiAEgAi0ALCACQSBqIAIoAigiBRCQASACLQAgQQFxRQRAQQIhAQwEC0EBcSEKAkACQCACLQAhIgAiDUEsRwRAIA1B/QBGDQIgCg0BQQkhAQwGCyAKDQQgBRCKASACQRhqIAUQkAEgAi0AGEEBcUUNBSACLQAZIQALAkACQCAAQf0ARwRAIABBIkcNBiACQRBqIAUQkAEgAi0AEEEBcUUNB0EOIQEgAi0AEUEiRw0HIAUQigEgAkHIAWogBRCPASACKALIASIAQRVHDQEgAkHUAWooAgAhACACQdABaigCACEBIAIoAswBIgVFBEAgAkGgAWogASAAQYyKwABBABA2DAMLIAJBoAFqIAUgAEGMisAAQQAQNiABRQ0CIAUQqwEMAgtBEyEBDAYLIAIgAigC1AE2AqwBIAIgAikCzAE3AqQBIAIgADYCoAELIAIoAqABIgFBFUYNACACLwClASACLQCnAUEQdHIhCyACKQOoASEOIAItAKQBIQMMBAsgAkHIAWogAxCNASACKALIASIBQRVHBEAgAi8AzQEgAi0AzwFBEHRyIQsgAikD0AEhDiACLQDMASEDDAQLIAJBCGogAxCQASACLQAIQQFxRQ0EIAItAAlB/QBHBEBBCyEBDAYLIAMQigEgAkHIAWogAkFAaxCLASACKALIASIBQRVGDQYLIAIpA9ABIQ4gAigCzAEhAwwECyACQZgBaiACQeABaikDADcDACACQZABaiACQdgBaikDADcDACACQYgBaiACQdABaikDADcDACACIAIpA8gBNwOAASACQQA2ArACIAJCATcDqAIgAkGgAWoiACACQagCakGohcAAEPIBIAJBgAFqIAAQfUUEQCACQcwAaiACQbACaigCADYCACACIAIpA6gCNwJEIAJBATYCQCACQYABahAuDAkLDA4LQRAhAQsgA0H/AXEgC0EIdHIhAwwBC0EEIQFBACEDCyACIA43A9ABIAIgAzYCzAEgAiABNgLIASACQYABakGgh8AAQRkgAkHIAWoQGyACKAKAAUENRw0BCyACQZQCakH0gMAANgIAIAJBjAJqQciAwAA2AgAgAkGEAmpBrIDAADYCACACQdABaiACQfgAaikDADcDACACQegBaiACQegAaikDADcDACACQZACaiACQbgCaiIANgIAIAJBiAJqIAA2AgAgAiACKQNwNwPIASACIAY2AtwBIAIgBDYC2AEgAiACKQNgNwPgASACIA83A/gBIAIgCTYC9AEgAiAINgLwASACIAA2AoACIAJBgAFqIgUhASACQcgBaiEDIwBB8ABrIgAkACAAQRhqIAJBgAJqIgQoAgAgBCgCBEEMaigCABAkAkACQAJAAkACQAJAAkAgACgCGCIEQQ1GBEAgACgCHCEEIABBJGooAgAEQCAAQSBqKAIAEKsBCyAAQcgAaiIGEJUBIABBGGogBhCbASAAKAIYDQEgACAAKAIcNgJoIAAgAEEgai0AADoAbCAAQRhqIABB6ABqIAQQJyAAKAIYBEAgAEHkAGogAEEkaigCADYCACAAIAApAhw3AlwMBAsgAEHYAGogACgCaCAALQBsEJMBIAAoAlhFDQIMAwsgAEEQaiAAQTRqKAIAIgY2AgAgACAAKQIsIg43AwggACkCHCEPIAApAiQhECABQRxqIAY2AgAgASAONwIUIAEgEDcCDCABIA83AgQgASAENgIAIANBFGooAgAEQCADKAIQEKsBCyADQSxqKAIARQ0GIAMoAigQqwEMBgsgAEHkAGogAEEkaigCADYCACAAIAApAhw3AlwMAQsgAEEkaiAAQdAAaigCADYCACAAIAApA0g3AhwMAQsgAEFAayIEIABB5ABqKAIANgIAIAAgACkCXDcDOCAAKAJMBEAgACgCSBCrAQsgAEHgAGogBCgCADYCACAAIAApAzg3A1ggAEEYakH/hsAAQSEgAEHYAGoQISAAKAIYQQ1HDQELIAEgACkCHDcCBCABQQ02AgAgAUEMaiAAQSRqKAIANgIADAELIAEgACkDGDcDACABQRhqIABBMGopAwA3AwAgAUEQaiAAQShqKQMANwMAIAFBCGogAEEgaikDADcDAAsgA0EUaigCAARAIAMoAhAQqwELIANBLGooAgBFDQAgAygCKBCrAQsgAEHwAGokACAFQQRyIQACQCACKAKAASIBQQ1GBEAgAkHMAGogAEEIaigCADYCACACQQA2AkAgAiAAKQIANwJEDAELIAJBrAFqIABBCGooAgA2AgAgAkG4AWogAkGYAWopAwA3AwAgAiABNgKgASACIAIpA5ABNwOwASACIAApAgA3AqQBIAJBADYCsAIgAkIBNwOoAiACQcgBaiIAIAJBqAJqQaiFwAAQ8gEgAkGgAWogABB9DQogAkHMAGogAkGwAmooAgA2AgAgAiACKQOoAjcCRCACQQE2AkAgAkGgAWoQLgsgAigCnAIEQCAMEKsBCyACKAJUBEAgBxCrAQsgAkGoAmoQlQEgAUENRw0EIAIoArACIgAgAigCrAJGBEAgAkGoAmogABAQIAIoArACIQALIAIoAqgCIABqQfsAOgAAIAIgAEEBajYCsAIgAkHIAWogAkGoAmpBy4TAAEECEJcBIAIoAsgBDQIgAigCsAIiACACKAKsAkYEQCAC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KAIAIQIjAEEwayIAJAACfwJAAkACQAJAIAIoAgBBAWsOAwECAwALIABBHGpBADYCACAAQfSRwAA2AhggAEIBNwIMIABB5KjAADYCCCABIABBCGoQ9wEMAwsgAEEcakEANgIAIABB9JHAADYCGCAAQgE3AgwgAEHIqMAANgIIIAEgAEEIahD3AQwCCyAAQRxqQQA2AgAgAEH0kcAANgIYIABCATcCDCAAQaiowAA2AgggASAAQQhqEPcBDAELIABBHGpBATYCACAAQgE3AgwgAEHop8AANgIIIABBIDYCJCAAIAJBBGo2AiwgACAAQSBqNgIYIAAgAEEsajYCICABIABBCGoQ9wELIABBMGokAAu0AwEBfyAAKAIAIQIjAEEwayIAJAACfwJAAkACQAJAAkACQAJAIAIoAgBBAWsOBgECAwQFBgALIABBHGpBADYCACAAQfSRwAA2AhggAEIBNwIMIABB4LLAADYCCCABIABBCGoQ9wEMBgsgAEEcakEANgIAIABB9JHAADYCGCAAQgE3AgwgAEHMssAANgIIIAEgAEEIahD3AQwFCyAAQRxqQQA2AgAgAEH0kcAANgIYIABCATcCDCAAQeSowAA2AgggASAAQQhqEPcBDAQLIABBHGpBADYCACAAQfSRwAA2AhggAEIBNwIMIABByKjAADYCCCABIABBCGoQ9wEMAwsgAEEcakEANgIAIABB9JHAADYCGCAAQgE3AgwgAEG0ssAANgIIIAEgAEEIahD3AQwCCyAAQRxqQQA2AgAgAEH0kcAANgIYIABCATcCDCAAQaiowAA2AgggASAAQQhqEPcBDAELIABBHGpBATYCACAAQgE3AgwgAEHop8AANgIIIABBIDYCJCAAIAJBBGo2AiwgACAAQSBqNgIYIAAgAEEsajYCICABIABBCGoQ9wELIABBMGokAAsMACAAKAIAIAEQ3AELYgEBfyMAQTBrIgIkACAAKAIAIQAgAkEcakEBNgIAIAJCAjcCDCACQeSwwAA2AgggAkEeNgIkIAIgADYCLCACIAJBIGo2AhggAiACQSxqNgIgIAEgAkEIahD3ASACQTBqJAALVwEBfyMAQSBrIgIkACACIAA2AgQgAkEYaiABQRBqKQIANwMAIAJBEGogAUEIaikCADcDACACIAEpAgA3AwggAkEEakHckcAAIAJBCGoQ3gEgAkEgaiQACwgAIAEgARBUC5oEAQR/IwBBQGoiACQAIABBADYCCCAAQgE3AwAgAEEQaiIEIABBmI/AABDyAQJAIwBBQGoiAiQAQQEhAwJAIAQoAhgiBUGo38AAQQwgBEEcaigCACIEKAIMEQEADQACQCABKAIIIgMEQCACIAM2AgwgAkHnADYCFCACIAJBDGo2AhBBASEDIAJBATYCPCACQgI3AiwgAkG438AANgIoIAIgAkEQajYCOCAFIAQgAkEoahDeAUUNAQwCCyABKAIAIgMgASgCBEEMaigCABEIAELrkZO19tizovQAUg0AIAIgAzYCDCACQegANgIUIAIgAkEMajYCEEEBIQMgAkEBNgI8IAJCAjcCLCACQbjfwAA2AiggAiACQRBqNgI4IAUgBCACQShqEN4BDQELIAEoAgwhASACQSRqQcoANgIAIAJBHGpBygA2AgAgAiABQQxqNgIgIAIgAUEIajYCGCACQekANgIUIAIgATYCECACQQM2AjwgAkIDNwIsIAJBkN/AADYCKCACIAJBEGo2AjggBSAEIAJBKGoQ3gEhAwsgAkFAayQAIANFBEAgACgCCCECIAAoAgAhA0EMQQQQPSIBRQ0BIAEgAjYCCCABIAI2AgQgASADNgIAIAEQACABEKsBIAAoAgQEQCAAKAIAEKsBCyAAQUBrJAAPC0Gwj8AAQTcgAEE4akHoj8AAQcSQwAAQ6QEAC0EMQQQQzgEAC4cBAQV/IwBBIGsiAyQAAn8gAkUEQEEAIQJBAAwBCwJAA0AgA0EIaiABEFYgAygCCCIFRQ0BIAMoAhggAygCFCEHIAMoAgwEQCAFEKsBCyAEQQFqIQQEQCAHEKsBCyACIARHDQALQQAMAQsgBCECQQELIQEgACACNgIEIAAgATYCACADQSBqJAALiQMCCH8BfiMAQUBqIgIkAAJAIAEoAgAQBSIBBEAgASgCACIDRQ0BIAEpAgQhCiABEKsBIAIgCjcCNCACIAM2AjAgAkEYaiIEIAJBMGoiBRBsIAJBEGogAkEgaigCACIGNgIAIAIgAikDGCIKNwMIIAJBKGoiBygCACEBIAJBLGoiCCgCACEJIAIoAiQhAyACQThqIAY2AgAgAiAKNwMwIAQgBRBsIAgoAgAhBCAHKAIAIQUgAigCJCEGIAIoAhwEQCACKAIYEKsBCwJAIARFBEAgAEEANgIAIAEEQCADEKsBCyAFRQ0BIAYQqwEMAQsgACAJNgIUIAAgATYCECAAIAM2AgwgACAENgIIIAAgBTYCBCAAIAY2AgALIAJBQGskAA8LIAJBLGpBADYCACACQfSRwAA2AiggAkIBNwIcIAJBqKbAADYCGCACQRhqQZCnwAAQ1AEACyACQSxqQQA2AgAgAkH0kcAANgIoIAJCATcCHCACQcCnwAA2AhggAkEYakHIp8AAENQBAAt9AQV/IwBBIGsiAyQAAkAgAkUNAANAAkAgA0EIaiABEFYgAygCCCIERQ0AIAMoAhggAygCFCEGIAMoAgwEQCAEEKsBCwRAIAYQqwELIAJBAWsiAg0BDAILC0EBIQcLAkAgB0UEQCAAIAEQVgwBCyAAQQA2AgALIANBIGokAAsJACAAQgA3AgALDQAgACgCACABEFpBAAvNAgECfyMAQRBrIgIkAAJAAn8CQCABQYABTwRAIAJBADYCDCABQYAQTw0BIAIgAUE/cUGAAXI6AA0gAiABQQZ2QcABcjoADEECDAILIAAoAggiAyAAKAIERgRAIAAgAxAQIAAoAgghAwsgACADQQFqNgIIIAAoAgAgA2ogAToAAAwCCyABQYCABE8EQCACIAFBP3FBgAFyOgAPIAIgAUEGdkE/cUGAAXI6AA4gAiABQQx2QT9xQYABcjoADSACIAFBEnZBB3FB8AFyOgAMQQQMAQsgAiABQT9xQYABcjoADiACIAFBDHZB4AFyOgAMIAIgAUEGdkE/cUGAAXI6AA1BAwshASABIABBBGooAgAgACgCCCIDa0sEQCAAIAMgARARIAAoAgghAwsgACgCACADaiACQQxqIAEQiwIaIAAgASADajYCCAsgAkEQaiQAC1oBAX8jAEEgayICJAAgAiAAKAIANgIEIAJBGGogAUEQaikCADcDACACQRBqIAFBCGopAgA3AwAgAiABKQIANwMIIAJBBGpB3JHAACACQQhqEN4BIAJBIGokAAsKACAAIAEQWkEAC8UBAQF/IwBB8ABrIgMkACADIAI2AgwgAyABNgIIIANBJGpBATYCACADQgI3AhQgA0Ggk8AANgIQIANBITYCLCADIANBKGo2AiAgAyADQQhqNgIoIANBADYCOCADQgE3AzAgA0FAayIBIANBMGpBmI/AABDyASADQRBq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CCAEIAM2AgQgBCACNgIAQcAAQQEQPSIDRQ0EQQxBBBA9IgJFDQUgAkLAADcCBCACIAM2AgAgBCACEAciAw0BIAIoAgAiA0UNByACKQIEIQUgAhCrASAAQQhqIAU3AgAgACADNgIEIABBDTYCACAEEKsBDAILQSRBARA9IgJFDQUgAEKkgICAwAQ3AwggACACNgIEIABBAjYCACACQSBqQZijwAAoAAA2AAAgAkEYakGQo8AAKQAANwAAIAJBEGpBiKPAACkAADcAACACQQhqQYCjwAApAAA3AAAgAkH4osAAKQAANwAADAELIAMoAgAiAkUNBSADKQIEIQUgAxCrASABIAU3AgQgASACNgIAIAFBIjYCJCABIAE2AiAgAUEBNgI8IAFCATcCLCABQbijwAA2AiggASABQSBqNgI4IAFBEGogAUEoahDQASAAQQI2AgAgACABKQMQNwIEIABBDGogAUEYaigCADYCACABKAIEBEAgASgCABCrAQsgBBCrAQsgAUFAayQADwtBDEEEEM4BAAtBwABBARDOAQALQQxBBBDOAQALQSRBARDOAQALIAFBPGpBADYCACABQfSRwAA2AjggAUIBNwIsIAFBwKfAADYCKCABQShqQcinwAAQ1AEAC5kDAgJ/AX4jAEFAaiIBJAAgAkEIaigCACEDIAIoAgAhAgJAAkACQEEMQQQQPSIEBEAgBCADNgIIIAQgAzYCBCAEIAI2AgBB2gBBARA9IgNFDQFBDEEEED0iAkUNAiACQtoANwIEIAIgAzYCAAJAIAQgAhAIIgNFBEAgAigCACIDRQ0FIAIpAgQhBSACEKsBIABBCGogBTcCACAAIAM2AgQgAEENNgIADAELIAMoAgAiAkUNBCADKQIEIQUgAxCrASABIAU3AgQgASACNgIAIAFBIjYCJCABIAE2AiAgAUEBNgI8IAFCATcCLCABQdijwAA2AiggASABQSBqNgI4IAFBEGogAUEoahDQASAAQQI2AgAgACABKQMQNwIEIABBDGogAUEYaigCADYCACABKAIEBEAgASgCABCrAQsLIAQQqwEgAUFAayQADwtBDEEEEM4BAAtB2gBBARDOAQALQQxBBBDOAQALIAFBPGpBADYCACABQfSRwAA2AjggAUIBNwIsIAFBwKfAADYCKCABQShqQcinwAAQ1AEAC8cCAQF/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IABBCGpBADYCACAAQQE2AgALzQEBA38jAEEgayICJAACQAJAIAFBAWoiAUUNACAAQQRqKAIAIgNBAXQiBCABIAEgBEkbIgFBCCABQQhLGyIBQX9zQR92IQQCQCADBEAgAkEBNgIYIAIgAzYCFCACIAAoAgA2AhAMAQsgAkEANgIYCyACIAEgBCACQRBqEIIBIAIoAgQhAyACKAIARQRAIAAgAzYCACAAQQRqIAE2AgAMAgsgAkEIaigCACIAQYGAgIB4Rg0BIABFDQAgAyAAEM4BAAsQzwEACyACQSBqJAALzwEBAn8jAEEgayIDJAACQAJAIAEgASACaiIBSw0AIABBBGooAgAiAkEBdCIEIAEgASAESRsiAUEIIAFBCEsbIgFBf3NBH3YhBAJAIAIEQCADQQE2AhggAyACNgIUIAMgACgCADYCEAwBCyADQQA2AhgLIAMgASAEIANBEGoQggEgAygCBCECIAMoAgBFBEAgACACNgIAIABBBGogATYCAAwCCyADQQhqKAIAIgBBgYCAgHhGDQEgAEUNACACIAAQzgEACxDPAQALIANBIGokAAsdACABKAIARQRAAAsgAEHEs8AANgIEIAAgATYCAAtVAQJ/IAEoAgAhAiABQQA2AgACQCACBEAgASgCBCEDQQhBBBA9IgFFDQEgASADNgIEIAEgAjYCACAAQcSzwAA2AgQgACABNgIADwsAC0EIQQQQzgEAC+0DAQF/IwBBMGsiAiQAAn8CQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgACgCAEEBaw4UAQIDBAUGBwgJCgsMDQ4PEBESExQACyACQcK5wAA2AihBIgwUCyACQam5wAA2AihBGQwTCyACQY25wAA2AihBHAwSCyACQfK4wAA2AihBGwwRCyACQdO4wAA2AihBHwwQCyACQa24wAA2AihBJgwPCyACQYW4wAA2AihBKAwOCyACQc63wAA2AihBNwwNCyACQae3wAA2AihBJwwMCyACQe+2wAA2AihBOAwLCyACQbe2wAA2AihBOAwKCyACQYm2wAA2AihBLgwJCyACQfG1wAA2AihBGAwICyACQeK1wAA2AihBDwwHCyACQda1wAA2AihBDAwGCyACQbu1wAA2AihBGwwFCyACQaC1wAA2AihBGwwECyACQdG0wAA2AihBzwAMAwsgAkGVtMAANgIoQTwMAgsgAkHcs8AANgIoQTkMAQsgAiAAQQRqKAIANgIoIABBDGooAgALIQAgAkEcakEBNgIAIAJBwwA2AiQgAiAANgIsIAJCATcCDCACQdSzwAA2AgggAiACQShqNgIgIAIgAkEgajYCGCABIAJBCGoQ9wEgAkEwaiQACxAAIABBAToABCAAIAE2AgALFwAgAEEANgIIIAAgAjYCBCAAIAE2AgALKQEBfyAAKAIIQQFqIgEEQCAAIAE2AggPC0HgusAAQRxBxLzAABDZAQALXwEDfyAAAn8gASgCCCIAIAEoAgQiAkkEQCABKAIAIQMDQEESIAAgA2otAABBCWsiBEEXS0EBIAR0QZOAgARxRXINAhogASAAQQFqIgA2AgggACACRw0ACwtBFQs2AgALzAIBBX8CQAJAAkACQAJAAkACQAJAIAEoAggiAiABKAIEIgNJBEAgASgCACEFA0ACQCACIAVqLQAAIgRBCWsOJAAABAQABAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQEBAQEBAQEBgMLIAEgAkEBaiICNgIIIAIgA0cNAAsLIABBADsABSAAQQE2AgAgAEEHakEAOgAADwsgBEHdAEYNAQsgAEESNgIADwsgAkEBaiICRQ0BIABBFTYCACABIAI2AggPCyACQQFqIgJFDQEgASACNgIIIAIgA08NAwNAIAIgBWotAAAiBEEJayIGQRdLQQEgBnRBk4CABHFFcg0DIAEgAkEBaiICNgIIIAIgA0cNAAsMAwtB4LrAAEEcQcS8wAAQ2QEAC0HgusAAQRxBxLzAABDZAQALIARB3QBHDQAgAEETNgIADwsgAEESNgIAC9MBAQR/AkACQAJAAkACQCABKAIIIgIgASgCBCIDSQRAIAEoAgAhBANAAkAgAiAEai0AACIFQQlrDiQAAAQEAAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAYDCyABIAJBAWoiAjYCCCACIANHDQALCyAAQQA7AAUgAEECNgIAIABBB2pBADoAAA8LIAVB/QBGDQELIABBEjYCAA8LIAJBAWoiAkUNASAAQRU2AgAgASACNgIIDwsgAEETNgIADwtB4LrAAEEcQcS8wAAQ2QEAC8kBAQN/AkACQAJAIAEoAggiAiABKAIEIgNJBEAgASgCACEEA0ACQCACIARqLQAAQQlrDjIAAAQEAAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAwQLIAEgAkEBaiICNgIIIAIgA0cNAAsLIABBADsABSAAQQI2AgAgAEEHakEAOgAADwsgAkEBaiICRQ0BIABBFTYCACABIAI2AggPCyAAQQU2AgAPC0HgusAAQRxBxLzAABDZAQALjBIBDH8jAEEwayIDJAACQAJAIAEoAggiBSABKAIEIgZJBEAgASgCACEEIAUhAgNAIAECfwJAIAIgBGotAAAiB0EiRwRAIAdB3ABGDQFBACEJIAJBAWoMAgsgAkEBaiEHIAlBAXFBACEJRQ0EIAcMAQtBASEIIAlBAXMhCSACQQFqCyICNgIIIAIgBkkNAAsLIABBAzYCAAwBCyABIAc2AggCQAJAAkAgCEUEQCACIAVJDQIgAiAGSw0BIANBIGogBCAFaiACIAVrEOEBIAMoAiANAyAAQQhqIAMpAiQ3AgAgAEIVNwIADAQLIAIgBU8EQCACIAZNBEAgAiAFayEHAkACQAJAAkACQAJAAkAgA0EgagJ/IAIgBUYEQEEAIQJBAQwBCyAHQX9KIgFFDQcgByABED0iBkUNBiAEIAVqIQkgA0EANgIQIAMgBzYCDCADIAY2AgggA0EANgIYIANBADYCHEEAIQJBACEIQQAhAUEAIQVBACELA0AgCS0AACIKIgxBIEkEQEEAIQQMBAsCQAJAAkACQAJAAkACQAJAAkACQAJAIAFBAXFFBEAgCA0BIAxB3ABHDQJBASEIQQAhAQwLCwJAIApBMGtB/wFxQQpJDQBBDCEEIAxBwQBrDiYAAAAAAAAPDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDwAAAAAAAA8LIAVBA0sNAiADQRxqIAVqIAo6AABBASEBIAVBAWoiBUEERw0KIAMoAhwiAUEwayIFQf8BcUEKSQ0EIAFBwQBrQf8BcUEGSQ0DIAFB4QBrQf8BcUEGTw0FIAFB1wBrIQUMBAtBASEBQQwhBEEBIQgCQAJAAkACQAJAAkAgDEEiaw5UABMTExMTExMTExMTEwATExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTEwATExMTEwETExMCExMTExMTEwMTExMEEwUPEwsgAygCDCACRgRAIANBCGogAhCDASADKAIQIQILIAMoAggiBiACaiAKOgAAIAJBAWohAgwMCyADKAIMIAJGBEAgA0EIaiACEIMBIAMoAhAhAgsgAygCCCIGIAJqQQg6AAAgAkEBaiECDAsLIAMoAgwgAkYEQCADQQhqIAIQgwEgAygCECECCyADKAIIIgYgAmpBDDoAACACQQFqIQIMCgsgAygCDCACRgRAIANBCGogAhCDASADKAIQIQILIAMoAggiBiACakEKOgAAIAJBAWohAgwJCyADKAIMIAJGBEAgA0EIaiACEIMBIAMoAhAhAgsgAygCCCIGIAJqQQ06AAAgAkEBaiECDAgLIAMoAgwgAkYEQCADQQhqIAIQgwEgAygCECECCyADKAIIIgYgAmpBCToAACACQQFqIQIMBwsgCwRAQREhBAwNCyADKAIMIAJGBEAgA0EIaiACEIMBIAMoAgghBiADKAIQIQILIAIgBmogCjoAACACQQFqIQIMBgsgBUEEQcy6wAAQ1QEACyABQTdrIQULAkAgAUEIdiIEQTBrIghB/wFxQQpJDQAgBEHBAGtB/wFxQQZPBEAgBEHhAGtB/wFxQQZPDQIgBEHXAGshCAwBCyAEQTdrIQgLAkAgAUEQdiIEQTBrIgpB/wFxQQpJDQAgBEHBAGtB/wFxQQZPBEAgBEHhAGtB/wFxQQZPDQIgBEHXAGshCgwBCyAEQTdrIQoLIAFBGHYiBEEwayIBQf8BcUEKSQ0CIARBwQBrQf8BcUEGSQ0BIARB4QBrQf8BcUEGTw0AIARB1wBrIQEMAgsjAEEQayIAJAAgAEHQu8AANgIIIABBHTYCBCAAQbG7wAA2AgAjAEEQayIBJAAgAUEIaiAAQQhqKAIANgIAIAEgACkCADcDACMAQRBrIgAkACAAIAEpAgA3AwggAEEIakGws8AAQQAgASgCCEEBELIBAAsgBEE3ayEBCyAIQQh0IAVBDHRyIApB/wFxQQR0ciIFIAFB/wFxciEBAn8CQCAFQYDwA3FBgLADRwRAIAFB//8DcSIBQYCwv39zQYCQvH9JIgVFDQFBDCEEDAkLAkAgCwRAIAFB//8DcUGAuANPDQFBCCEEDAoLIAFB//8DcUH/twNLDQhBACEFQQEhCyABIQ0MBAsgDUH//wNxQYCwA2siBUH//wNxIgggBUcNCkEPIQQgAUGAyABqQf//A3EgCEEKdHJBgIAEaiIBQYCwA3NBgIDEAGtBgJC8f0kgAUGAgMQARnINCCADIAFBP3FBgAFyOgAbIAMgAUEGdkE/cUGAAXI6ABogAyABQQx2QT9xQYABcjoAGSADIAFBEnZBB3FB8AFyOgAYIAMoAgwgAmtBA00EQCADQQhqIAJBBBCEASADKAIQIQILIAMoAggiBiACaiADKAIYNgAAQQAhCyACQQRqDAELAn9BgIDEACABIAUbIgFBgAFPBEAgAUGAEE8EQCADIAFBP3FBgAFyOgAaIAMgAUEMdkHgAXI6ABggAyABQQZ2QT9xQYABcjoAGUEDDAILIAMgAUE/cUGAAXI6ABkgAyABQQZ2QcABcjoAGEECDAELIAMgAToAGEEBCyEBIAEgAygCDCACa0sEQCADQQhqIAIgARCEASADKAIQIQILIAMoAggiBiACaiADQRhqIAEQiwIaIAEgAmoLIQJBACEFCyADIAI2AhALQQAhAUEAIQgLIAlBAWohCSAHQQFrIgcNAAtBDCEEIAgNAkERIQQgCw0CIAMoAgwhByADKAIICyIJIAIQ4QEgAygCIEUNBCADQShqMQAAQiCGQoCAgIAgUQ0EIAcEQCAJEKsBC0EPIQQMAgtBBiEECyADKAIMIgIEQCADKAIIEKsBCwsgACACNgIMIAAgBzYCCCAAIAk2AgQgACAENgIADAkLQZC7wABBIUH8usAAENkBAAsgAEEMaiACNgIAIABBCGogBzYCACAAIAk2AgQgAEEVNgIADAcLIAcgARDOAQALEM8BAAsgAiAGQdS8wAAQ1wEACyAFIAJB1LzAABDaAQALIAIgBkHkvMAAENcBAAsgBSACQeS8wAAQ2gEACyAAQQ82AgALIANBMGokAAttAQZ/AkAgASgCCCICIAEoAgQiBE8NACABKAIAIQUDQCACIAVqLQAAIgZBCWsiB0EXTUEAQQEgB3RBk4CABHEbRQRAQQEhAwwCCyABIAJBAWoiAjYCCCACIARHDQALCyAAIAY6AAEgACADOgAACzMBA38gACABKAIIIgIgASgCBCIDSQR/IAEoAgAgAmotAAAFIAQLOgABIAAgAiADSToAAAs/ACABKAIIIgIgASgCBEYEQCABIAIQgwEgASgCCCECCyAAQQA2AgAgASACQQFqNgIIIAEoAgAgAmpB3QA6AAALPwAgASgCCCICIAEoAgRGBEAgASACEIMBIAEoAgghAgsgAEEANgIAIAEgAkEBajYCCCABKAIAIAJqQf0AOgAAC4ABAQJ/IAEoAggiAiABKAIEIgRGBEAgASACEIMBIAEoAgQhBCABKAIIIQILIAEgAkEBaiIDNgIIIAIgASgCACICakH9ADoAACADIARGBEAgASAEEIMBIAEoAgghAyABKAIAIQILIABBADYCACABIANBAWo2AgggAiADakH9ADoAAAspAQF/QYAIQQEQPSIBRQRAQYAIQQEQzgEACyAAQoAINwIEIAAgATYCAAuFAgIEfwF+IwBBIGsiBCQAIARBF2pBADYAACAEQRBqQgA3AwAgBEIANwMIIAQgAkIKgqdBMHI6ABtBEyEFAkACQCACQgpaBEBBEyEDA0AgA0EBayIFIANLDQIgBEEIaiAFaiACQgqAIgdCCoKnQTByOgAAIAJC5ABUIAUhAyAHIQJFDQALIAVBFU8NAgtBFCAFayIGIAFBBGooAgAgASgCCCIDa0sEQCABIAMgBhCEASABKAIIIQMLIAEoAgAgA2ogBEEIaiAFaiAGEIsCGiAAQQA2AgAgASADIAZqNgIIIARBIGokAA8LQZC7wABBIUGAvsAAENkBAAsgBUEUQYC+wAAQ1gEAC68NAQZ/IwBBEGsiBiQAIAEoAggiBSABQQRqKAIARgRAIAEgBRCDASABKAIIIQULIAEgBUEBaiIENgIIIAEoAgAgBWpBIjoAACAGQQA2AgwCQCADRQ0AIAIgA2ohCSABQQRqIQMDQAJ/IAIsAAAiBUF/SgRAIAVB/wFxIQUgAkEBagwBCyACLQABQT9xIQcgBUEfcSEIIAVBX00EQCAIQQZ0IAdyIQUgAkECagwBCyACLQACQT9xIAdBBnRyIQcgBUFwSQRAIAcgCEEMdHIhBSACQQNqDAELIAhBEnRBgIDwAHEgAi0AA0E/cSAHQQZ0cnIhBSACQQRqCyECIAECfwJAAkACQAJAAkACQAJAAkAgBUEIaw4bAgMEBwUGBwcHBwcHBwcHBwcHBwcHBwcHBwcBAAsgBUHcAEcEQCAFQYCAxABHDQcMCgsgAygCACAERgRAIAEgBBCDASABKAIIIQQLIAEoAgAgBGpB3AA6AAAgASAEQQFqIgQ2AgggAygCACAERgRAIAEgBBCDASABKAIIIQQLIAEoAgAgBGpB3AA6AAAgBEEBagwHCyADKAIAIARGBEAgASAEEIMBIAEoAgghBAsgASgCACAEakHcADoAACABIARBAWoiBDYCCCADKAIAIARGBEAgASAEEIMBIAEoAgghBAsgASgCACAEakEiOgAAIARBAWoMBgsgAygCACAERgRAIAEgBBCDASABKAIIIQQLIAEoAgAgBGpB3AA6AAAgASAEQQFqIgQ2AgggAygCACAERgRAIAEgBBCDASABKAIIIQQLIAEoAgAgBGpB4gA6AAAgBEEBagwFCyADKAIAIARGBEAgASAEEIMBIAEoAgghBAsgASgCACAEakHcADoAACABIARBAWoiBDYCCCADKAIAIARGBEAgASAEEIMBIAEoAgghBAsgASgCACAEakH0ADoAACAEQQFqDAQLIAMoAgAgBEYEQCABIAQQgwEgASgCCCEECyABKAIAIARqQdwAOgAAIAEgBEEBaiIENgIIIAMoAgAgBEYEQCABIAQQgwEgASgCCCEECyABKAIAIARqQe4AOgAAIARBAWoMAwsgAygCACAERgRAIAEgBBCDASABKAIIIQQLIAEoAgAgBGpB3AA6AAAgASAEQQFqIgQ2AgggAygCACAERgRAIAEgBBCDASABKAIIIQQLIAEoAgAgBGpB5gA6AAAgBEEBagwCCyADKAIAIARGBEAgASAEEIMBIAEoAgghBAsgASgCACAEakHcADoAACABIARBAWoiBDYCCCADKAIAIARGBEAgASAEEIMBIAEoAgghBAsgASgCACAEakHyADoAACAEQQFqDAELAn8CQAJAIAVBIE8EQCAFQYABSQ0BIAVBgBBPDQIgBiAFQT9xQYABcjoADSAGIAVBBnZBwAFyOgAMQQIMAwsgAygCACAERgRAIAEgBBCDASABKAIIIQQLIAEoAgAgBGpB3AA6AAAgASAEQQFqIgQ2AgggAygCACAERgRAIAEgBBCDASABKAIIIQQLIAEoAgAgBGpB9QA6AAAgASAEQQFqIgQ2AgggAygCACAERgRAIAEgBBCDASABKAIIIQQLIAEoAgAgBGpBMDoAACABIARBAWoiBDYCCCADKAIAIARGBEAgASAEEIMBIAEoAgghBAsgASgCACAEakEwOgAAIAEgBEEBaiIENgIIIAVBD3EiCEEKSSEHIAMoAgAgBEYEQCABIAQQgwEgASgCCCEECyABKAIAIARqIAVB8AFxQQR2QTByOgAAIAEgBEEBaiIENgIIIAMoAgAgBEYEQCABIAQQgwEgASgCCCEECyABKAIAIARqIAhBMHIgCEE3aiAHGzoAACAEQQFqDAMLIAMoAgAgBEYEQCABIAQQgwEgASgCCCEECyABKAIAIARqIAU6AAAgBEEBagwCCyAFQYCABE8EQCAGIAVBP3FBgAFyOgAPIAYgBUESdkHwAXI6AAwgBiAFQQZ2QT9xQYABcjoADiAGIAVBDHZBP3FBgAFyOgANQQQMAQsgBiAFQT9xQYABcjoADiAGIAVBDHZB4AFyOgAMIAYgBUEGdkE/cUGAAXI6AA1BAwshBSAFIAMoAgAgBGtLBEAgASAEIAUQhAEgASgCCCEECyABKAIAIARqIAZBDGogBRCLAhogBCAFagsiBDYCCCACIAlHDQALCyABQQRqKAIAIARGBEAgASAEEIMBIAEoAgghBAsgAEEANgIAIAEgBEEBajYCCCABKAIAIARqQSI6AAAgBkEQaiQAC0wBAX8gAUEEaigCACABKAIIIgJrQQNNBEAgASACQQQQhAEgASgCCCECCyAAQQA2AgAgASACQQRqNgIIIAEoAgAgAmpB7uqx4wY2AAALDQAgACABIAIgAxCXAQtSAQF/IAEoAggiAiABKAIERgRAIAEgAhCDASABKAIIIQILIAAgATYCBCAAQQA2AgAgASACQQFqNgIIIABBCGpBAToAACABKAIAIAJqQdsAOgAAC1IBAX8gASgCCCICIAEoAgRGBEAgASACEIMBIAEoAgghAgsgACABNgIEIABBADYCACABIAJBAWo2AgggAEEIakEBOgAAIAEoAgAgAmpB+wA6AAALngICAn8BfiMAQSBrIgUkACABKAIIIgQgASgCBEYEQCABIAQQgwEgASgCCCEECyABIARBAWo2AgggASgCACAEakH7ADoAACAFQRBqIAEgAiADEJcBAkAgBSgCEEUEQCABKAIIIgQgASgCBEYEQCABIAQQgwEgASgCCCEECyABKAIAIARqQTo6AAAgASAEQQFqIgQ2AgggASgCBCAERgRAIAEgBBCDASABKAIIIQQLIAAgATYCBCAAQQA2AgAgASAEQQFqNgIIIABBCGpBAToAACABKAIAIARqQfsAOgAADAELIAVBCGogBUEcaigCACIBNgIAIAUgBSkCFCIGNwMAIABBDGogATYCACAAIAY3AgQgAEEBNgIACyAFQSBqJAALFgAgACgCACIAKAIAIAAoAgQgARCAAgsdACABKAIARQRAAAsgAEGI1cAANgIEIAAgATYCAAtVAQJ/IAEoAgAhAiABQQA2AgACQCACBEAgASgCBCEDQQhBBBA9IgFFDQEgASADNgIEIAEgAjYCACAAQYjVwAA2AgQgACABNgIADwsAC0EIQQQQzgEAC5QEAQN/IwBBMGsiAiQAAn8CQAJAAkACQCAAKAIEIgMOAwACAwELIwBBEGsiACQAIABB0NbAADYCCCAAQQ42AgQgAEG/1sAANgIAIwBBEGsiASQAIAFBCGogAEEIaigCADYCACABIAApAgA3AwAjAEEQayIAJAAgACABKQIANwMIIABBCGpB9NTAAEEAIAEoAghBARCyAQALIAJBLGpBADYCACACQYjVwAA2AiggAkIBNwIcIAJBoNXAADYCGEEBIAEgAkEYahD3AQ0CGiADQQN0IQMgACgCACEAAkADQCACIAA2AhQgBARAIAJBADYCLCACQYjVwAA2AiggAkIBNwIcIAJBrNXAADYCGCABIAJBGGoQ9wENAgsgAkEBNgIsIAJCAjcCHCACQbTVwAA2AhggAkHMADYCBCACIAI2AiggAiACQRRqNgIAIAEgAkEYahD3AQ0BIABBCGohACAEQQFrIQQgA0EIayIDDQALQQAMAwtBAQwCCyACQSxqQQE2AgAgAkICNwIcIAJBtNXAADYCGCACQc0ANgIEIAIgACgCADYCACACIAI2AiggASACQRhqEPcBDAELIAJBDGpBzQA2AgAgAkEsakECNgIAIAJCAzcCHCACQczVwAA2AhggAkHNADYCBCACIAAoAgAiADYCACACIABBCGo2AgggAiACNgIoIAEgAkEYahD3AQsgAkEwaiQACwwAQsiF+aSet9TbEgshAQF/AkAgACgCBCIBRQ0AIABBCGooAgBFDQAgARCrAQsL1gIBAn8jAEEQayICJAAgACgCACEAAkACfwJAIAFBgAFPBEAgAkEANgIMIAFBgBBPDQEgAiABQT9xQYABcjoADSACIAFBBnZBwAFyOgAMQQIMAgsgACgCCCIDIAAoAgRGBEAgACADEBAgACgCCCEDCyAAIANBAWo2AgggACgCACADaiABOgAADAILIAFBgIAETwRAIAIgAUE/cUGAAXI6AA8gAiABQQZ2QT9xQYABcjoADiACIAFBDHZBP3FBgAFyOgANIAIgAUESdkEHcUHwAXI6AAxBBAwBCyACIAFBP3FBgAFyOgAOIAIgAUEMdkHgAXI6AAwgAiABQQZ2QT9xQYABcjoADUEDCyEBIAEgAEEEaigCACAAKAIIIgNrSwRAIAAgAyABEBEgACgCCCEDCyAAKAIAIANqIAJBDGogARCLAhogACABIANqNgIICyACQRBqJABBAAtaAQF/IwBBIGsiAiQAIAIgACgCADYCBCACQRhqIAFBEGopAgA3AwAgAkEQaiABQQhqKQIANwMAIAIgASkCADcDCCACQQRqQeDWwAAgAkEIahDeASACQSBqJAALkwMBBX8CQAJAAkACQCABQQlPBEBBEEEIELMBIAFLDQEMAgsgABCmASEEDAILQRBBCBCzASEBC0EIQQgQswEhA0EUQQgQswEhAkEQQQgQswEhBUEAQRBBCBCzAUECdGsiBkGAgHwgBSACIANqamtBd3FBA2siAyADIAZLGyABayAATQ0AIAFBECAAQQRqQRBBCBCzAUEFayAASxtBCBCzASIDakEQQQgQswFqQQRrEKYBIgJFDQAgAhDDASEAAkAgAUEBayIEIAJxRQRAIAAhAQwBCyACIARqQQAgAWtxEMMBIQJBEEEIELMBIQQgABC3ASACQQAgASACIABrIARLG2oiASAAayICayEEIAAQugFFBEAgASAEELsBIAAgAhC7ASAAIAIQpwEMAQsgACgCACEAIAEgBDYCBCABIAAgAmo2AgALIAEQugENASABELcBIgJBEEEIELMBIANqTQ0BIAEgAxDAASEAIAEgAxC7ASAAIAIgA2siAxC7ASAAIAMQpwEMAQsgBA8LIAEQwgEgARC6ARoL7SECD38BfiMAQRBrIgskAAJAAkAgAEH1AU8EQEEIQQgQswEhBkEUQQgQswEhBUEQQQgQswEhAUEAQRBBCBCzAUECdGsiAkGAgHwgASAFIAZqamtBd3FBA2siASABIAJLGyAATQ0CIABBBGpBCBCzASEEQdD8wAAoAgBFDQFBACAEayEDAkACQAJ/QQAgBEGAAkkNABpBHyAEQf///wdLDQAaIARB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Gg8LDwsgAkF4cUHU/MAAaiEBAn9BzPzAACgCACIDQQEgAkEDdnQiAnEEQCABKAIIDAELQcz8wAAgAiADcjYCACABCyEDIAEgADYCCCADIAA2AgwgACABNgIMIAAgAzYCCAtpACMAQTBrIgEkAEG0/MAALQAABEAgAUEcakEBNgIAIAFCAjcCDCABQcjXwAA2AgggAUHKADYCJCABIAA2AiwgASABQSBqNgIYIAEgAUEsajYCICABQQhqQfDXwAAQ1AEACyABQTBqJAAL3gEBA38jAEEgayIAJAACQEHI/MAAKAIAQf////8HcQRAQZCAwQAoAgANAQtBvPzAACgCAEG8/MAAQX82AgBFBEBBxPzAACgCACEBQcT8wABBuJvAADYCAEHA/MAAKAIAIQJBwPzAAEEBNgIAQbz8wABBADYCAAJAIAFFDQAgAiABKAIAEQYAIAFBBGooAgBFDQAgAUEIaigCABogAhCrAQsgAEEgaiQADwsACyAAQRxqQQA2AgAgAEH41sAANgIYIABCATcCDCAAQbTYwAA2AgggAEEIakHY2MAAENQBAAuLAgIEfwF+IwBBMGsiAiQAIAFBBGohBCABKAIERQRAIAEoAgAhAyACQRBqIgVBADYCACACQgE3AwggAiACQQhqNgIUIAJBKGogA0EQaikCADcDACACQSBqIANBCGopAgA3AwAgAiADKQIANwMYIAJBFGpB4NbAACACQRhqEN4BGiAEQQhqIAUoAgA2AgAgBCACKQMINwIACyACQSBqIgMgBEEIaigCADYCACABQQxqQQA2AgAgBCkCACEGIAFCATcCBCACIAY3AxhBDEEEED0iAUUEQEEMQQQQzgEACyABIAIpAxg3AgAgAUEIaiADKAIANgIAIABBiNnAADYCBCAAIAE2AgAgAkEwaiQAC60BAQN/IwBBMGsiAiQAIAFBBGohAyABKAIERQRAIAEoAgAhASACQRBqIgRBADYCACACQgE3AwggAiACQQhqNgIUIAJBKGogAUEQaikCADcDACACQSBqIAFBCGopAgA3AwAgAiABKQIANwMYIAJBFGpB4NbAACACQRhqEN4BGiADQQhqIAQoAgA2AgAgAyACKQMINwIACyAAQYjZwAA2AgQgACADNgIAIAJBMGokAAtFAQJ/IAEoAgQhAiABKAIAIQNBCEEEED0iAUUE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BnZBwAFyOgAMQQIMAgsgACgCCCIDIAAoAgRGBEAgACADEIMBIAAoAgghAwsgACADQQFqNgIIIAAoAgAgA2ogAToAAAwCCyABQYCABE8EQCACIAFBP3FBgAFyOgAPIAIgAUEGdkE/cUGAAXI6AA4gAiABQQx2QT9xQYABcjoADSACIAFBEnZBB3FB8AFyOgAMQQQMAQsgAiABQT9xQYABcjoADiACIAFBDHZB4AFyOgAMIAIgAUEGdkE/cUGAAXI6AA1BAwshASABIABBBGooAgAgACgCCCIDa0sEQCAAIAMgARCEASAAKAIIIQMLIAAoAgAgA2ogAkEMaiABEIsCGiAAIAEgA2o2AggLIAJBEGokAEEAC1oBAX8jAEEgayICJAAgAiAAKAIANgIEIAJBGGogAUEQaikCADcDACACQRBqIAFBCGopAgA3AwAgAiABKQIANwMIIAJBBGpB0NnAACACQQhqEN4BIAJBIGokAAtLAQF/IAIgACgCACIAQQRqKAIAIAAoAggiA2tLBEAgACADIAIQhAEgACgCCCEDCyAAKAIAIANqIAEgAhCLAhogACACIANqNgIIQQALGgAgACABQbj8wAAoAgAiAEHSACAAGxECAAALQAEBfyMAQSBrIgAkACAAQRxqQQA2AgAgAEH42cAANgIYIABCATcCDCAAQajawAA2AgggAEEIakGw2sAAENQBAAvpAwEGfyMAQTBrIgUkAAJAAkACQAJAAkAgASgCBCIDBEAgASgCACEHIANBAWtB/////wFxIgNBAWoiBkEHcSEEAn8gA0EHSQRAQQAhAyAHDAELIAdBPGohAiAGQfj///8DcSEGQQAhAwNAIAIoAgAgAkEIaygCACACQRBrKAIAIAJBGGsoAgAgAkEgaygCACACQShrKAIAIAJBMGsoAgAgAkE4aygCACADampqampqamohAyACQUBrIQIgBkEIayIGDQALIAJBPGsLIQIgBARAIAJBBGohAgNAIAIoAgAgA2ohAyACQQhqIQIgBEEBayIEDQALCyABQRRqKAIADQEgAyEEDAMLQQAhAyABQRRqKAIADQFBASECDAQLIAcoAgQNACADQRBJDQILIAMgA2oiBCADSQ0BCyAERQ0AAkAgBEF/SgRAIARBARA9IgJFDQEgBCEDDAMLEM8BAAsgBEEBEM4BAAtBASECQQAhAwsgAEEANgIIIAAgAzYCBCAAIAI2AgAgBSAANgIMIAVBIGogAUEQaikCADcDACAFQRhqIAFBCGopAgA3AwAgBSABKQIANwMQIAVBDGpB0NnAACAFQRBqEN4BBEBBwNrAAEEzIAVBKGpB9NrAAEGc28AAEOkBAAsgBUEwaiQAC2cBAn8gASgCACEDAkACQAJAIAFBCGooAgAiAUUEQEEBIQIMAQsgAUF/TA0BIAFBARA9IgJFDQILIAIgAyABEIsCIQIgACABNgIIIAAgATYCBCAAIAI2AgAPCxDPAQALIAFBARDOAQALUwEBfyMAQRBrIgIkACACIAA2AgggAiAAQQxqNgIMIAFBzNzAAEENQbDcwABBBSACQQhqQaDcwABBtdzAAEEFIAJBDGpBvNzAABD7ASACQRBqJAALDgAgACgCABoDQAwACwAL4QIBAn8jAEEgayICJAAgAkEBOgAYIAIgATYCFCACIAA2AhAgAkHQ38AANgIMIAJB3NzAADYCCCMAQRBrIgEkAAJAIAJBCGoiACgCDCICBEAgACgCCCIDRQ0BIAEgAjYCCCABIAA2AgQgASADNgIAIwBBEGsiACQAIABBCGogAUEIaigCADYCACAAIAEpAgA3AwAjAEEQayIBJAAgACgCACICQRRqKAIAIQMCQAJ/AkACQCACKAIEDgIAAQMLIAMNAkEAIQJB+NbAAAwBCyADDQEgAigCACIDKAIEIQIgAygCAAshAyABIAI2AgQgASADNgIAIAFBvNnAACAAKAIEIgEoAgggACgCCCABLQAQELIBAAsgAUEANgIEIAEgAjYCACABQajZwAAgACgCBCIBKAIIIAAoAgggAS0AEBCyAQALQfjWwABBK0H42MAAENkBAAtB+NbAAEErQejYwAAQ2QEAC28BAX8jAEEwayIDJAAgAyABNgIEIAMgADYCACADQRxqQQI2AgAgA0EsakHKADYCACADQgI3AgwgA0H83sAANgIIIANBygA2AiQgAyADQSBqNgIYIAMgAzYCKCADIANBBGo2AiAgA0EIaiACENQBAAtvAQF/IwBBMGsiAyQAIAMgATYCBCADIAA2AgAgA0EcakECNgIAIANBLGpBygA2AgAgA0ICNwIMIANBkOTAADYCCCADQcoANgIkIAMgA0EgajYCGCADIANBBGo2AiggAyADNgIgIANB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AAgAAAAUAAAAL1VzZXJzL2RlYXJrYW5lLy5jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL2Nvc213YXNtLXN0ZC0xLjEuOS9zcmMvZXhwb3J0cy5ycwAAAAABEABhAAAAjQAAAA0AAAAAARAAYQAAAG8AAAANAAAAAAEQAGEAAADqAAAADQAAAHdhc21jdXN0b21iYW5rQmFua01zZ2J1cm5zZW5kdG9fYWRkcmVzc1dhc21Nc2djbGVhcl9hZG1pbmNvbnRyYWN0X2FkZHJ1cGRhdGVfYWRtaW5hZG1pbm1pZ3JhdGVuZXdfY29kZV9pZG1zZ2luc3RhbnRpYXRlY29kZV9pZGxhYmVsZXhlY3V0ZVN1Yk1zZ2dhc19saW1pdFJlcGx5T25uZXZlcnN1Y2Nlc3NlcnJvcmFsd2F5c29rRW1wdHlFdmVudHR5cGVhdHRyaWJ1dGVzQXR0cmlidXRla2V5dmFsdWVSZXNwb25zZWV2ZW50c0NvbnRyYWN0VmVyc2lvbnZlcnNpb25jb250cmFjdF9pbmZvABUAAAAMAAAABAAAABYAAAAXAAAAGAAAAGEgRGlzcGxheSBpbXBsZW1lbnRhdGlvbiByZXR1cm5lZCBhbiBlcnJvciB1bmV4cGVjdGVkbHkABQAAAAAAAAABAAAAGQAAAC9ydXN0Yy84OTdlMzc1NTNiYmE4YjQyNzUxYzY3NjU4OTY3ODg5ZDExZWNkMTIwL2xpYnJhcnkvYWxsb2Mvc3JjL3N0cmluZy5ycwAIAxAASwAAAM4JAAAJAAAAY3dfY291bnRlcjo6bXNnOjpFeGVjdXRlTXNnY3dfY291bnRlcjo6bXNnOjpHZXRDb3VudFJlc3BvbnNlY3dfY291bnRlcjo6bXNnOjpRdWVyeU1zZ2Nvc213YXNtX3N0ZDo6cmVzdWx0czo6Y29udHJhY3RfcmVzdWx0OjpDb250cmFjdFJlc3VsdDxjb3Ntd2FzbV9zdGQ6OnJlc3VsdHM6OnJlc3BvbnNlOjpSZXNwb25zZT5jb3Ntd2FzbV9zdGQ6OnJlc3VsdHM6OmNvbnRyYWN0X3Jlc3VsdDo6Q29udHJhY3RSZXN1bHQ8Y29zbXdhc21fc3RkOjpiaW5hcnk6OkJpbmFyeT5jb3Ntd2FzbV9zdGQ6OnR5cGVzOjpNZXNzYWdlSW5mb2Nvc213YXNtX3N0ZDo6dHlwZXM6OkVudmN3X2NvdW50ZXI6OnN0YXRlOjpTdGF0ZWN3X2NvdW50ZXI6Om1zZzo6SW5zdGFudGlhdGVNc2djdzI6OkNvbnRyYWN0VmVyc2lvbgAAAAUAAAAEAAAABAAAABoAAAAbAAAAHAAAAG1pc3NpbmcgZmllbGQgYGAMBRAADwAAABsFEAABAAAAdW5rbm93biBmaWVsZCBgYCwgZXhwZWN0ZWQgACwFEAAPAAAAOwUQAAwAAABgLCB0aGVyZSBhcmUgbm8gZmllbGRzAAAsBRAADwAAAFgFEAAWAAAAZHVwbGljYXRlIGZpZWxkIGAAAACABRAAEQAAABsFEAABAAAAdW5rbm93biB2YXJpYW50IGAAAACkBRAAEQAAADsFEAAMAAAAaW52YWxpZCBVaW50NjQgJycgLSDIBRAAEAAAANgFEAAEAAAAaW52YWxpZCBVaW50MTI4ICcAAADsBRAAEQAAANgFEAAEAAAAdWxsc3RhdGVhY3Rpb25pbmNyZW1lbnRzcmMvY29udHJhY3QucnMAACcGEAAPAAAANAAAAA0AAAByZXNldGNyYXRlcy5pbzpjdy1jb3VudGVyMC4xLjBtZXRob2Rvd25lcmNvdW50VW5hdXRob3JpemVkAAB2BhAADAAAAAwFEAAAAAAAcQYQAAUAAAAeBhAACQAAAEgGEAAFAAAAZ2V0X2NvdW50AAAArAYQAAkAAABHZXRDb3VudFJlc3BvbnNlU3RhdGUvcnVzdGMvODk3ZTM3NTUzYmJhOGI0Mjc1MWM2NzY1ODk2Nzg4OWQxMWVjZDEyMC9saWJyYXJ5L2NvcmUvc3JjL2l0ZXIvYWRhcHRlcnMvZW51bWVyYXRlLnJz1QYQAFsAAAAwAAAACQAAAGF0dGVtcHQgdG8gYWRkIHdpdGggb3ZlcmZsb3cAAAAAYXR0ZW1wdCB0byBtdWx0aXBseSB3aXRoIG92ZXJmbG93AAAAKAAAAAgAAAAEAAAAKQAAACoAAAArAAAADAAAAAQAAAAsAAAALQAAAC4AAABhIERpc3BsYXkgaW1wbGVtZW50YXRpb24gcmV0dXJuZWQgYW4gZXJyb3IgdW5leHBlY3RlZGx5ACgAAAAAAAAAAQAAABkAAAAvcnVzdGMvODk3ZTM3NTUzYmJhOGI0Mjc1MWM2NzY1ODk2Nzg4OWQxMWVjZDEyMC9saWJyYXJ5L2FsbG9jL3NyYy9zdHJpbmcucnMA+AcQAEsAAADOCQAACQAAAGNvc213YXNtX3N0ZDo6cmVzdWx0czo6c3lzdGVtX3Jlc3VsdDo6U3lzdGVtUmVzdWx0PGNvc213YXNtX3N0ZDo6cmVzdWx0czo6Y29udHJhY3RfcmVzdWx0OjpDb250cmFjdFJlc3VsdDxjb3Ntd2FzbV9zdGQ6OmJpbmFyeTo6QmluYXJ5Pj4oAAAABAAAAAQAAAAvAAAAMAAAADEAAABpbnRlcm5hbCBlcnJvcjogZW50ZXJlZCB1bnJlYWNoYWJsZSBjb2RlOiAAAPQIEAAqAAAAL3J1c3RjLzg5N2UzNzU1M2JiYThiNDI3NTFjNjc2NTg5Njc4ODlkMTFlY2QxMjAvbGlicmFyeS9jb3JlL3NyYy9pdGVyL3RyYWl0cy9hY2N1bS5ycwAAACgJEABVAAAAjQAAAAEAAABtaXNzaW5nIGZpZWxkIGBgkAkQAA8AAACfCRAAAQAAAGR1cGxpY2F0ZSBmaWVsZCBgAAAAsAkQABEAAACfCRAAAQAAAHVua25vd24gdmFyaWFudCBgYCwgZXhwZWN0ZWQgAAAA1AkQABEAAADlCRAADAAAACgAAAAEAAAABAAAADIAAAAvVXNlcnMvZGVhcmthbmUvLmNhcmdvL3JlZ2lzdHJ5L3NyYy9naXRodWIuY29tLTFlY2M2Mjk5ZGI5ZWM4MjMvYmFzZTY0LTAuMTMuMC9zcmMvZGVjb2RlLnJzABQKEABbAAAAbgAAAC8AAABhdHRlbXB0IHRvIHN1YnRyYWN0IHdpdGggb3ZlcmZsb3cAAAAUChAAWwAAAAMBAAA3AAAAFAoQAFsAAAADAQAAJAAAABQKEABbAAAABAEAACkAAAAUChAAWwAAACEBAAARAAAAFAoQAFsAAAAqAQAAKQAAABQKEABbAAAAKgEAABYAAAAUChAAWwAAAC4BAAApAAAAFAoQAFsAAAAuAQAAKAAAABQKEABbAAAALQEAABoAAAAUChAAWwAAADMBAAARAAAAFAoQAFsAAABBAQAADgAAABQKEABbAAAARAEAACcAAAAUChAAWwAAAEQBAAASAAAAFAoQAFsAAABHAQAACQAAABQKEABbAAAAWAEAABMAAAAUChAAWwAAAGYBAAApAAAAFAoQAFsAAAB4AQAADQAAABQKEABbAAAAggEAABEAAAAUChAAWwAAAIoBAAAVAAAAFAoQAFsAAACOAQAAMQAAAEltcG9zc2libGU6IG11c3Qgb25seSBoYXZlIDAgdG8gOCBpbnB1dCBieXRlcyBpbiBsYXN0IGNodW5rLCB3aXRoIG5vIGludmFsaWQgbGVuZ3Roc+QLEABUAAAAFAoQAFsAAACdAQAADgAAABQKEABbAAAAqAEAAA0AAAAUChAAWwAAALEBAAAJAAAAT3ZlcmZsb3cgd2hlbiBjYWxjdWxhdGluZyBvdXRwdXQgYnVmZmVyIGxlbmd0aAAAFAoQAFsAAACTAAAAIAAAABQKEABbAAAAJwIAAAUAAABJbnZhbGlkIFVURjgrAAAAFAAAAAQAAAAzAAAAL1VzZXJzL2RlYXJrYW5lLy5jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL2Jhc2U2NC0wLjEzLjAvc3JjL2VuY29kZS5ycwDcDBAAWwAAADQAAAAFAAAAaW50ZWdlciBvdmVyZmxvdyB3aGVuIGNhbGN1bGF0aW5nIGJ1ZmZlciBzaXplAAAA3AwQAFsAAAAvAAAAEQAAACgAAAAIAAAABAAAADQAAAD0CBAAAAAAAGludmFsaWQgYmFzZTY0OiCgDRAAEAAAACgAAAAAAAAAAQAAADUAAAA2AAAANgAAAC9Vc2Vycy9kZWFya2FuZS8uY2FyZ28vcmVnaXN0cnkvc3JjL2dpdGh1Yi5jb20tMWVjYzYyOTlkYjllYzgyMy9jb3Ntd2FzbS1zdGQtMS4xLjkvc3JjL3NlY3Rpb25zLnJzAADQDRAAYgAAABoAAAAQAAAA0A0QAGIAAAAaAAAABQAAANANEABiAAAAOQAAABgAAABDYW5ub3QgcmVhZCBzZWN0aW9uIGxlbmd0aAAAZA4QABoAAADQDRAAYgAAADcAAAAJAAAAVEw7RFI6IFZhbHVlIG11c3Qgbm90IGJlIGVtcHR5IGluIFN0b3JhZ2U6OnNldCBidXQgaW4gbW9zdCBjYXNlcyB5b3UgY2FuIHVzZSBTdG9yYWdlOjpyZW1vdmUgaW5zdGVhZC4gTG9uZyBzdG9yeTogR2V0dGluZyBlbXB0eSB2YWx1ZXMgZnJvbSBzdG9yYWdlIGlzIG5vdCB3ZWxsIHN1cHBvcnRlZCBhdCB0aGUgbW9tZW50LiBTb21lIG9mIG91ciBpbnRlcm5hbCBpbnRlcmZhY2VzIGNhbm5vdCBkaWZmZXJlbnRpYXRlIGJldHdlZW4gYSBub24tZXhpc3RlbnQga2V5IGFuZCBhbiBlbXB0eSB2YWx1ZS4gUmlnaHQgbm93LCB5b3UgY2Fubm90IHJlbHkgb24gdGhlIGJlaGF2aW91ciBvZiBlbXB0eSB2YWx1ZXMuIFRvIHByb3RlY3QgeW91IGZyb20gdHJvdWJsZSBsYXRlciBvbiwgd2Ugc3RvcCBoZXJlLiBTb3JyeSBmb3IgdGhlIGluY29udmVuaWVuY2UhIFdlIGhpZ2hseSB3ZWxjb21lIHlvdSB0byBjb250cmlidXRlIHRvIENvc21XYXNtLCBtYWtpbmcgdGhpcyBtb3JlIHNvbGlkIG9uZSB3YXkgb3IgdGhlIG90aGVyLpgOEAAIAgAAL1VzZXJzL2RlYXJrYW5lLy5jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL2Nvc213YXNtLXN0ZC0xLjEuOS9zcmMvaW1wb3J0cy5ycwAAAKgQEABhAAAAawAAAA0AAAAoAAAABAAAAAQAAAA3AAAAOAAAADkAAAA6AAAAaW5wdXQgdG9vIGxvbmcgZm9yIGFkZHJfdmFsaWRhdGVhZGRyX3ZhbGlkYXRlIGVycm9yZWQ6IABYERAAFwAAAGlucHV0IHRvbyBsb25nIGZvciBhZGRyX2Nhbm9uaWNhbGl6ZWFkZHJfY2Fub25pY2FsaXplIGVycm9yZWQ6IACcERAAGwAAAGFkZHJfaHVtYW5pemUgZXJyb3JlZDogAMAREAAXAAAATWVzc2FnZVRvb0xvbmcgbXVzdCBub3QgaGFwcGVuLiBUaGlzIGlzIGEgYnVnIGluIHRoZSBWTS7gERAAOAAAAKgQEABhAAAACAEAABIAAACoEBAAYQAAACUBAAASAAAASW52YWxpZEhhc2hGb3JtYXQgbXVzdCBub3QgaGFwcGVuLiBUaGlzIGlzIGEgYnVnIGluIHRoZSBWTS4AQBIQADsAAACoEBAAYQAAAD8BAAASAAAARXJyb3IgY29kZSAyIHVudXNlZCBzaW5jZSBDb3NtV2FzbSAwLjE1LiBUaGlzIGlzIGEgYnVnIGluIHRoZSBWTS4AAACUEhAAQQAAAKgQEABhAAAAPgEAABIAAACoEBAAYQAAAF8BAAASAAAAqBAQAGEAAABeAQAAEgAAAFJlZ2lvbiBwb2ludGVyIGlzIG51bGwAABATEAAWAAAAL1VzZXJzL2RlYXJrYW5lLy5jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL2Nvc213YXNtLXN0ZC0xLjEuOS9zcmMvbWVtb3J5LnJzMBMQAGAAAAA5AAAABQAAAFJlZ2lvbiBzdGFydHMgYXQgbnVsbCBwb2ludGVyAAAAoBMQAB0AAAAwExAAYAAAAD8AAAAFAAAAVW5rbm93biBlcnJvcjogANgTEAAPAAAASW52YWxpZCByZWNvdmVyeSBwYXJhbWV0ZXIuIFN1cHBvcnRlZCB2YWx1ZXM6IDAgYW5kIDEuAADwExAANgAAAEludmFsaWQgc2lnbmF0dXJlIGZvcm1hdDAUEAAYAAAASW52YWxpZCBoYXNoIGZvcm1hdABQFBAAEwAAAFVua25vd25FcnJlcnJvcl9jb2RlKAAAAAQAAAAEAAAAOwAAAEludmFsaWRSZWNvdmVyeVBhcmFtSW52YWxpZFNpZ25hdHVyZUZvcm1hdEludmFsaWRIYXNoRm9ybWF0Q29udmVyc2lvbiBlcnJvcjogAAAAyxQQABIAAABEaXZpZGUgYnkgemVybzog6BQQABAAAABPdmVyZmxvdzogAAAAFRAACgAAAEVycm9yIHNlcmlhbGl6aW5nIHR5cGUgOiAAAAAUFRAAFwAAACsVEAACAAAARXJyb3IgcGFyc2luZyBpbnRvIHR5cGUgQBUQABgAAAArFRAAAgAAACBub3QgZm91bmQAAPQIEAAAAAAAaBUQAAoAAABDYW5ub3QgZGVjb2RlIFVURjggYnl0ZXMgaW50byBzdHJpbmc6IAAAhBUQACYAAABJbnZhbGlkIGhleCBzdHJpbmc6ILQVEAAUAAAASW52YWxpZCBkYXRhIHNpemU6IGV4cGVjdGVkPSBhY3R1YWw90BUQABwAAADsFRAACAAAAEludmFsaWQgQmFzZTY0IHN0cmluZzogAAQWEAAXAAAAR2VuZXJpYyBlcnJvcjogACQWEAAPAAAAUmVjb3ZlciBwdWJrZXkgZXJyb3I6IAAAPBYQABYAAABWZXJpZmljYXRpb24gZXJyb3I6IFwWEAAUAAAAQ29udmVyc2lvbk92ZXJmbG93c291cmNlKAAAAAQAAAAEAAAAPAAAAERpdmlkZUJ5WmVybygAAAAEAAAABAAAAD0AAABPdmVyZmxvdygAAAAEAAAABAAAAD4AAABTZXJpYWxpemVFcnJzb3VyY2VfdHlwZW1zZ1BhcnNlRXJydGFyZ2V0X3R5cGVOb3RGb3VuZGtpbmRJbnZhbGlkVXRmOEludmFsaWRIZXhJbnZhbGlkRGF0YVNpemVleHBlY3RlZAAAACgAAAAEAAAABAAAAD8AAABhY3R1YWxJbnZhbGlkQmFzZTY0R2VuZXJpY0VyclJlY292ZXJQdWJrZXlFcnIAAAAoAAAABAAAAAQAAABAAAAAVmVyaWZpY2F0aW9uRXJyACgAAAAEAAAABAAAAEEAAABTaGxTaHJQb3dNdWxTdWJBZGRDYW5ub3QgIHdpdGggIGFuZCC+FxAABwAAAMUXEAAGAAAAyxcQAAUAAABPdmVyZmxvd0Vycm9yb3BlcmF0aW9uAAAoAAAABAAAAAQAAAAdAAAAb3BlcmFuZDFvcGVyYW5kMkNvbnZlcnNpb25PdmVyZmxvd0Vycm9yACgAAAAEAAAABAAAAEIAAAB2YWx1ZUNhbm5vdCBkZXZpZGUgIGJ5IHplcm8ATRgQAA4AAABbGBAACAAAAERpdmlkZUJ5WmVyb0Vycm9yb3BlcmFuZGludmFsaWRfcmVxdWVzdGludmFsaWRfcmVzcG9uc2Vub19zdWNoX2NvbnRyYWN0dW5rbm93bnVuc3VwcG9ydGVkX3JlcXVlc3QAAACMGBAADwAAAJsYEAAQAAAAqxgQABAAAAC7GBAABwAAAMIYEAATAAAAYWRkcmVycm9ycmVzcG9uc2VyZXF1ZXN0SW52YWxpZCBwdWJsaWMga2V5IGZvcm1hdAAAABgZEAAZAAAAR2VuZXJpYyBlcnJvcgAAADwZEAANAAAAQmF0Y2ggZXJyb3IAVBkQAAsAAABJbnZhbGlkUHVia2V5Rm9ybWF0QmF0Y2hFcnJvawAAAIMZEAACAAAABBkQAAUAAAC7FxAAuBcQALUXEACyFxAArxcQAKwXEABFAAAACAAAAAQAAABGAAAARwAAAEUAAAAIAAAABAAAAEgAAADEGRAAAAAAAEpTT04gaGFzIGEgY29tbWEgYWZ0ZXIgdGhlIGxhc3QgdmFsdWUgaW4gYW4gYXJyYXkgb3IgbWFwLkpTT04gaGFzIG5vbi13aGl0ZXNwYWNlIHRyYWlsaW5nIGNoYXJhY3RlcnMgYWZ0ZXIgdGhlIHZhbHVlLkZvdW5kIGEgbG9uZSBzdXJyb2dhdGUsIHdoaWNoIGNhbiBleGlzdCBpbiBKU09OIGJ1dCBjYW5ub3QgYmUgZW5jb2RlZCB0byBVVEYtOC5PYmplY3Qga2V5IGlzIG5vdCBhIHN0cmluZy5JbnZhbGlkIHVuaWNvZGUgY29kZSBwb2ludC5JbnZhbGlkIHR5cGVJbnZhbGlkIG51bWJlci5JbnZhbGlkIGVzY2FwZSBzZXF1ZW5jZS5FeHBlY3RlZCB0aGlzIGNoYXJhY3RlciB0byBzdGFydCBhIEpTT04gdmFsdWUuRXhwZWN0ZWQgdG8gcGFyc2UgZWl0aGVyIGEgYHRydWVgLCBgZmFsc2VgLCBvciBhIGBudWxsYC5FeHBlY3RlZCB0aGlzIGNoYXJhY3RlciB0byBiZSBlaXRoZXIgYSBgJywnYCBvciBhIGAnfSdgLkV4cGVjdGVkIGEgbG93IHN1cnJvZ2F0ZSAoREMwMOKAk0RGRkYpLkV4cGVjdGVkIHRoaXMgY2hhcmFjdGVyIHRvIGJlIGVpdGhlciBhIGAnLCdgIG9yYSBgJ10nYC5FeHBlY3RlZCBhIGhpZ2ggc3Vycm9nYXRlIChEODAw4oCTREJGRikuRXhwZWN0ZWQgdGhpcyBjaGFyYWN0ZXIgdG8gYmUgYSBgJzonYC5FT0Ygd2hpbGUgcGFyc2luZyBhIEpTT04gdmFsdWUuRU9GIHdoaWxlIHBhcnNpbmcgYSBzdHJpbmcuRU9GIHdoaWxlIHBhcnNpbmcgYW4gb2JqZWN0LkVPRiB3aGlsZSBwYXJzaW5nIGEgbGlzdC5Db250cm9sIGNoYXJhY3RlciBmb3VuZCBpbiBzdHJpbmcuL1VzZXJzL2RlYXJrYW5lLy5jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL3NlcmRlLWpzb24td2FzbS0wLjQuMS9zcmMvZGUvdW5lc2NhcGUucnPkHBAAaAAAACUAAAAVAAAAAAAAAGF0dGVtcHQgdG8gYWRkIHdpdGggb3ZlcmZsb3fkHBAAaAAAADMAAAApAAAAAAAAAGF0dGVtcHQgdG8gc3VidHJhY3Qgd2l0aCBvdmVyZmxvd05vbi1oZXggQVNDSUkgY2hhcmFjdGVyIGZvdW5kAADkHBAAaAAAAJkAAAAOAAAAL1VzZXJzL2RlYXJrYW5lLy5jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL3NlcmRlLWpzb24td2FzbS0wLjQuMS9zcmMvZGUvbW9kLnJzAOAdEABjAAAAJAAAAAkAAADgHRAAYwAAAH0AAAAiAAAA4B0QAGMAAACBAAAALAAAAEJ1ZmZlciBpcyBmdWxsAAB0HhAADgAAAC9Vc2Vycy9kZWFya2FuZS8uY2FyZ28vcmVnaXN0cnkvc3JjL2dpdGh1Yi5jb20tMWVjYzYyOTlkYjllYzgyMy9zZXJkZS1qc29uLXdhc20tMC40LjEvc3JjL3Nlci9tb2QucnOMHhAAZAAAALUAAAAJAAAAjB4QAGQAAADXAAAACQAAAGludGVybmFsIGVycm9yOiBlbnRlcmVkIHVucmVhY2hhYmxlIGNvZGU6IAAAEB8QACoAQdC+wAALIWF0dGVtcHQgdG8gc3VidHJhY3Qgd2l0aCBvdmVyZmxvdwBBgL/AAAv0JmF0dGVtcHQgdG8gYWRkIHdpdGggb3ZlcmZsb3cvVXNlcnMvZGVhcmthbmUvLmNhcmdvL3JlZ2lzdHJ5L3NyYy9naXRodWIuY29tLTFlY2M2Mjk5ZGI5ZWM4MjMvYmFzZTY0LTAuMTMuMC9zcmMvZW5jb2RlLnJzAJwfEABbAAAAkgAAACcAAAB1c2l6ZSBvdmVyZmxvdyB3aGVuIGNhbGN1bGF0aW5nIGI2NCBsZW5ndGgAAJwfEABbAAAAlwAAABkAAACcHxAAWwAAALYAAAAgAAAAnB8QAFsAAAC3AAAAOgAAAJwfEABbAAAAtwAAACUAAACcHxAAWwAAAPcAAAAYAAAAnB8QAFsAAAD8AAAALwAAAJwfEABbAAAA/AAAABwAAACcHxAAWwAAAP0AAAA2AAAAnB8QAFsAAAD9AAAAIQAAAJwfEABbAAAAEwEAAC4AAACcHxAAWwAAABMBAAAJAAAAnB8QAFsAAAAUAQAACQAAAJwfEABbAAAACwEAAC4AAACcHxAAWwAAAAsBAAAJAAAAnB8QAFsAAAANAQAADwAAAJwfEABbAAAADAEAAAkAAACcHxAAWwAAAA8BAAAJAAAAnB8QAFsAAAARAQAACQAAAEltcG9zc2libGUgcmVtYWluZGVyVCEQABQAAACcHxAAWwAAACoBAAAWAAAAnB8QAFsAAAA7AQAACQAAAEludmFsaWQgbGFzdCBzeW1ib2wgLCBvZmZzZXQgLgAAkCEQABQAAACkIRAACQAAAK0hEAABAAAARW5jb2RlZCB0ZXh0IGNhbm5vdCBoYXZlIGEgNi1iaXQgcmVtYWluZGVyLgDIIRAAKwAAAEludmFsaWQgYnl0ZSAAAAD8IRAADQAAAKQhEAAJAAAArSEQAAEAAABPdmVyZmxvdyB3aGVuIGNhbGN1bGF0aW5nIG51bWJlciBvZiBjaHVua3MgaW4gaW5wdXQvVXNlcnMvZGVhcmthbmUvLmNhcmdvL3JlZ2lzdHJ5L3NyYy9naXRodWIuY29tLTFlY2M2Mjk5ZGI5ZWM4MjMvYmFzZTY0LTAuMTMuMC9zcmMvZGVjb2RlLnJzAABXIhAAWwAAALkAAAAFAAAAISIjJCUmJygpKissLTAxMjM0NTY3ODlAQUJDREVGR0hJSktMTU5QUVJTVFVWWFlaW2BhYmNkZWhpamtsbXBxckFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5KywuL0FCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5Li8wMTIzNDU2Nzg5QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5LV9BQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsv////////////////////////////////////////////AAECAwQFBgcICQoLDP//DQ4PEBESExQVFv///////xcYGRobHB0eHyAhIiMkJf8mJygpKiss/y0uLzD/////MTIzNDU2//83ODk6Ozz//z0+P/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8+P////zQ1Njc4OTo7PD3/////////AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBn///////8aGxwdHh8gISIjJCUmJygpKissLS4vMDEyM///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAE2Nzg5Ojs8PT4//////////wIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRob////////HB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDX//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wABAgMEBQYHCAkKC/////////8MDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJf///////yYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////z7//zQ1Njc4OTo7PD3/////////AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBn/////P/8aGxwdHh8gISIjJCUmJygpKissLS4vMDEyM///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////Pv///z80NTY3ODk6Ozw9/////////wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ////////GhscHR4fICEiIyQlJicoKSorLC0uLzAxMjP/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////BCQQAMQjEACEIxAARCMQAAQjEADEIhAARCkQAEQoEABEJxAARCYQAEQlEABEJBAATgAAAAgAAAAEAAAATwAAAFAAAABOAAAACAAAAAQAAABRAAAAYG9uZSBvZiCZKhAABwAAACwgAACoKhAAAgAAAJgqEAABAAAAmCoQAAEAAABgIG9yIGAAAJgqEAABAAAAxCoQAAYAAACYKhAAAQAAAC9Vc2Vycy9kZWFya2FuZS8uY2FyZ28vcmVnaXN0cnkvc3JjL2dpdGh1Yi5jb20tMWVjYzYyOTlkYjllYzgyMy9zZXJkZS0xLjAuMTUwL3NyYy9kZS9tb2QucnNleHBsaWNpdCBwYW5pYwAAAOQqEABbAAAA7QgAABIAAABTAAAABAAAAAQAAABUAAAAVQAAAFYAAABjYWxsZWQgYE9wdGlvbjo6dW53cmFwKClgIG9uIGEgYE5vbmVgIHZhbHVlbWVtb3J5IGFsbG9jYXRpb24gb2YgIGJ5dGVzIGZhaWxlZAoAAKMrEAAVAAAAuCsQAA4AAABsaWJyYXJ5L3N0ZC9zcmMvYWxsb2MucnPYKxAAGAAAAFUBAAAJAAAAY2Fubm90IG1vZGlmeSB0aGUgcGFuaWMgaG9vayBmcm9tIGEgcGFuaWNraW5nIHRocmVhZAAsEAA0AAAAbGlicmFyeS9zdGQvc3JjL3Bhbmlja2luZy5yczwsEAAcAAAAfQAAAAkAAAA8LBAAHAAAAEcCAAAPAAAAPCwQABwAAABGAgAADwAAAFcAAAAMAAAABAAAAFgAAABTAAAACAAAAAQAAABZAAAAWgAAABAAAAAEAAAAWwAAAFwAAABTAAAACAAAAAQAAABdAAAAXgAAAF8AAAAEAAAABAAAAGAAAABhAAAAYgAAAF8AAAAEAAAABAAAAGMAAABsaWJyYXJ5L2FsbG9jL3NyYy9yYXdfdmVjLnJzY2FwYWNpdHkgb3ZlcmZsb3cAAAAULRAAEQAAAPgsEAAcAAAABgIAAAUAAABhIGZvcm1hdHRpbmcgdHJhaXQgaW1wbGVtZW50YXRpb24gcmV0dXJuZWQgYW4gZXJyb3IAXwAAAAAAAAABAAAAGQAAAGxpYnJhcnkvYWxsb2Mvc3JjL2ZtdC5yc4QtEAAYAAAAZAIAAAkAAAApbGlicmFyeS9hbGxvYy9zcmMvdmVjL21vZC5ycykgc2hvdWxkIGJlIDw9IGxlbiAoaXMgYGF0YCBzcGxpdCBpbmRleCAoaXMgAAAA4C0QABUAAADJLRAAFwAAAKwtEAABAAAArS0QABwAAADLBwAADQAAAF8AAAAEAAAABAAAAGQAAABieXRlc2Vycm9yAABfAAAABAAAAAQAAABlAAAARnJvbVV0ZjhFcnJvcgAAAGNhbGxlZCBgT3B0aW9uOjp1bndyYXAoKWAgb24gYSBgTm9uZWAgdmFsdWVudW1iZXIgd291bGQgYmUgemVybyBmb3Igbm9uLXplcm8gdHlwZW51bWJlciB0b28gc21hbGwgdG8gZml0IGluIHRhcmdldCB0eXBlbnVtYmVyIHRvbyBsYXJnZSB0byBmaXQgaW4gdGFyZ2V0IHR5cGVpbnZhbGlkIGRpZ2l0IGZvdW5kIGluIHN0cmluZ2Nhbm5vdCBwYXJzZSBpbnRlZ2VyIGZyb20gZW1wdHkgc3RyaW5nKS4uAD0vEAACAAAAaW5kZXggb3V0IG9mIGJvdW5kczogdGhlIGxlbiBpcyAgYnV0IHRoZSBpbmRleCBpcyAAAEgvEAAgAAAAaC8QABIAAAA6AAAAXC4QAAAAAACMLxAAAQAAAIwvEAABAAAAcGFuaWNrZWQgYXQgJycsILQvEAABAAAAtS8QAAMAAABcLhAAAAAAAG0AAAAAAAAAAQAAAG4AAABgOiAAXC4QAAAAAADhLxAAAgAAAG0AAAAMAAAABAAAAG8AAABwAAAAcQAAACAgICAgewosCiwgIHsgfSB9KAooLApbAG0AAAAEAAAABAAAAHIAAABdbGlicmFyeS9jb3JlL3NyYy9mbXQvbnVtLnJzNTAQABsAAABlAAAAFAAAADB4MDAwMTAyMDMwNDA1MDYwNzA4MDkxMDExMTIxMzE0MTUxNjE3MTgxOTIwMjEyMjIzMjQyNTI2MjcyODI5MzAzMTMyMzMzNDM1MzYzNzM4Mzk0MDQxNDI0MzQ0NDU0NjQ3NDg0OTUwNTE1MjUzNTQ1NTU2NTc1ODU5NjA2MTYyNjM2NDY1NjY2NzY4Njk3MDcxNzI3Mzc0NzU3Njc3Nzg3OTgwODE4MjgzODQ4NTg2ODc4ODg5OTA5MTkyOTM5NDk1OTY5Nzk4OTlhc3NlcnRpb24gZmFpbGVkOiAqY3VyciA+IDE5AAA1MBAAGwAAAOUBAAAFAAAAbQAAAAQAAAAEAAAAcwAAAHQAAAB1AAAAbGlicmFyeS9jb3JlL3NyYy9mbXQvbW9kLnJzAHAxEAAbAAAAdAkAAB4AAABwMRAAGwAAAHsJAAAWAAAAbGlicmFyeS9jb3JlL3NyYy9zbGljZS9tZW1jaHIucnOsMRAAIAAAAGgAAAAnAAAAcmFuZ2Ugc3RhcnQgaW5kZXggIG91dCBvZiByYW5nZSBmb3Igc2xpY2Ugb2YgbGVuZ3RoINwxEAASAAAA7jEQACIAAAByYW5nZSBlbmQgaW5kZXggIDIQABAAAADuMRAA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"
}
{
"id": 290,
"creator": "inj1h3gepa4tszh66ee67he53jzmprsqc2l9npq3ty",
"data_hash": "F8E7689E23AC0C9D53F44A8FD98C686C20B0140A8D76D600E2C546BFBBA7758D",
"instantiate_permission": {
"permission": "Everybody"
},
"data": "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Qf8BcQshBgJAAkACQCAEIAZyIgZB/wFxIgVBAkcEQCAGQQFxDQEgC0UNAiADQfACakG5gcAAQQcQGCARRQ0KDAkLIAsNCiADQdACakG5gcAAQQcQFiADKALQAkEVRgRAIAMoAtwCIRQgAygC2AIhESADKALUAiELDAsLIANB+AJqIANB2AJqKQMANwMAIAMgAykD0AI3A/ACDAkLIANB0AJqIA4QjgECQCADKALQAiIPQRVHBEAgFyAYKQIANwIAIBdBCGogGEEIaigCADYCACADIA82AoADDAELIANBgANqIA4QFyADKAKAA0EVRg0CCyADQfgCaiADQYgDaikDADcDACADIAMpA4ADNwPwAgwGCyADQdACaiAOEI4BIAMoAtACIgRBFUcNAiADQdACaiAOEBogAygC3AIhFCADKALYAiERIAMoAtQCIQsgAygC0AIiBEEVRw0JCyADQbABaiAOEJABIAMtALEBIQQgAy0AsAFBAXENAAsMAgsgAygC3AIhFCADKALYAiERIAMoAtQCIQsMBgsgC0H/AXEhC0EEIQQMBQsgAyAJNgL8AiADIAQ2AvgCIAMgBTYC9AIgAyABNgLwAgsgC0UgEUVyDQELIAsQqwELIAMoAvwCIRQgAygC+AIhESADKAL0AiELIAMoAvACIgRBFUcNAQsgA0HQAmogCBCNASADKALQAiIEQRVGDQIgAygC3AIhFCADKALYAiADKALUAiEBIBEEQCALEKsBCyERIAEhCwsgAyAUNgKkAiADIBE2AqACIAMgCzYCnAIgAyAENgKYAgwJCyAhQiiIpyEKICFCIIinIRUgIachGyAJIRYLIANBCGogCBCQASADLQAJIQEgAy0ACEEBcQ0AC0ECIQQMAwtBACENDAMLIANBoAJqIANB2AJqKQMANwMAIAMgAykD0AI3A5gCIBZFDQUgDRCrAQwFCyADIBQ2AsgCIAMpA8gCISAgA0GYAmogA0GIAmoQjQEgAygCmAIiAUEVRwRAIAMtAJ8CQRB0IQkgAy8AnQIgAykDoAIhICADLQCcAiEMIBYEQCANEKsBCyAJciECIBFFDQYgCxCrAQwGCyADQZgCaiADQYgCahCLASADKAKYAiIBQRVHBEAgAy0AnwJBEHQhCSADLwCdAiADKQOgAiEgIAMtAJwCIQwgFgRAIA0QqwELIAlyIQIg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aigCACIENgIAIAMgCykCACIMNwMwIAlBCGogBDYCACAJIAw3AgAMAQsgA0EgaiAHEBcgAygCICIFQRVGDQELIAMoAiwhCSADKAIoIQggAy0AJCEEIAMvACUgAy0AJ0EQdHIMBgsgAyAHEJABIAMtAAEhBSADLQAAQQFxDQALCyAEQf8BcSEEQQIhBQwCCyAKQRU2AgAMAwsgAygCTCEJIAYhBAsgBEEIdgsiBjsABSAKIAk2AAwgCiAINgAIIAogBDoABCAKIAU2AgAgCkEHaiAGQRB2OgAACyADQdAAaiQAIAIoAlAiBEEVRw0KIAJB0ABqIAEQjQEgAigCUCIBQRVGBEAgAEEVNgIADAwLIAJByABqIAJB3ABqKAIAIgQ2AgAgAiACKQJUIgw3A0AgAEEMaiAENgIAIAAgDDcCBCAAIAE2AgAMCwsgAEELNgIADAoLIABBFTYCAAwJCyAAQQA7AAUgAEEENgIAIABBB2pBADoAAAwICyAAQQ42AgAMBwsgAikCVCEMIAAgAigCXDYCDCAAIAw3AgQgACABNgIADAYLIABBADsABSAAQQQ2AgAgAEEHakEAOgAADAULIABBDjYCAAwECyACQcgAaiACQdwAaigCACIBNgIAIAIgAikCVCIMNwNAIABBDGogATYCACAAIAw3AgQgACAENgIADAMLIABBADsABSAAQQQ2AgAgAEEHakEAOgAADAILIABBDjYCAAwBCyACQcgAaiACQdwAaigCACIBNgIAIAIgAikCVCIMNwNAIABBDGogATYCACAAIAw3AgQgACAENgIACyACQeAAaiQAC8UBAQF/IwBB8ABrIgMkACADIAI2AgwgAyABNgIIIANBJGpBATYCACADQgI3AhQgA0GUi8AANgIQIANBATYCLCADIANBKGo2AiAgAyADQQhqNgIoIANBADYCOCADQgE3AzAgA0FAayIBIANBMGpBqIXAABDyASADQRBqIAEQ6AEEQEHAhcAAQTcgA0HoAGpB+IXAAEHUhsAAEOkBAAsgACADKQMwNwIEIABBFDYCACAAQQxqIANBOGooAgA2AgAgA0HwAGokAAuFBAIFfwJ+IwBB4ABrIgMkACADIAI2AgwgAyABNgIIIwBBEGsiBiQAIANBEGoiBAJ/AkACQCACRQRAIARBADoAAQwBCwJAAkACQCABLQAAQStrDgMBAgACCyACQQFGDQMMAQsgAkEBayICRQ0CIAFBAWohAQsCQAJAAkAgAkERTwRAA0AgBiAIQgBCChCMAiABLQAAQTBrIgVBCUsNBiAGKQMIQgBSDQQgBikDACIJIAUgByAFQQpJG618IgggCVQNAyABQQFqIQEgBSEHIAJBAWsiAg0ACwwBCwNAIAEtAABBMGsiBUEJSw0FIAFBAWohASAFrSAIQgp+fCEIIAJBAWsiAg0ACwsgBCAINwMIQQAMBAsgBEECOgABDAELIARBAjoAAQtBAQwBCyAEQQE6AAFBAQs6AAAgBkEQaiQAAkAgAy0AEEUEQCAAIAMpAxg3AwggAEEVNgIADAELIAMgAy0AEToAJyADQcQAakECNgIAIANBATYCPCADIANBJ2o2AkAgAyADQQhqNgI4IANBAjYCXCADQgI3AkwgA0Hci8AANgJIIAMgA0E4ajYCWCADQShqIgEgA0HIAGoiAhDQASACQQRyIAEQ0QEgA0EUNgJIIAMoAiwEQCADKAIoEKsBCyAAIAMpA0g3AgAgAEEIaiADQdAAaikDADcCAAsgA0HgAGokAAvFAgIEfwF+IwBBIGsiAiQAIAJBCGogARCQAQJAAkACQAJAAkAgAi0ACEEBcQRAIAItAAlBIkcNASABEIoBIAJBEGogARCPASACKAIQIgFBFUcNAiACQRxqKAIAIQEgAkEYaigCACEDIAIoAhQiBEUEQAJAIAFFBEBBASEEDAELIAFBf0oiBUUNBSABIAUQPSIERQ0GCyAEIAMgARCLAiEDIABBDGogATYCACAAQQhqIAE2AgAgACADNgIEIABBFTYCAAwGCyAAIAQ2AgQgAEEVNgIAIABBDGogATYCACAAQQhqIAM2AgAMBQsgAEEAOwAFIABBBDYCACAAQQdqQQA6AAAMBAsgAEEONgIADAMLIAIpAhQhBiAAIAIoAhw2AgwgACAGNwIEIAAgATYCAAwCCxDPAQALIAEgBRDOAQALIAJBIGokAAv3AQEDfyMAQUBqIgQkAAJAAkACQAJAIAJFBEBBASEFDAELIAJBf0oiBkUNASACIAYQPSIFRQ0CCyAFIAEgAhCLAiEBIARBADYCCCAEQgE3AwAgBEEQaiIFIARBqIXAABDyASADIAUQhwENAiAAQQxqIAI2AgAgAEEIaiACNgIAIAAgATYCBCAAIAQpAwA3AhAgAEEINgIAIABBGGogBEEIaigCADYCAAJAIAMoAgBBFEkNACADQQhqKAIARQ0AIAMoAgQQqwELIARBQGskAA8LEM8BAAsgAiAGEM4BAAtBwIXAAEE3IARBOGpB+IXAAEHUhsAAEOkBAAvwIwIbfwN+IwBBkAJrIgMkACADQZABaiIHIAEgAhCJASADQYgBaiAHEJABQQAhAgJAAkACQCADLQCIAUEBcUUEQEEEIQEMAQsgAy0AiQFB+wBHBEBBDiEBDAELIANBkAFqIgEQigEgA0GAAWogARCIASADLQCEASEEIANB+ABqIAMoAoABIgwQkAECQAJAAkACQAJAIAMtAHhBAXFFBEBBAiECDAELIAMtAHkhAiAEQQFxIRcgA0HoAWpBBHIhESADQYACakEEciEUIANB8AFqIRggA0HUAWohHCADQfMBaiEdA0ACfwJAAkACfwJAIAJB/wFxIgRBLEcEQCAEQf0ARwRAIBcNAkEJDAMLIA1BgH5xIQJBAwwFC0EQIBcNARogDBCKASADQfAAaiAMEJABIAMtAHBBAXFFDQIgAy0AcSECCyACQf8BcSIEQSJGDQJBECAEQf0ARw0AGkETCyECIA0hCwwECyANQf8BcSELQQQhAgwDCyADQegAaiAMEJABIAMtAGhBAXFFBEBBBCECQQAhCwwDCyADLQBpQSJHBEBBDiECDAMLIAwQigEgA0HIAWogDBCPASADKALUASEFIAMoAtABIQQgAygCzAEhCyADKALIASICQRVHDQICQCALRQRAQQIhAgJAAkAgBUEFaw4CAQADCyAEQa6BwABBBhCNAkEAR0EBdCECDAILQQJBASAEQbSBwABBBRCNAhshAgwBC0ECIQICQAJAAkAgBUEFaw4CAQACCyALQa6BwABBBhCNAkEAR0EBdCECDAELQQJBASALQbSBwABBBRCNAhshAgsgBEUNACALEKsBC0EAIRcgDUGAfnELIQQCQAJAAkACQAJAAkACQCACIARyIg1B/wFxIgtBA0cEQCALDgIDAgELIBkhDQJAIBIiB0UEQCADQcgBakGugcAAQQYQFiADKALIAUEVRw0BIANB1AFqKAIAIRUgAygCzAEhByADQdABaigCACENCwJAIAZFBEAgA0HIAWpBtIHAAEEFEBYgAygCyAFBFUcNASADQdABaigCACEJIAMoAswBIQYgA0HUAWooAgAhCAsgAyAJNgKwASADIAY2AqwBIAMgFTYCqAEgAyANNgKkASADIAc2AqABIAdFDQ4gA0HIAWogA0GQAWoQjQEgAygCyAEiAUEVRg0FIAMoAswBIQsgAygC1AEhBCADKALQASEFIA0EQCAHEKsBCyAIBEAgCEEFdCEHIAZBEGohAgNAIAJBBGooAgAEQCACKAIAEKsBCyACQSBqIQIgB0EgayIHDQALCyALQQh2IQIgCUUNDyAGEKsBDA8LIBJFIQIgA0GsAWogA0HQAWopAwA3AgAgAyADKQPIATcCpAEgDUUNDCAHEKsBDAwLIANBrAFqIANB0AFqKQMANwIAIAMgAykDyAE3AqQBQQAhEiAGDQkMCgsgA0HIAWogDBCOAQJAIAMoAsgBIgFBFUcEQCADQfQBaiADQdQBaigCADYCACADIAMpAswBNwLsASADIAE2AugBDAELIANB6AFqIAwQFyADKALoAUEVRg0GCyADQawBaiADQfABaikDADcCACADIAMpA+gBNwKkASADQQA2AqABIAYNCAwJCyAGRQ0DIANBoAFqQQRyQbSBwABBBRAYIANBADYCoAEMBwsgEkUNASADQaABakEEckGugcAAQQYQGCADQQA2AqABIAYNBgwHCyADQcgBaiADQZABahCLASADKALIASIBQRVHBEAgAygC1AEhBCADKALQASEFIAMoAswBIQIgDQRAIAcQqwELIAgEQCAIQQV0IQcgBkEQaiELA0AgC0EEaigCAARAIAsoAgAQqwELIAtBIGohCyAHQSBrIgcNAAsLIAlFDQsgBhCrAQwLCyAAQRhqIAg2AgAgAEEUaiAJNgIAIABBEGogBjYCACAAQQxqIBU2AgAgAEEIaiANNgIAIAAgBzYCBCAAQQ02AgAMCwsgA0HIAWogDBCOAQJ/IAMoAsgBIgJBFUYEQCADQcgBaiAMEBogAygC1AEhFSADKALMASESIAMoAtABIgQgAygCyAEiAkEVRw0BGiAEIRkMAwsgAygC1AEhFSADKALMASESIAMoAtABCyEBIANBsAFqIBU2AgAgA0GsAWogATYCACADQagBaiASNgIAIAMgAjYCpAFBACESIANBADYCoAEgBg0EDAULIANByAFqIAwQjgECQAJAAkACQAJAAkACQAJAAkAgAygC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IAMgCEEBaiIINgLAASADQQhqIBAQkAEgAy0ACSECIAMtAAhBAXENCEEAIQYMEAsgA0EONgLsAQwECyADIA82AvgBIAMgCjYC9AEgAyAFNgLwASADIBY2AuwBDAMLIBggFCkCADcCACAYQQhqIBRBCGooAgA2AgAgAyAFNgLsAQwCCyADQcgBakGlgMAAQQYQGCADQQA2AtgBQQEhAgwJCyADQegBaiAOEI4BAkACQCADKALoASIFQRVHBEAgFCARKQIANwIAIBRBCGogEUEIaigCADYCACADIAU2AoACDAELIANBgAJqIA4QGiADKAKAAkEVRg0BCyADQdABaiADQYgCaikDADcDACADIAMpA4ACNwPIAQwKCyADKAKMAiEbIAMoAogCIRogAygChAIhAQwBCyADQdABaiARQQhqKQIANwMAIANBADYC2AEgAyARKQIANwPIAUEBIQIMBwsgA0EQaiAOEJABIAMtABEhBSADLQAQQQFxDQALCwwDCyAGQf8BcSEGQQQhCgwJCyADKALUASEIIAMoAtABIQkgAygCzAEhBgwICyADKAK8ASEJIAMoArgBIQYMBgsgAyAKNgLUASADIAk2AtABIAMgBDYCzAEgAyACNgLIAUEBIQILIBpFIAFFIAJFcnINACABEKsBCyADKQPIASIeQiCIpyEGIANB0AFqKQMAIh9CIIinIRAgHqchCiAfpyEJDAELQQAhBkEAIRALIAMoArgBIQcgCARAIAhBBXQhAUEAIQIDQCACIAdqIgRBFGooAgAiBQRAIARBEGooAgAQqwELIAEgAkEgaiICRw0ACwsgECEICyADKAK8AQRAIAcQqwELIApBFUcNAQsgA0HIAWogDBCMASADKALIASIKQRVGDQEgAygC1AEgAygC0AEhDSADKALMASAIBEAgCEEFdCEBIAZBEGohAgNAIAJBBGooAgAEQCACKAIAEKsBCyACQSBqIQIgAUEgayIBDQALCyAJBEAgBhCrAQshBiEIIA0hCQsgA0GwAWogCDYCACADQawBaiAJNgIAIANBqAFqIAY2AgAgAyAKNgKkAQwECyADIAwQkAEgAy0AASECIAMtAABBAXENAAtBAiECCyADQbABaiAFNgIAIANBrAFqIAQ2AgAgA0GoAWogCzYCACADIAI2AqQBIAZFDQELIAgEQCAIQQV0IQEg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A2pB+wA6AAAgAkHQAWogBEGYg8AAQQYQlwECQAJAIAIoAtABRQRAIAQoAggiAyAHKAIARgRAIAQgAxAQIAQoAgghAwsgBCADQQFqNgIIIAQoAgAgA2pBOjoAACACQdABaiAEEJsBIAIoAtABRQ0BIAJBzAFqIAVBCGooAgA2AgAgAiAFKQIANwLEAQwCCyACQZABaiACQdwBaigCADYCACACIAIpAtQBNwOIAQwSCyACQcABaiACKALUASACLQDYARCTASACKALAAUUNAwsgAkGQAWogAkHMAWooAgA2AgAgAiACKQLEATcDiAEMEAsgBygCACADRgRAIAQgAxAQIAQoAgghAwsgBCADQQFqNgIIIAQoAgAgA2pB+wA6AAAgAkHQAWogBEGUg8AAQQQQlwEgAigC0AENBCAEKAIIIgMgBygCAEYEQCAEIAMQECAEKAIIIQMLIAQgA0EBajYCCCAEKAIAIANqQTo6AAACQAJAAkACQAJAIAlBAWsOBAMCAQAECyACQdABaiAEQcKDwABBCxCcASACKALQAQ0HIAIgAi0A2AE6AKQBIAIgAigC1AE2AqABIAJB0AFqIAJBoAFqQc2DwABBDSAIQRRrKAIAIAhBDGsoAgAQDyACKALQAUUEQCACQcABaiACKAKgASACLQCkARCUAQwPCyAGIAUpAgA3AgAgBkEIaiAFQQhqKAIANgIADAsLIAJB0AFqIARB2oPAAEEMEJwBIAIoAtABBEAgBiAFKQIANwIAIAZBCGogBUEIaigCADYCAAwLCyACIAItANgBOgCkASACIAIoAtQBNgKgASACQdABaiACQaABakHNg8AAQQ0gCEEUaygCACAIQQxrKAIAEA8gAigC0AEEQCAGIAUpAgA3AgAgBkEIaiAFQQhqKAIANgIADAsLIAJB0AFqIAJBoAFqQeaDwABBBSAIQQhrKAIAIAgoAgAQDyACKALQAUUNDCAGIAUpAgA3AgAgBkEIaiAFQQhqKAIANgIADAoLIAJB0AFqIARB64PAAEEHEJwBIAIoAtABBEAgBiAFKQIANwIAIAZBCGogBUEIaigCADYCAAwKCyACIAItANgBOgCkASACIAIoAtQBNgKgASACQdABaiACQaABakHNg8AAQQ0gCEEUaygCACAIQQxrKAIAEA8gAigC0AEEQCAGIAUpAgA3AgAgBkEIaiAFQQhqKAIANgIADAoLIAJB0AFqIAJBoAFqQfKDwABBCyAIQQhqKQMAEBIgAigC0AEEQCAGIAUpAgA3AgAgBkEIaiAFQQhqKAIANgIADAoLIAJB0AFqIAJBoAFqIAhBCGsQEyACKALQAUUNCiAGIAUpAgA3AgAgBkEIaiAFQQhqKAIANgIADAkLIAJB0AFqIARBgITAAEELEJwBIAIoAtABRQ0HIAYgBSkCADcCACAGQQhqIAVBCGooAgA2AgAMCAsgAkHQAWogBEGXhMAAQQcQnAEgAigC0AEEQCAGIAUpAgA3AgAgBkEIaiAFQQhqKAIANgIADAgLIAIgAi0A2AE6AKQBIAIgAigC1AE2AqABIAJB0AFqIAJBoAFqQc2DwABBDSAIQRRrKAIAIAhBDGsoAgAQDyACKALQAQRAIAYgBSkCADcCACAGQQhqIAVBCGooAgA2AgAMCAsgAkHQAWogAkGgAWogCEEIaxATIAIoAtABBEAgBiAFKQIANwIAIAZBCGogBUEIaigCADYCAAwICyACQdABaiACQaABakG0gcAAQQUgCEEEaigCACAIQQxqKAIAEBQgAigC0AFFDQUgBiAFKQIANwIAIAZBCGogBUEIaigCADYCAAwHCyACQbwBaiACQdwBaigCADYCACACIAIpAtQBNwK0AQwaCyAEKAIIIgMgBygCAEYNCwwMCyACQZABaiACQdwBaigCADYCACACIAIpAtQBNwOIAQwMCyAGIAUpAgA3AgAgBkEIaiAFQQhqKAIANgIADAMLIAJBkAFqIAJB3AFqKAIANgIAIAIgAikC1AE3A4gBDAoLIAJBwAFqIAIoAqABIAItAKQBEJQBDAQLIAIgAigC1AEiAzYCmAEgCEEMaygCACEPIAhBFGsoAgAhDQJAIAItANgBBEAgAygCCCEJDAELIAMoAggiCiADKAIERgRAIAMgChAQIAMoAgghCgsgAyAKQQFqIgk2AgggAygCACAKakEsOgAACyACQQA6AJwBIANBBGoiCigCACAJRgRAIAMgCRAQIAMoAgghCQsgAygCACAJakEiOgAAIAMgCUEBaiIJNgIIIAooAgAgCWtBBE0EQCADIAlBBRARIAMoAgghCQsgAygCACAJaiIQQeaDwAAoAAA2AAAgEEEEakHqg8AALQAAOgAAIAMgCUEFaiIJNgIIIAooAgAgCWtBAU0EQCADIAlBAhARIAMoAgghCQsgAygCACAJakGi9AA7AAAgAyAJQQJqNgIIAkAgDUUEQCACQdABaiADEJgBDAELIAJB0AFqIAMgDSAPEJcBCwJAAkACQAJAIAIoAtABRQRAIAJB0AFqIAJBmAFqQYuEwABBByAIQSBqKQMAEBIgAigC0AENASACQdABaiACQZgBaiAIQQhrEBMgAigC0AENAiACQdABaiACQZgBakG0gcAAQQUgCEEEaigCACAIQQxqKAIAEBQgAigC0AENAyACQdABaiACQZgBakGShMAAQQUgCEEQaigCACAIQRhqKAIAEA8gAigC0AENBCACQcABaiACKAKYASACLQCcARCUAQwICyACQagBaiAFQQhqKAIAIgM2AgAgAiAFKQIAIhE3A6ABIAZBCGogAzYCACAGIBE3AgAMBAsgBiAFKQIANwIAIAZBCGogBUEIaigCADYCAAwDCyAGIAUpAgA3AgAgBkEIaiAFQQhqKAIANgIADAILIAYgBSkCADcCACAGQQhqIAVBCGooAgA2AgAMAQsgBiAFKQIANwIAIAZBCGogBUEIaigCADYCAAsgAkEBNgLAAQwCCyACQcABaiACKAKgASACLQCkARCUAQwBCyACQcABaiACKAKgASACLQCkARCUAQsgAigCwAFFBEAgBCgCCCIDIAcoAgBHDQQMAwsgAkGQAWogBkEIaigCADYCACACIAYpAgA3A4gBDAQLIAYgBSkCADcCACAGQQhqIAVBCGooAgA2AgAgAkEBNgLAAQsgAigCwAFFBEAgBCgCCCIDIAcoAgBGDQEMAgsgAkGQAWogBkEIaigCADYCACACIAYpAgA3A4gBDAILIAQgAxAQIAQoAgghAwsgBCgCACADakH9ADoAACAEIANBAWoiAzYCCCAMQdAAaikDACERIAxByABqKQMAIRIgAyAHKAIARw0BIAQgAxAQIAQoAgghAwwBCyACQbwBaiACQZABaigCADYCACACIAIpA4gBNwK0AQwLCyAEKAIAIANqQSw6AAAgBCADQQFqIgM2AgggBygCACADRgRAIAQgAxAQIAQoAgghAwsgBCgCACADakEiOgAAIAQgA0EBaiIDNgIIIAcoAgAgA2tBCE0EQCAEIANBCRARIAQoAgghAwsgBCgCACADaiIJQaSEwAApAAA3AAAgCUEIakGshMAALQAAOgAAIAQgA0EJaiIDNgIIIAcoAgAgA2tBAU0EQCAEIANBAhARIAQoAgghAwsgBCgCACADakGi9AA7AAAgBCADQQJqNgIIAkAgElAEQCACQdABaiAEEJgBDAELIAJB0AFqIAQgERCWAQsgAigC0AENAiAMQdgAai0AACEJIAQoAggiAyAHKAIARgRAIAQgAxAQIAQoAgghAwsgBCgCACADakEsOgAAIAQgA0EBaiIDNgIIIAcoAgAgA0YEQCAEIAMQECAEKAIIIQMLIAQoAgAgA2pBIjoAACAEIANBAWoiAzYCCCAHKAIAIANrQQdNBEAgBCADQQgQESAEKAIIIQMLIAQoAgAgA2pC8srB45bv17fuADcAACAEIANBCGoiAzYCCCAHKAIAIANrQQFNBEAgBCADQQIQESAEKAIIIQMLIAQoAgAgA2pBovQAOwAAIAQgA0ECajYCCAJAAkACQAJAAkAgCUEBaw4DAQIDAAsgAkHQAWogBEHFhMAAQQYQmQEMAwsgAkHQAWogBEHAhMAAQQUQmQEMAgsgAkHQAWogBEG5hMAAQQcQmQEMAQsgAkHQAWogBEG0hMAAQQUQmQELIAIoAtABBEAgAkG8AWogAkHcAWooAgA2AgAgAiACKQLUATcCtAEMCwsgAkGwAWogBEEAEJMBIAIoArABDQogCEHgAGohCEEBIQMgDEHgAGogDkcNAAtBAAUgAwtB/wFxQQBHEJIBIAIoAlgNCSACQdABaiACQUBrIAFBDGooAgAgAUEUaigCABAgIAIoAtABBEAgAkE8aiACQdwBaigCADYCACACIAIpAtQBNwI0DAsLIAFBIGooAgAhBiABQRhqKAIAIQcgAigCQCEEIAItAEQEQCAEKAIIIQMMAgsgBCgCCCIFIAQoAgRGBEAgBCAFEBAgBCgCCCEFCyAEIAVBAWoiAzYCCCAEKAIAIAVqQSw6AAAMAQsgAkG8AWogAkHcAWooAgA2AgAgAiACKQLUATcCtAEMBwsgAkEAOgBEIARBBGoiBSgCACADRgRAIAQgAxAQIAQoAgghAwsgBCgCACADakEiOgAAIAQgA0EBaiIDNgIIIAUoAgAgA2tBBU0EQCAEIANBBhARIAQoAgghAwsgBCgCACADaiIFQf6EwAAoAAA2AAAgBUEEakGChcAALwAAOwAAIAQgA0EGaiIDNgIIIARBBGooAgAgA2tBAU0EQCAEIANBAhARIAQoAgghAwsgBCgCACADakGi9AA7AAAgBCADQQJqNgIIIAJB0AFqIAQQmgEgAigC0AENAiACQdgBai0AACEDAkACQAJAIAJBsAFqIAIoAtQBIgUgBgR/IAcgBkEYbGohCCADRSEDIAJB0AFqQQRyIQYDQCADQQFxBEAgBSgCCCIDIAUoAgRGBEAgBSADEBAgBSgCCCEDCyAFIANBAWo2AgggBSgCACADakEsOgAACyACQdABaiAFEJsBIAIoAtABDQIgAiACLQDYAToAjAEgAiACKALUATYCiAEgAkHQAWogAkGIAWpB14TAAEEEIAcoAgAgB0EIaigCABAPIAIoAtABDQYgAkHQAWogAkGIAWogB0EMaigCACAHQRRqKAIAECAgAigC0AEEQCACQcwBaiACQdwBaigCADYCACACIAIpAtQBNwLEAQwJCyACQcABaiACKAKIASACLQCMARCTASACKALAAQ0IQQEhAyAHQRhqIgcgCEcNAAtBAAUgAwtB/wFxQQBHEJIBIAIoArABDQcgBCgCCCIHIARBBGoiAygCAEYEQCAEIAcQECAEKAIIIQcLIAQoAgAgB2pBLDoAACAEIAdBAWoiBzYCCCACQQA6AEQgAygCACAHRgRAIAQgBxAQIAQoAgghBwsgBCgCACAHakEiOgAAIAQgB0EBaiIHNgIIIAFBJGohAyAEQQRqIgUoAgAgB2tBA00EQCAEIAdBBBARIAQoAgghBwsgBCgCACAHakHkwtGLBjYAACAEIAdBBGoiATYCCCAFKAIAIAFrQQFNBEAgBCABQQIQESAEKAIIIQELIAQoAgAgAWpBovQAOwAAIAQgAUECajYCCCADKAIADQEgAkHQAWogBBCYAQwCCyACQcwBaiAGQQhqKAIANgIAIAIgBikCADcCxAEMBQsgAkHAAWogAxBqIAJB0AFqIAQgAigCwAEiASACKALIARCXASACKALEAUUNACABEKsBCyACKALQAQRAIAJBPGogAkHcAWooAgA2AgAgAiACKQLUATcCNAwJCyACQTBqIARBABCTASACKAIwDQggAigCCCIDIAIoAgRGBEAgAiADEBAgAigCCCEDCyACKAIAIANqQf0AOgAAIAIgA0EBajYCCAsgAkHIAWogAkEIaigCACIBNgIAIAIgAikDACIRNwPAASAAQQxqIAE2AgAgACARNwIEIABBDTYCAAwJCyACQcwBaiACQdwBaigCADYCACACIAIpAtQBNwLEAQwBCyACQbwBaiACQdwBaigCADYCACACIAIpAtQBNwK0AQwBCyACQbwBaiACQcwBaigCADYCACACIAIpAsQBNwK0AQsgAkE8aiACQbwBaigCADYCACACIAIpArQBNwI0DAMLIAJB5ABqIAJB3AFqKAIANgIAIAIgAikC1AE3AlwMAQsgAkHkAGogAkG8AWooAgA2AgAgAiACKQK0ATcCXAsgAkE8aiACQeQAaigCADYCACACIAIpAlw3AjQLIAJBHGogAkE8aigCADYCACACIAIpAjQ3AhQLIAJByAFqIgEgAkEcaigCADYCACACIAIpAhQ3A8ABIAIoAgQEQCACKAIAEKsBCyACQdgBaiABKAIANgIAIAIgAikDwAE3A9ABIABBuYfAAEHhACACQdABahAhCyACQeABaiQAC+ACAgJ/AX4jAEEgayIFJAAgASgCCCIEIAEoAgRGBEAgASAEEBAgASgCCCEECyABIARBAWo2AgggASgCACAEakH7ADoAACAFQRBqIAFBwITAAEEFEJcBAkACQCAFKAIQRQRAIAEoAggiBCABKAIERgRAIAEgBBAQIAEoAgghBAsgASAEQQFqNgIIIAEoAgAgBGpBOjoAACAFQRBqIAEgAiADEJcBIAUoAhANASABKAIIIgQgASgCBEYEQCABIAQQECABKAIIIQQLIABBADYCACABIARBAWo2AgggASgCACAEakH9ADoAAAwCCyAFQQhqIAVBHGooAgAiATYCACAFIAUpAhQiBjcDACAAQQxqIAE2AgAgACAGNwIEIABBATYCAAwBCyAFQQhqIAVBHGooAgAiATYCACAFIAUpAhQiBjcDACAAQQxqIAE2AgAgACAGNwIEIABBATYCAAsgBUEgaiQAC9QGAgR/AX4jAEHgAGsiBCQAIAEoAgAhBgJAIAEtAAQEQCAGKAIIIQUMAQsgBigCCCIHIAYoAgRGBEAgBiAHEBAgBigCCCEHCyAGIAdBAWoiBTYCCCAGKAIAIAdqQSw6AAALIAFBADoABCAGQQRqIgEoAgAgBUYEQCAGIAUQECAGKAIIIQULIAYoAgAgBWpBIjoAACAGIAVBAWoiBTYCCCABKAIAIAVrQQlNBEAgBiAFQQoQESAGKAIIIQULIAYoAgAgBWoiAUHbhMAAKQAANwAAIAFBCGpB44TAAC8AADsAACAGIAVBCmoiBTYCCCAGQQRqKAIAIAVrQQFNBEAgBiAFQQIQESAGKAIIIQULIAYoAgAgBWpBovQAOwAAIAYgBUECajYCCCAEQdAAaiAGEJoBAkACQAJAIAQoAlBFBEAgBEHYAGotAAAhBQJAAkAgBEEYaiAEKAJUIgEgAwR/IAIgA0EYbGohBiAFQf8BcUUhBSAEQdAAakEEciEDA0AgBUEBcQRAIAEoAggiBSABKAIERgRAIAEgBRAQIAEoAgghBQsgASAFQQFqNgIIIAEoAgAgBWpBLDoAAAsgBEHQAGogARCbASAEKAJQDQIgBCAELQBYOgBMIAQgBCgCVDYCSCAEQdAAaiAEQcgAakHuhMAAQQMgAigCACACQQhqKAIAEA8gBCgCUA0DIARB0ABqIARByABqQfGEwABBBSACQQxqKAIAIAJBFGooAgAQDyAEKAJQBEAgBEHEAGogBEHcAGooAgA2AgAgBCAEKQJUNwI8DAYLIARBOGogBCgCSCAELQBMEJMBIAQoAjgNBUEBIQUgAkEYaiICIAZHDQALQQAFIAULQf8BcUEARxCSASAEKAIYDQQgAEEANgIADAULIARBxABqIANBCGooAgA2AgAgBCADKQIANwI8DAILIARBxABqIARB3ABqKAIANgIAIAQgBCkCVDcCPAwBCyAEQSRqIARB3ABqKAIANgIAIAQgBCkCVDcCHAwBCyAEQSRqIARBxABqKAIANgIAIAQgBCkCPDcCHAsgBEEQaiAEQSRqKAIAIgE2AgAgBCAEKQIcIgg3AwggAEEMaiABNgIAIAAgCDcCBCAAQQE2AgALIARB4ABqJAALjgMBBH8jAEFAaiIFJAACQAJAAkACQCACRQRAQQEhBAwBCyACQX9KIgZFDQEgAiAGED0iBEUNAgsgBCABIAIQiwIhByAFQQA2AgggBUIBNwMAIAVBEGoiBiAFQaiFwAAQ8gEjAEEwayIEJAACfyADIgEoAgBFBEAgBEEcakEANgIAIARBxLPAADYCGCAEQgE3AgwgBEGEvcAANgIIIAYgBEEIahD3AQwBCyAEIAE2AgQgBEEcakEBNgIAIARCATcCDCAEQdSzwAA2AgggBEHEADYCJCAEIARBIGo2AhggBCAEQSxqNgIgIAQgBEEEajYCLCAGIARBCGoQ9wELIARBMGokAA0CIABBDGogAjYCACAAQQhqIAI2AgAgACAHNgIEIAAgBSkDADcCECAAQQk2AgAgAEEYaiAFQQhqKAIANgIAAkAgAygCACIARQ0AIANBBGooAgBFDQAgABCrAQsgBUFAayQADwsQzwEACyACIAYQzgEAC0HAhcAAQTcgBUE4akH4hcAAQdSGwAAQ6QEAC6kCAQJ/QQEhBQJAAkBBBkEBED0iBgRAIAYgAigAADYAACAGQQRqIAJBBGovAAA7AAAgBARAIARBf0oiAkUNAiAEIAIQPSIFRQ0DCyAFIAMgBBCLAiEDIAFBFGooAgAiAiABQRBqIgUoAgBGBEAgAUEMaiACECMgASgCFCECCyABIAJBAWo2AhQgACABKQIANwIAIAEoAgwgAkEYbGoiAiAENgIUIAIgBDYCECACIAM2AgwgAkKGgICA4AA3AgQgAiAGNgIAIABBCGogAUEIaikCADcCACAAQRhqIAFBGGopAgA3AgAgAEEgaiABQSBqKQIANwIAIABBKGogAUEoaikCADcCACAAQRBqIAUpAgA3AgAPC0EGQQEQzgEACxDPAQALIAQgAhDOAQAL2QEBBH8jAEEgayICJAACQAJAIAFBAWoiAUUNACAAQQRqKAIAIgNBAXQiBCABIAEgBEkbIgFBBCABQQRLGyIBQRhsIQQgAUHWqtUqSUECdCEFAkAgAwRAIAJBBDYCGCACIANBGGw2AhQgAiAAKAIANgIQDAELIAJBADYCGAsgAiAEIAUgAkEQahA1IAIoAgQhAyACKAIARQRAIAAgAzYCACAAQQRqIAE2AgAMAgsgAkEIaigCACIAQYGAgIB4Rg0BIABFDQAgAyAAEM4BAAsQzwEACyACQSBqJAAL+QwBC38jAEGQAWsiAyQAIANBOGogAUGTjMAAQQUgAhEFAAJAAkACQAJAAkACQAJAAkAgAygCOCILRQRAQRhBARA9IgFFDQEgAEKYgICAgAM3AwggACABNgIEIABBBzYCACABQRBqQbaJwAApAAA3AAAgAUEIakGuicAAKQAANwAAIAFBponAACkAADcAAAwICyADQcgAaiIBIAsgAygCQBCJASADQTBqIAEQkAEgAy0AMEEBcUUEQEEEIQIMBgsgAy0AMUH7AEcEQEEOIQIMBgsgA0HIAGoiARCKASADQShqIAEQiAEgAy0ALCADQSBqIAMoAigiAhCQASADLQAgQQFxRQRAQQIhAQwCCyADLQAhIQRBAXEhCQNAAkACQAJAAkACQAJAAkACQAJAAn8CQAJAAn8CQCAEQf8BcSIBQSxHBEAgAUH9AEcEQCAJQf8BcQ0CQQkMAwtBAyEEIAdBgH5xDAULQRAgCUH/AXENARogAhCKASADQRhqIAIQkAEgAy0AGEEBcUUNAiADLQAZIQQLIARB/wFxIgVBIkYNAkEQIAVB/QBHDQAaQRMLIQEgByEFDA4LIAdB/wFxIQVBBCEBDA0LIANBEGogAhCQASADLQAQQQFxRQRAQQQhAUEAIQUMDQsgAy0AEUEiRwRAQQ4hAQwNCyACEIoBIANBgAFqIAIQjwEgAygCjAEhCSADKAKIASEEIAMoAoQBIQUgAygCgAEiAUEVRw0MAkAgBUUEQEECIQEgCUEFRw0BIARB8YzAAEEFEI0CRQRAQQAhAQwCC0ECQQEgBEHsjMAAQQUQjQIbIQEMAQsCf0ECIAlBBUcNABpBACAFQfGMwABBBRCNAkUNABpBAkEBIAVB7IzAAEEFEI0CGwshASAERQ0AIAUQqwELIAdBgH5xIQRBACEJIAFB/wFxCyAEciIHQf8BcSIFQQNHBEAgBQ4CAwIBCwJAIA1FBEAgA0GAAWpB8YzAAEEFEBYgAygCgAFBFUcNASADKAKEASEMCyAGRQRAIANBgAFqQeyMwABBBRAWIAMoAoABQRVHDQUgA0GMAWooAgAhCiADQYgBaigCACEIIAMoAoQBIQYLIANB2ABqIANByABqEI0BIAMoAlgiAkEVRg0FIAMoAmQhBCADKAJgIQcgAygCXCEFIAhFDRAgBhCrAQwQCyADQeQAaiADQYgBaikDADcCACADIAMpA4ABNwJcDAwLIANBgAFqIAIQjgECQCADKAKAASIBQRVHBEAgA0H8AGogA0GMAWooAgA2AgAgAyADKQKEATcCdCADIAE2AnAMAQsgA0HwAGogAhAXIAMoAnBBFUYNCAsgA0HkAGogA0H4AGopAwA3AgAgAyADKQNwNwJcDAsLIAZFDQUgA0HYAGpBBHJB7IzAAEEFEBggCEUNDAwLCyANDQIgA0GAAWogAhAlIAMoAoABQRVGBEAgAygChAEhDEEBIQ0MBgsgA0HkAGogA0GIAWopAwA3AgAgAyADKQOAATcCXAwJCyADQeQAaiADQYgBaikDADcCACADIAMpA4ABNwJcDAoLIANB2ABqIANByABqEIsBIAMoAlgiAkEVRg0BIAMoAmQhBCADKAJgIQcgAygCXCEFIAhFDQogBhCrAQwKCyADQdgAakEEckHxjMAAQQUQGAwGCyAAQRBqIAo2AgAgAEEMaiAINgIAIABBCGogBjYCACAAIAw2AgQgAEENNgIADAkLIANBgAFqIAIQjgECQCADKAKAASIEQRVGBEAgA0GAAWogAhAaIAMoAowBIQogAygCiAEhCCADKAKEASEGIAMoAoABIgRBFUYNAgwBCyADKAKMASEKIAMoAogBIQggAygChAEhBgsgA0HoAGogCjYCACADQeQAaiAINgIAIANB4ABqIAY2AgAgAyAENgJcDAYLIANBCGogAhCQASADLQAJIQQgAy0ACEEBcQ0AC0ECIQEMAQtBGEEBEM4BAAsgA0HoAGogCTYCACADQeQAaiAENgIAIANB4ABqIAU2AgAgAyABNgJcCyAGRSAIRXINAQsgBhCrAQsgA0HoAGooAgAhBCADQeQAaigCACEHIANB4ABqKAIAIQUgAygCXCECCyADIAQ2AmQgAyAHNgJgIAMgBTYCXCADIAI2AlggAEGmicAAQRggA0HYAGoQGwsgC0UNACADKAI8RQ0AIAsQqwELIANBkAFqJAALtQMCBX8BfiMAQTBrIgIkACACQSBqIAEQjgECQAJAAkAgAigCICIDQRVGBEAgAkEYaiABEJABIAItABhBAXFFDQEgAi0AGSIEQS1GBEAgARCKAQsgAkEQaiABEJEBIAItABBBAXFFDQIgAi0AESIDQTBGBEAgARCKASAAQhU3AgAMBAsgA0Exa0H/AXFBCU8EQCAAQQ42AgAMBAsgARCKAUF/QQEgBEEtRhsiBCADQTBrQf8BcWwhAwNAIAJBCGogARCRAQJAAkAgAi0ACEEBcUUNACACLQAJIgUiBkEwSQ0AIAZBOkkNAQsgAEEVNgIAIAAgAzYCBAwFCyABEIoBIAOsQgp+IgdCIIinIAenIgNBH3VHBEAgACADNgIEIABBDTYCAAwFCyAEIAVBMGtB/wFxbCIFQQBIIAMgAyAFaiIDSkYNAAsgACADNgIEIABBDTYCAAwDCyAAIAIpAiQ3AgQgAEEMaiACQSxqKAIANgIAIAAgAzYCAAwCCyAAQQA7AAUgAEEENgIAIABBB2pBADoAAAwBCyAAQQA7AAUgAEEENgIAIABBB2pBADoAAAsgAkEwaiQAC7sGAgV/A34jAEGQAWsiBCQAIARByABqIgUQlQEgBEGAAWogBRCbAQJAAkACQAJAAkAgBCgCgAFFBEAgBCAEKAKEATYCaCAEIARBiAFqLQAAOgBsIARBgAFqIARB6ABqIAMoAgAQJyAEKAKAAUUEQCADQQxqKAIAIQcgA0EEaigCACEIIAQoAmghAyAELQBsBEAgAygCCCEFDAMLIAMoAggiBiADKAIERgRAIAMgBhAQIAMoAgghBgsgAyAGQQFqIgU2AgggAygCACAGakEsOgAADAILIARB5ABqIARBjAFqKAIANgIAIAQgBCkChAE3AlwMAgsgBEHkAGogBEGMAWooAgA2AgAgBCAEKQKEATcCXAwBCyAEQQA6AGwgA0EEaiIGKAIAIAVGBEAgAyAFEBAgAygCCCEFCyADKAIAIAVqQSI6AAAgAyAFQQFqIgU2AgggBigCACAFa0EETQRAIAMgBUEFEBEgAygCCCEFCyADKAIAIAVqIgZB7IzAACgAADYAACAGQQRqQfCMwAAtAAA6AAAgAyAFQQVqIgU2AgggA0EEaigCACAFa0EBTQRAIAMgBUECEBEgAygCCCEFCyADKAIAIAVqQaL0ADsAACADIAVBAmo2AgggBEGAAWogAyAIIAcQlwEgBCgCgAEEQCAEQeQAaiAEQYwBaigCADYCACAEIAQpAoQBNwJcDAELIARB2ABqIANBABCTASAEKAJYRQ0BCyAEQUBrIgMgBEHkAGooAgA2AgAgBCAEKQJcNwM4IAQoAkwEQCAEKAJIEKsBCyAEQYgBaiADKAIANgIAIAQgBCkDODcDgAEgBEEYakGmicAAQRggBEGAAWoQISAEKAIYIgNBDUYNASAEQRBqIARBMGopAwAiCTcDACAEIAQpAygiCjcDCCAEKQIcIQsgBCgCJCEBIABBGGogCTcDACAAIAo3AxAgACABNgIMIAAgCzcCBCAAIAM2AgAMAgsgBEEkaiAEQdAAaigCADYCACAEIAQpA0g3AhwLIARBIGooAgAgAUGTjMAAQQUgBCgCHCIBIARBJGooAgAgAigCFBEHAARAIAEQqwELIABBDTYCAAsgBEGQAWokAAuUBwIFfwF+IwBBIGsiBiQAIAEoAgAhBAJAIAEtAAQEQCAEKAIIIQMMAQsgBCgCCCIFIAQoAgRGBEAgBCAFEBAgBCgCCCEFCyAEIAVBAWoiAzYCCCAEKAIAIAVqQSw6AAALIAFBADoABCAEQQRqIgEoAgAgA0YEQCAEIAMQECAEKAIIIQMLIAQoAgAgA2pBIjoAACAEIANBAWoiAzYCCCABKAIAIANrQQRNBEAgBCADQQUQESAEKAIIIQMLIAQoAgAgA2oiAUHxjMAAKAAANgAAIAFBBGpB9YzAAC0AADoAACAEIANBBWoiAzYCCCAEQQRqKAIAIANrQQFNBEAgBCADQQIQESAEKAIIIQMLIAQoAgAgA2pBovQAOwAAIAQgA0ECajYCCCAGQRBqIQcjAEEQayIDJAAgA0EIakEAOwEAIANCADcDACADQYCAgIB4IAIgAkEfdSIBcyABayACQYCAgIB4RhsiASABQQpuIgVBCmxrQTByOgAKAn9BCSABQQpJDQAaIAMgBUEKcEEwcjoACUEIIAFB5ABJDQAaIAMgAUHkAG5BCnBBMHI6AAhBByABQegHSQ0AGiADIAFB6AduQQpwQTByOgAHQQYgAUGQzgBJDQAaIAMgAUGQzgBuQQpwQTByOgAGQQUgAUGgjQZJDQAaIAMgAUGgjQZuQQpwQTByOgAFQQQgAUHAhD1JDQAaIAMgAUHAhD1uQQpwQTByOgAEQQMgAUGAreIESQ0AGiADIAFBgK3iBG5B/wFxQQpwQTByOgADQQIgAUGAwtcvSQ0AGiADIAFBgMLXL25BCnBBMHI6AAJBASABQYCU69wDSQ0AGiADIAFBgJTr3ANuQTByOgABQQALIQECQAJAAkACQCACQQBOBEAgAUEBaiIBRQ0DIAFBDEkNASABQQtB8L3AABDWAQALIAFBCksNASABIANqQS06AAALQQsgAWsiBSAEQQRqKAIAIAQoAggiAmtLBEAgBCACIAUQhAEgBCgCCCECCyAEKAIAIAJqIAEgA2ogBRCLAhogB0EANgIAIAQgAiAFajYCCCADQRBqJAAMAgsgAUELQfC9wAAQ1QEAC0HgusAAQRxB8L3AABDZAQALAkAgBigCEEUEQCAAQQA2AgAMAQsgBkEIaiAGQRxqKAIAIgE2AgAgBiAGKQIUIgg3AwAgAEEMaiABNgIAIAAgCDcCBCAAQQE2AgALIAZBIGokAAsRACAAKAIAIAAoAgQgARCAAgsLACAAKAIAIAEQfQtXAQF/IwBBIGsiAiQAIAIgADYCBCACQRhqIAFBEGopAgA3AwAgAkEQaiABQQhqKQIANwMAIAIgASkCADcDCCACQQRqQfSJwAAgAkEIahDeASACQSBqJAAL6QgBB38CQCAAKAIAIgUEQCAAQQhqKAIAIgEEQCAFIAFB4ABsaiEHA0AgBSIBQeAAaiEFAkACQAJAIAEoAggiA0EFayIGQQIgBkECSRsOAgECAAsCQAJAAkACQAJAIAMOBAECAwQACyABQRBqKAIARQ0FIAFBDGooAgAQqwEMBQsgAUEQaigCAARAIAFBDGooAgAQqwELIAFBHGooAgAEQCABQRhqKAIAEKsBCyABQSxqKAIAIgMEQCADQQV0IQQgAUEkaigCAEEQaiECA0AgAkEEaigCAARAIAIoAgAQqwELIAJBIGohAiAEQSBrIgQNAAsLIAFBKGooAgBFDQQgASgCJBCrAQwECwJAIAFBDGooAgAiA0UNACABQRBqKAIARQ0AIAMQqwELIAFBHGooAgAEQCABQRhqKAIAEKsBCyABQSxqKAIAIgMEQCADQQV0IQQgAUEkaigCAEEQaiECA0AgAkEEaigCAARAIAIoAgAQqwELIAJBIGohAiAEQSBrIgQNAAsLIAFBKGooAgAEQCABKAIkEKsBCyABQTRqKAIARQ0DIAFBMGooAgAQqwEMAwsgAUEQaigCAARAIAFBDGooAgAQqwELIAFBHGooAgBFDQIgAUEYaigCABCrAQwCCyABQRBqKAIABEAgAUEMaigCABCrAQsgAUEcaigCAEUNASABQRhqKAIAEKsBDAELIAFBDGohBgJAIAFBGGoiAygCACICBEAgAUEQaigCAARAIAYoAgAQqwEgAygCACECCyABQSBqKAIAIgYEQCAGQQV0IQQgAkEQaiECA0AgAkEEaigCAARAIAIoAgAQqwELIAJBIGohAiAEQSBrIgQNAAsLIAFBHGooAgANAQwCCyABQRRqKAIAIgMEQCADQQV0IQQgASgCDEEQaiECA0AgAkEEaigCAARAIAIoAgAQqwELIAJBIGohAiAEQSBrIgQNAAsLIAYhAyABQRBqKAIARQ0BCyADKAIAEKsBCyAFIAdHDQALCyAAQQRqKAIABEAgACgCABCrAQsgAEEUaigCACIBBEAgAEEMaigCACECIAFBGGwhBANAIAJBBGooAgAEQCACKAIAEKsBCyACQRBqKAIABEAgAkEMaigCABCrAQsgAkEYaiECIARBGGsiBA0ACwsgAEEQaigCAARAIAAoAgwQqwELIABBIGooAgAiBQRAIABBGGooAgAiASAFQRhsaiEFA0AgAUEEaigCAARAIAEoAgAQqwELIAFBFGooAgAiAwRAIAFBDGooAgAhAiADQRhsIQQDQCACQQRqKAIABEAgAigCABCrAQsgAkEQaigCAARAIAJBDGooAgAQqwELIAJBGGohAiAEQRhrIgQNAAsLIAFBEGooAgAEQCABKAIMEKsBCyABQRhqIgMhASADIAVHDQALCyAAQRxqKAIABEAgACgCGBCrAQsgACgCJCIBRQ0BIABBKGooAgBFDQEgARCrAQ8LIABBCGooAgBFDQAgACgCBBCrAQsLAwABCxUAIABBBGooAgAEQCAAKAIAEKsBCwurAgACQAJ/AkACQAJAAkACQAJAAkACQAJAAkAgACgCAA4MCwsBAgsDBAUGBwgJAAsgAEEYaigCAEUNCiAAQRRqDAkLIABBCGooAgBFDQkgAEEEagwICyAAQQhqKAIARQ0IIABBBGoMBwsgAEEIaigCAEUNByAAQQRqDAYLIABBCGooAgBFDQYgAEEEagwFCyAAQQhqKAIARQ0FIABBBGoMBAsgAEEIaigCAARAIAAoAgQQqwELIABBFGooAgBFDQQgAEEQagwDCyAAQQhqKAIABEAgACgCBBCrAQsgAEEUaigCAEUNAyAAQRBqDAILIABBCGooAgAEQCAAKAIEEKsBCyAAQRRqKAIARQ0CIABBEGoMAQsgAEEIaigCAEUNASAAQQRqCygCABCrAQsLDgAgACgCACABEDAaQQALzwIBAn8jAEEQayICJAACQAJ/AkAgAUGAAU8EQCACQQA2AgwgAUGAEE8NASACIAFBP3FBgAFyOgANIAIgAUEGdkHAAXI6AAxBAgwCCyAAKAIIIgMgACgCBEYEQCAAIAMQECAAKAIIIQMLIAAgA0EBajYCCCAAKAIAIANqIAE6AAAMAgsgAUGAgARPBEAgAiABQT9xQYABcjoADyACIAFBBnZBP3FBgAFyOgAOIAIgAUEMdkE/cUGAAXI6AA0gAiABQRJ2QQdxQfABcjoADEEEDAELIAIgAUE/cUGAAXI6AA4gAiABQQx2QeABcjoADCACIAFBBnZBP3FBgAFyOgANQQMLIQEgASAAQQRqKAIAIAAoAggiA2tLBEAgACADIAEQESAAKAIIIQMLIAAoAgAgA2ogAkEMaiABEIsCGiAAIAEgA2o2AggLIAJBEGokAEEAC1oBAX8jAEEgayICJAAgAiAAKAIANgIEIAJBGGogAUEQaikCADcDACACQRBqIAFBCGopAgA3AwAgAiABKQIANwMIIAJBBGpB9InAACACQQhqEN4BIAJBIGokAAtKAQF/IAIgACgCACIAQQRqKAIAIAAoAggiA2tLBEAgACADIAIQESAAKAIIIQMLIAAoAgAgA2ogASACEIsCGiAAIAIgA2o2AghBAAvGBAICfwF+IwBBsAFrIgIkACACQQhqIAFBDGopAgA3AwAgAkEQaiABQRRqKQIANwMAIAJBGGogAUEcaikCADcDACACQSBqIAFBJGooAgA2AgAgAiABKQIENwMAAkACQCABKAIAIgMEQCABKQMoIQQgACADNgIAIAAgBDcCKCAAIAFBBGoiASkCADcCBCAAQQxqIAFBCGopAgA3AgAgAEEUaiABQRBqKQIANwIAIABBHGogAUEYaikCADcCACAAQSRqIAFBIGooAgA2AgAMAQsgAkFAayACQRxqKQIANwMAIAJBOGogAkEUaikCADcDACACQTBqIAJBDGopAgA3AwAgAiACKQIENwMoIAJBADYCUCACQgE3A0ggAkHYAGogAkHIAGpBqIXAABDyASACKAIoQQ1GBEAgAkGkAWpBADYCACACQYyKwAA2AqABIAJCATcClAEgAkGEjcAANgKQASACQdgAaiACQZABahD3AQ0CIAAgAikDSDcCBCAAQQA2AgAgAEEMaiACQdAAaigCADYCAAwBCyACQaQBakEBNgIAIAJCATcClAEgAkGMjcAANgKQASACQQM2AoQBIAIgAkGAAWo2AqABIAIgAkGMAWo2AoABIAIgAkEoajYCjAEgAkHYAGogAkGQAWoQ9wENASACKAIoIABBDGogAkHQAGooAgA2AgAgACACKQNINwIEIABBADYCAEENRg0AIAJB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yAFBDUcNASADKALMASEBCyADQfQCakH0gMAANgIAIANB7AJqQciAwAA2AgAgA0HkAmpBrIDAADYCACADQbACaiADQcABaikDADcDACADQcgCaiADQbABaikDADcDACADQYwDaiAGNgIAIANBiANqIA02AgAgA0GEA2ogCDYCACADQYADaiATNgIAIANB/AJqIA82AgAgA0HwAmogA0GYA2oiADYCACADQegCaiAANgIAIAMgAykDuAE3A6gCIAMgCjYCvAIgAyAJNgK4AiADIAMpA6gBNwPAAiADIAE2ApADIAMgEDYC+AIgAyAWNwPYAiADIAw2AtQCIAMgCzYC0AIgAyAANgLgAiADQegBaiINIQIgA0GoAmohB0EAIQojAEHgAWsiACQAIAAgATYCDCAAQfAAaiADQfgCaiIEENEBIABBHGogAEH4AGooAgA2AgAgACABNgIQIAAgACkDcDcCFCADQeACaiIBKAIEIQsgASgCACEMAkACQAJAAkACQAJAAkACQAJAQRRBARA9IgEEQCABQRBqQd2MwAAoAAA2AAAgAUEIakHVjMAAKQAANwAAIAFBzYzAACkAADcAAEEFQQEQPSIFRQ0IIAVBBGpB5YzAAC0AADoAACAFQeGMwAAoAAA2AAAgAEGwAWoiBhCVASAAQUBrIAYQmwEgACgCQA0BIAAgACgCRDYCwAEgACAAQcgAai0AADoAxAEgAEFAayAAQcABakGUgcAAQQggAUEUEA8gACgCQA0CIABBQGsgAEHAAWpBk4XAAEEHIAVBBRAPIAAoAkAEQCAAQdQBaiAAQcwAaigCADYCACAAIAApAkQ3AswBDAULIABByAFqIAAoAsABIAAtAMQBEJMBIAAoAsgBRQ0DDAQLQRRBARDOAQALIABB1AFqIABBzABqKAIANgIAIAAgACkCRDcCzAEMAgsgAEHUAWogAEHMAGooAgA2AgAgACAAKQJENwLMAQwBCyAAQfwAaiAAQbgBaigCADYCACAAIAApA7ABNwJ0DAELIABBqAFqIgYgAEHUAWooAgA2AgAgACAAKQLMATcDoAEgACgCtAEEQCAAKAKwARCrAQsgAEHIAGogBigCADYCACAAIAApA6ABNwNAIABB8ABqQd2JwABBFCAAQUBrECEgACgCcCIGQQ1HDQELIABB+ABqKAIAIQhBDSEGIAxBmoXAAEENIAAoAnQiCSAAQfwAaigCACALKAIUEQcAIAhFDQEgCRCrAQwBCyAAQThqIABBiAFqKQMANwMAIAAgACkDgAE3AzAgACgCfCEIIAAoAnghCSAAKAJ0IQoLIAEQqwEgBRCrAQJAAkACQAJAAkACQCAGQQ1GBEAgAEHwAGogDCALIABBEGoQJiAAKAJwIgFBDUYNAiAAQdgAaiAAQYwBaigCACIFNgIAIABB0ABqIABBhAFqKQIAIhU3AwAgAEHIAGogAEH8AGopAgAiFjcDACAAIAApAnQiFzcDQCACQSRqIAU2AgAgAkEcaiAVNwIAIAJBFGogFjcCACACQQxqIBc3AgAgAiABNgIIDAELIABBKGogAEE4aikDACIVNwMAIAAgACkDMCIWNwMgIAJBIGogFTcCACACQRhqIBY3AgAgAkEUaiAINgIAIAJBEGogCTYCACACQQxqIAo2AgAgAiAGNgIICyACQQA2AgAgAEEYaigCAARAIAAoAhQQqwELIARBBGooAgAEQCAEKAIAEKsBCyAEQRRqKAIAIgEEQCABQQV0IQEgBEEMaigCAEEQaiECA0AgAkEEaigCAARAIAIoAgAQqwELIAJBIGohAiABQSBrIgENAAsLIARBEGooAgAEQCAEKAIMEKsBCyAHQRRqKAIABEAgBygCEBCrAQsgB0EsaigCAA0BDAILIABBkAFqQgA3AwAgAEGAAWpCADcDACAAQgQ3A4gBIABCgICAgMAANwN4IABCCDcDcCAAQUBrIABB8ABqQeaMwABBgITAAEELECIgAEE4aiIFIARBCGooAgA2AgAgACAEKQIANwMwQQVBARA9IgFFDQQgAUEEakHwjMAALQAAOgAAIAFB7IzAACgAADYAACAAQfgAaiAFKAIANgIAIAAgACkDMDcDcCAAQdQBaiIFIABB8ABqIgYpAgA3AgAgBUEIaiAGQQhqKAIANgIAIABChYCAgNAANwLMASAAIAE2AsgBIABB1ABqKAIAIgEgAEHQAGooAgBGBEAgAEHMAGogARAjIAAoAlQhAQsgACgCTCABQRhsaiIFIAApA8gBNwIAIAVBCGogAEHQAWopAwA3AgAgBUEQaiAAQdgBaikDADcCACAAQfgAaiAAQcgAaikDADcDACAAQYgBaiAAQdgAaikDADcDACAAQZABaiAAQeAAaikDADcDACAAQZgBaiAAQegAaikDADcDACAAIAFBAWo2AlQgAEGAAWogAEHQAGopAwA3AwAgACAAKQNANwNwIABBADYC0AEgAEIBNwPIASAAQUBrIgUgAEHIAWpBqIXAABDyASAAQQxqKAIAIgGtQgAgAax9IAFBf0oiARsgASAFEIUCDQJBBUEBED0iBUUNAyAFQQRqQfWMwAAtAAA6AAAgBUHxjMAAKAAANgAAIABBhAFqKAIAIgEgAEGAAWoiCCgCAEYEQCAAQfwAaiABECMgACgChAEhAQsgACgCfCABQRhsaiIGQoWAgIDQADcCBCAGIAU2AgAgAiAAKQNwNwIAIAJBCGogAEH4AGopAwA3AgAgAkEYaiAAQYgBaikDADcCACACQSBqIABBkAFqKQMANwIAIAJBKGogAEGYAWopAwA3AgAgACABQQFqNgKEASACQRBqIAgpAwA3AgAgBiAAKQPIATcCDCAGQRRqIABB0AFqKAIANgIAIABBGGooAgAEQCAAKAIUEKsBCyAEQRRqKAIAIgEEQCABQQV0IQEgBEEMaigCAEEQaiECA0AgAkEEaigCAARAIAIoAgAQqwELIAJBIGohAiABQSBrIgENAAsLIARBEGooAgAEQCAEKAIMEKsBCyAHQRRqKAIABEAgBygCEBCrAQsgB0EsaigCAEUNAQsgBygCKBCrAQsgAEHgAWokAAwDC0HAhcAAQTcgAEEwakH4hcAAQdSGwAAQ6QEACwtBBUEBEM4BAAsgA0HIAGogDRAzIAMoApwBBEAgFBCrAQsgAygCjAEEQCASEKsBCyADKAJ8RQ0DIA4QqwEMAwsgA0GAAmogA0HgAWopAwA3AwAgA0H4AWogA0HYAWopAwA3AwAgA0HwAWogA0HQAWopAwA3AwAgAyADKQPIATcD6AEgA0EANgKgAiADQgE3A5gCIANBqAJqIgAgA0GYAmpBqIXAABDyASADQegBaiAAEH1FBEAgA0HUAGogA0GgAmooAgA2AgAgAyADKQOYAjcCTCADQQA2AkggA0HoAWoQLiAPBEAgEBCrAQsgBgRAIAZBBXQhASAIQRBqIQADQCAAQQRqKAIABEAgACgCABCrAQsgAEEgaiEAIAFBIGsiAQ0ACwsgDUUNASAIEKsBDAELDAMLIAoEQCAJEKsBCyAMRQ0AIAsQqwELIAMoApwBBEAgAygCmAEQqwELIAMoAowBBEAgAygCiAEQqwELIAMoAnxFDQAgDhCrAQsgA0HoAWogA0HIAGoQHiADKALoAUENRgRAIANB0AFqIANB9AFqKAIAIgA2AgAgAyADKQLsASIVNwPIASADQbACaiAANgIAIAMgFTcDqAIgA0GoAmoQfiADQcgAahArIANBoANqJAAPCyADQcACaiADQYACaikDADcDACADQbgCaiADQfgBaikDADcDACADQbACaiADQfABaikDADcDACADIAMpA+gBNwOoAkHFgcAAQSsgA0GoAmpB8IHAAEH0gsAAEOkBAAtBwIXAAEE3IANBmANqQfiFwABB1IbAABDpAQALnSoCE38CfiMAQdADayIDJAAQrQEgA0GoAWogABB/IANBuAFqIAEQfyADQcgBaiACEH8gA0HYAmogAygCqAEiEyADKAKwARAVAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJ/AkACfwJAAkACQAJAAkACQAJAAkACQAJAIAMoAvgCQQJHBEAgA0HwAWogA0HgAmopAwA3AwAgA0HgAWogA0H4AmopAwA3AwAgAyADKQPYAjcD6AEgAyADKQPwAjcD2AEgAygC6AIhESADKALsAiEOIAMoAoADIQ8gAygChAMhEiADKQOIAyEWIANB+AFqIAMoArgBIhQgAygCwAEQHCADKAL4AUENRw0CIANBkAJqKAIAIQwgA0GMAmooAgAhCiADQYgCaigCACEJIANBhAJqKAIAIQIgA0GAAmooAgAhDSADKAL8ASEQIANByAJqIgAgAygCyAEiFSADKALQARCJASADQfAAaiAAEJABIAMtAHBBAXENAQwUCyADQZACaiADQfACaikDADcDACADQYgCaiADQegCaikDADcDACADQYACaiADQeACaikDADcDACADIAMpA9gCNwP4ASADQQA2AtACIANCATcDyAIgA0GYAmoiACADQcgCakGohcAAEPIBIANB+AFqIAAQfQ0aIANBhAFqIANB0AJqKAIANgIAIAMgAykDyAI3AnwgA0EANgJ4IANB+AFqEC4MGAsgAy0AcSIAQfsARwRAIABBIkcEQEEKIQAMFQsgA0HYAmogA0HIAmoQOCADKALYAiIAQRVHDQ9BDiEADBQLIANByAJqIgQQigEgA0HYAmogBBA4AkACfyAD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AEEiRw0GIANBCGogBRCQAUEEIQAgAy0ACEEBcUUNB0EOIQAgAy0ACUEiRw0HIAUQigEgA0HYAmogBRCPASADKALYAiIAQRVHDQEgA0HkAmooAgAhByADQeACaigCACEAIAMoAtwCIgVFBEAgA0GYAmogACAHQYyKwABBABA2DAMLIANBmAJqIAUgB0GMisAAQQAQNiAARQ0CIAUQqwEMAgtBEyEADAYLIAMgAygC5AI2AqQCIAMgAykC3AI3ApwCIAMgADYCmAILIAMoApgCIgBBFUYNACADLwCdAiADLQCfAkEQdHIhByADKQOgAiEXIAMtAJwCIQUMBAsgA0HYAmogBBCNASADKALYAiIAQRVHBEAgAygC3AIiAUEIdiEHIAMoAuQCIQUgAygC4AIhBgwFCyADIAQQkAEgAy0AAEEBcUUNBUELIQAgAy0AAUH9AEcNBgsgBBCKASADQdgCaiADQcgCahCLASADKALYAiIAQRVGDQYLIAMoAuQCIQUgAygC4AIhBiADKALcAiEHDAQLQRAhAAsgBUH/AXEhASAXQiCIpyEFIBenIQYLIAFB/wFxIAdBCHRyIQcMAQtBBCEAQQAhBwsgAyAFNgLkAiADIAY2AuACIAMgBzYC3AIgAyAANgLYAiADQfgBakHkhsAAQRsgA0HYAmoQGyADKAL4AUENRw0BIANBgAJqKAIAIQEgAygC/AEhCAsgA0GkA2pB9IDAADYCACADQZwDakHIgMAANgIAIANBlANqQayAwAA2AgAgA0HgAmogA0HwAWopAwA3AwAgA0H4AmogA0HgAWopAwA3AwAgA0HEA2ogATYCACADQbwDaiAMNgIAIANBuANqIAo2AgAgA0G0A2ogCTYCACADQbADaiACNgIAIANBrANqIA02AgAgA0GgA2ogA0HIA2oiADYCACADQZgDaiAANgIAIAMgAykD6AE3A9gCIAMgDjYC7AIgAyARNgLoAiADIAMpA9gBNwPwAiADIAg2AsADIAMgEDYCqAMgAyAWNwOIAyADIBI2AoQDIAMgDzYCgAMgAyAANgKQAyADQZgCaiISIQogA0GQA2ohACADQdgCaiERIANBqANqIQkgASECIwBBMGsiCyQAAkAgCEUEQCALQShqIABBEGopAgA3AwAgC0EgaiAAQQhqKQIANwMAIAsgACkCADcDGCMAQeAA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AWooAgAhACACQdABaigCACEBIAIoAswBIgVFBEAgAkGgAWogASAAQYyKwABBABA2DAMLIAJBoAFqIAUgAEGMisAAQQAQNiABRQ0CIAUQqwEMAgtBEyEBDAYLIAIgAigC1AE2AqwBIAIgAikCzAE3AqQBIAIgADYCoAELIAIoAqABIgFBFUYNACACLwClASACLQCnAUEQdHIhCyACKQOoASEOIAItAKQBIQMMBAsgAkHIAWogAxCNASACKALIASIBQRVHBEAgAi8AzQEgAi0AzwFBEHRyIQsgAikD0AEhDiACLQDMASEDDAQLIAJBCGogAxCQASACLQAIQQFxRQ0EIAItAAlB/QBHBEBBCyEBDAYLIAMQigEgAkHIAWogAkFAaxCLASACKALIASIBQRVGDQYLIAIpA9ABIQ4gAigCzAEhAwwECyACQZgBaiACQeABaikDADcDACACQZABaiACQdgBaikDADcDACACQYgBaiACQdABaikDADcDACACIAIpA8gBNwOAASACQQA2ArACIAJCATcDqAIgAkGgAWoiACACQagCakGohcAAEPIBIAJBgAFqIAAQfUUEQCACQcwAaiACQbACaigCADYCACACIAIpA6gCNwJEIAJBATYCQCACQYABahAuDAkLDA4LQRAhAQsgA0H/AXEgC0EIdHIhAwwBC0EEIQFBACEDCyACIA43A9ABIAIgAzYCzAEgAiABNgLIASACQYABakGgh8AAQRkgAkHIAWoQGyACKAKAAUENRw0BCyACQZQCakH0gMAANgIAIAJBjAJqQciAwAA2AgAgAkGEAmpBrIDAADYCACACQdABaiACQfgAaikDADcDACACQegBaiACQegAaikDADcDACACQZACaiACQbgCaiIANgIAIAJBiAJqIAA2AgAgAiACKQNwNwPIASACIAY2AtwBIAIgBDYC2AEgAiACKQNgNwPgASACIA83A/gBIAIgCTYC9AEgAiAINgLwASACIAA2AoACIAJBgAFqIgUhASACQcgBaiEDIwBB8ABrIgAkACAAQRhqIAJBgAJqIgQoAgAgBCgCBEEMaigCABAkAkACQAJAAkACQAJAAkAgACgCGCIEQQ1GBEAgACgCHCEEIABBJGooAgAEQCAAQSBqKAIAEKsBCyAAQcgAaiIGEJUBIABBGGogBhCbASAAKAIYDQEgACAAKAIcNgJoIAAgAEEgai0AADoAbCAAQRhqIABB6ABqIAQQJyAAKAIYBEAgAEHkAGogAEEkaigCADYCACAAIAApAhw3AlwMBAsgAEHYAGogACgCaCAALQBsEJMBIAAoAlhFDQIMAwsgAEEQaiAAQTRqKAIAIgY2AgAgACAAKQIsIg43AwggACkCHCEPIAApAiQhECABQRxqIAY2AgAgASAONwIUIAEgEDcCDCABIA83AgQgASAENgIAIANBFGooAgAEQCADKAIQEKsBCyADQSxqKAIARQ0GIAMoAigQqwEMBgsgAEHkAGogAEEkaigCADYCACAAIAApAhw3AlwMAQsgAEEkaiAAQdAAaigCADYCACAAIAApA0g3AhwMAQsgAEFAayIEIABB5ABqKAIANgIAIAAgACkCXDcDOCAAKAJMBEAgACgCSBCrAQsgAEHgAGogBCgCADYCACAAIAApAzg3A1ggAEEYakH/hsAAQSEgAEHYAGoQISAAKAIYQQ1HDQELIAEgACkCHDcCBCABQQ02AgAgAUEMaiAAQSRqKAIANgIADAELIAEgACkDGDcDACABQRhqIABBMGopAwA3AwAgAUEQaiAAQShqKQMANwMAIAFBCGogAEEgaikDADcDAAsgA0EUaigCAARAIAMoAhAQqwELIANBLGooAgBFDQAgAygCKBCrAQsgAEHwAGokACAFQQRyIQACQCACKAKAASIBQQ1GBEAgAkHMAGogAEEIaigCADYCACACQQA2AkAgAiAAKQIANwJEDAELIAJBrAFqIABBCGooAgA2AgAgAkG4AWogAkGYAWopAwA3AwAgAiABNgKgASACIAIpA5ABNwOwASACIAApAgA3AqQBIAJBADYCsAIgAkIBNwOoAiACQcgBaiIAIAJBqAJqQaiFwAAQ8gEgAkGgAWogABB9DQogAkHMAGogAkGwAmooAgA2AgAgAiACKQOoAjcCRCACQQE2AkAgAkGgAWoQLgsgAigCnAIEQCAMEKsBCyACKAJUBEAgBxCrAQsgAkGoAmoQlQEgAUENRw0EIAIoArACIgAgAigCrAJGBEAgAkGoAmogABAQIAIoArACIQALIAIoAqgCIABqQfsAOgAAIAIgAEEBajYCsAIgAkHIAWogAkGoAmpBy4TAAEECEJcBIAIoAsgBDQIgAigCsAIiACACKAKsAkYEQCACQagCaiAAEBAgAigCsAIhAAsgAigCqAIgAGpBOjoAACACIABBAWo2ArACIAJB8ABqIAJBQGtBBHIQaiACQcgBaiACQagCaiACKAJwIgAgAigCeBCXASACKAJ0BEAgABCrAQsgAigCyAENASACKAKwAiIAIAIoAqwCRgRAIAJBqAJqIAAQECACKAKwAiEACyACKAKoAiAAakH9ADoAACACIABBAWo2ArACDAULIAJBuAFqIAJBmAFqKQMANwMAIAJBsAFqIAJBkAFqKQMANwMAIAJBqAFqIAJBiAFqKQMANwMAIAIgAikDgAE3A6ABIAJBADYCsAIgAkIBNwOoAiACQcgBaiIAIAJBqAJqQaiFwAAQ8gEgAkGgAWogABB9DQggAkHMAGogAkGwAmooAgA2AgAgAiACKQOoAjcCRCACQQE2AkAgAkGgAWoQLiAGBEAgBBCrAQsgCUUNAiAIEKsBDAILIAJBjAFqIAJB1AFqKAIANgIAIAIgAikCzAE3AoQBDAQLIAJBjAFqIAJB1AFqKAIANgIAIAIgAikCzAE3AoQBDAMLIAIoApwCBEAgAigCmAIQqwELIAIoAlQEQCAHEKsBCyACQagCahCVAQsgAkGAAWogAkGoAmogAigCRCACQcwAaigCABAfIAIoAoABDQELIAJBrAFqIAJBsAJqKAIANgIAIAIgAikDqAI3AqQBDAELIAJBoAJqIgAgAkGMAWooAgA2AgAgAiACKQKEATcDmAIgAigCrAIEQCACKAKoAhCrAQsgAkHQAWogACgCADYCACACIAIpA5gCNwPIASACQaABakGaiMAAQdQAIAJByAFqECEgAigCoAFBDUcNAQsgAkHYAGogAkGsAWooAgAiADYCACACIAIpAqQBIg43A1AgAkHQAWogADYCACACIA43A8gBIAJByAFqEH4CQAJAIAIoAkBFBEAgAkHIAGooAgANAQwCCyACQcgAaigCAEUNAQsgAigCRBCrAQsgAkHAAmokAA8LIAJB4AFqIAJBuAFqKQMANwMAIAJB2AFqIAJBsAFqKQMANwMAIAJB0AFqIAJBqAFqKQMANwMAIAIgAikDoAE3A8gBQcWBwABBKyACQcgBakHwgcAAQYSDwAAQ6QEAC0HAhcAAQTcgAkG4AmpB+IXAAEHUhsAAEOkBAAsJACAAIAEQpQELmAcBBn8CfwJAAkACQCACQQlPBEAgAyACEKUBIgcNAUEADAQLQQhBCBCzASEBQRRBCBCzASECQRBBCBCzASEEQQBBEEEIELMBQQJ0ayIFQYCAfCAEIAEgAmpqa0F3cUEDayIBIAEgBUsbIANNDQFBECADQQRqQRBBCBCzAUEFayADSxtBCBCzASECIAAQwwEiASABELcBIgUQwAEhBAJAAkACQAJAAkACQAJAIAEQugFFBEAgAiAFTQ0BIARB6P/AACgCAEYNAiAEQeT/wAAoAgBGDQMgBBC4AQ0HIAQQtwEiBiAFaiIIIAJJDQcgCCACayEFIAZBgAJJDQQgBBCoAQwFCyABELcBIQQgAkGAAkkNBiACQQRqIARNQQAgBCACa0GBgAhJGw0FIAEoAgAiBSAEakEQaiEGIAJBH2pBgIAEELMBIQRBACICRQ0GIAIgBWoiASAEIAVrIgBBEGsiAzYCBCABIAMQwAFBBzYCBCABIABBDGsQwAFBADYCBEHs/8AAQez/wAAoAgAgBCAGa2oiADYCAEGIgMEAQYiAwQAoAgAiAyACIAIgA0sbNgIAQfD/wABB8P/AACgCACICIAAgACACSRs2AgAMCQtBEEEIELMBIAUgAmsiBEsNBCABIAIQwAEhBSABIAIQuwEgBSAEELsBIAUgBBCnAQwEC0Hg/8AAKAIAIAVqIgUgAk0NBCABIAIQwAEhBCABIAIQuwEgBCAFIAJrIgJBAXI2AgRB4P/AACACNgIAQej/wAAgBDYCAAwDC0Hc/8AAKAIAIAVqIgUgAkkNAwJAQRBBCBCzASAFIAJrIgRLBEAgASAFELsBQQAhBEEAIQUMAQsgASACEMABIgUgBBDAASEGIAEgAhC7ASAFIAQQvgEgBiAGKAIEQX5xNgIEC0Hk/8AAIAU2AgBB3P/AACAENgIADAILIARBDGooAgAiCSAEQQhqKAIAIgRHBEAgBCAJNgIMIAkgBDYCCAwBC0HM/MAAQcz8wAAoAgBBfiAGQQN2d3E2AgALQRBBCBCzASAFTQRAIAEgAhDAASEEIAEgAhC7ASAEIAUQuwEgBCAFEKcBDAELIAEgCBC7AQsgAQ0DCyADEKYBIgJFDQEgAiAAIAEQtwFBeEF8IAEQugEbaiIBIAMgASADSRsQiwIgABCrAQwDCyAHIAAgASADIAEgA0kbEIsCGiAAEKsBCyAHDAELIAEQugEaIAEQwgELCw0AQuuRk7X22LOi9AALGQAgACgCACIAKAIAIABBCGooAgAgARD9AQtuAQF/IwBBEGsiAiQAIAIgACgCACIAQRhqNgIEIAIgADYCCCACIABBDGo2AgwgAUHor8AAQQ1B9a/AAEEJIAJBBGpBgLDAAEGQsMAAQQggAkEIakGElMAAQZiwwABBCCACQQxqEPwBIAJBEGokAAs7AQF/IwBBEGsiAiQAIAIgACgCADYCDCABQfSwwABBEUGFscAAQQcgAkEMakGElMAAEPoBIAJBEGokAAsdACABIAAoAgAtAABBAnRBmLPAAGooAgBBAxD2AQsZACAAKAIAIgAoAgAgAEEEaigCACABEP0BC8oDAgF+BH8gACgCACEAIAEQ+AFFBEAgARD5AUUEQCAAIAEQgwIPCyMAQYABayIEJAAgACkDACECQYABIQAgBEGAAWohBQJAAkADQCAARQRAQQAhAAwDCyAFQQFrQTBBNyACpyIDQQ9xIgZBCkkbIAZqOgAAIAJCEFoEQCAFQQJrIgVBMEE3IANB/wFxIgNBoAFJGyADQQR2ajoAACAAQQJrIQAgAkKAAlQgAkIIiCECRQ0BDAILCyAAQQFrIQALIABBgQFJDQAgAEGAAUHQ4MAAENYBAAsgAUEBQeDgwABBAiAAIARqQYABIABrEOwBIARBgAFqJAAPCyMAQYABayIEJAAgACkDACECQYABIQAgBEGAAWohBQJAAkADQCAARQRAQQAhAAwDCyAFQQFrQTBB1wAgAqciA0EPcSIGQQpJGyAGajoAACACQhBaBEAgBUECayIFQTBB1wAgA0H/AXEiA0GgAUkbIANBBHZqOgAAIABBAmshACACQoACVCACQgiIIQJFDQEMAgsLIABBAWshAAsgAEGBAUkNACAAQYABQdDgwAAQ1gEACyABQQFB4ODAAEECIAAgBGpBgAEgAGsQ7AEgBEGAAWokAAtuAQF/IwBBEGsiAiQAIAIgACgCACIANgIEIAIgAEEIajYCCCACIABBEGo2AgwgAUGgsMAAQRdB4K3AAEELIAJBBGpBuLDAAEH2rcAAQQsgAkEIakG4sMAAQciwwABBBSACQQxqEPwBIAJBEGokAAuHAQEBfyMAQRBrIgIkAAJ/AkACQAJAAkAgACgCACIAKAIAQQFrDgMBAgMACyABQbqpwABBERD2AQwDCyABQaSpwABBFhD2AQwCCyABQZCpwABBFBD2AQwBCyACIABBBGo2AgwgAUHsqMAAQQpB9qjAAEEKIAJBDGpBgKnAABD6AQsgAkEQaiQAC78CAQN/IAAoAgAhAiABEPgBRQRAIAEQ+QFFBEAgAiABENwBDwtBACEAIwBBgAFrIgMkACACKAIAIQIDQCAAIANqQf8AakEwQTcgAkEPcSIEQQpJGyAEajoAACAAQQFrIQAgAkEPSyACQQR2IQINAAsgAEGAAWoiAkGBAU8EQCACQYABQdDgwAAQ1gEACyABQQFB4ODAAEECIAAgA2pBgAFqQQAgAGsQ7AEgA0GAAWokAA8LQQAhACMAQYABayIDJAAgAigCACECA0AgACADakH/AGpBMEHXACACQQ9xIgRBCkkbIARqOgAAIABBAWshACACQQ9LIAJBBHYhAg0ACyAAQYABaiICQYEBTwRAIAJBgAFB0ODAABDWAQALIAFBAUHg4MAAQQIgACADakGAAWpBACAAaxDsASADQYABaiQAC78BAQF/IAAoAgAhAiMAQRBrIgAkAAJ/AkACQAJAAkACQAJAAkAgAigCAEEBaw4GAQIDBAUGAAsgAUH7ssAAQQgQ9gEMBgsgAUHfrsAAQQoQ9gEMBQsgAUG6qcAAQREQ9gEMBAsgAUGkqcAAQRYQ9gEMAwsgAUHossAAQRMQ9gEMAgsgAUGQqcAAQRQQ9gEMAQsgACACQQRqNgIMIAFB7KjAAEEKQfaowABBCiAAQQxqQYCpwAAQ+gELIABBEGokAAteAQF/IwBBMGsiAiQAIAIgACgCADYCDCACQSRqQQE2AgAgAkIBNwIUIAJBmJvAADYCECACQR02AiwgAiACQShqNgIgIAIgAkEMajYCKCABIAJBEGoQ9wEgAkEwaiQAC5sBAQF/IwBBQGoiAiQAIAAoAgAhACACQRRqQQM2AgAgAkEsakEeNgIAIAJBJGpBHjYCACACIABBGGo2AjQgAiAANgI4IAJCAzcCBCACQdCvwAA2AgAgAkEfNgIcIAIgAEEMajYCPCACIAJBGGo2AhAgAiACQTxqNgIoIAIgAkE4ajYCICACIAJBNGo2AhggASACEPcBIAJBQGskAAsZACAAKAIAIgAoAgAgAEEIaigCACABEIACCwwAIAAoAgAgARCDAguVAgEBfyAAKAIAIQIjAEEwayIAJAACfwJAAkACQAJAIAIoAgBBAWsOAwECAwALIABBHGpBADYCACAAQfSRwAA2AhggAEIBNwIMIABB5KjAADYCCCABIABBCGoQ9wEMAwsgAEEcakEANgIAIABB9JHAADYCGCAAQgE3AgwgAEHIqMAANgIIIAEgAEEIahD3AQwCCyAAQRxqQQA2AgAgAEH0kcAANgIYIABCATcCDCAAQaiowAA2AgggASAAQQhqEPcBDAELIABBHGpBATYCACAAQgE3AgwgAEHop8AANgIIIABBIDYCJCAAIAJBBGo2AiwgACAAQSBqNgIYIAAgAEEsajYCICABIABBCGoQ9wELIABBMGokAAu0AwEBfyAAKAIAIQIjAEEwayIAJAACfwJAAkACQAJAAkACQAJAIAIoAgBBAWsOBgECAwQFBgALIABBHGpBADYCACAAQfSRwAA2AhggAEIBNwIMIABB4LLAADYCCCABIABBCGoQ9wEMBgsgAEEcakEANgIAIABB9JHAADYCGCAAQgE3AgwgAEHMssAANgIIIAEgAEEIahD3AQwFCyAAQRxqQQA2AgAgAEH0kcAANgIYIABCATcCDCAAQeSowAA2AgggASAAQQhqEPcBDAQLIABBHGpBADYCACAAQfSRwAA2AhggAEIBNwIMIABByKjAADYCCCABIABBCGoQ9wEMAwsgAEEcakEANgIAIABB9JHAADYCGCAAQgE3AgwgAEG0ssAANgIIIAEgAEEIahD3AQwCCyAAQRxqQQA2AgAgAEH0kcAANgIYIABCATcCDCAAQaiowAA2AgggASAAQQhqEPcBDAELIABBHGpBATYCACAAQgE3AgwgAEHop8AANgIIIABBIDYCJCAAIAJBBGo2AiwgACAAQSBqNgIYIAAgAEEsajYCICABIABBCGoQ9wELIABBMGokAAsMACAAKAIAIAEQ3AELYgEBfyMAQTBrIgIkACAAKAIAIQAgAkEcakEBNgIAIAJCAjcCDCACQeSwwAA2AgggAkEeNgIkIAIgADYCLCACIAJBIGo2AhggAiACQSxqNgIgIAEgAkEIahD3ASACQTBqJAALVwEBfyMAQSBrIgIkACACIAA2AgQgAkEYaiABQRBqKQIANwMAIAJBEGogAUEIaikCADcDACACIAEpAgA3AwggAkEEakHckcAAIAJBCGoQ3gEgAkEgaiQACwgAIAEgARBUC5oEAQR/IwBBQGoiACQAIABBADYCCCAAQgE3AwAgAEEQaiIEIABBmI/AABDyAQJAIwBBQGoiAiQAQQEhAwJAIAQoAhgiBUGo38AAQQwgBEEcaigCACIEKAIMEQEADQACQCABKAIIIgMEQCACIAM2AgwgAkHnADYCFCACIAJBDGo2AhBBASEDIAJBATYCPCACQgI3AiwgAkG438AANgIoIAIgAkEQajYCOCAFIAQgAkEoahDeAUUNAQwCCyABKAIAIgMgASgCBEEMaigCABEIAELrkZO19tizovQAUg0AIAIgAzYCDCACQegANgIUIAIgAkEMajYCEEEBIQMgAkEBNgI8IAJCAjcCLCACQbjfwAA2AiggAiACQRBqNgI4IAUgBCACQShqEN4BDQELIAEoAgwhASACQSRqQcoANgIAIAJBHGpBygA2AgAgAiABQQxqNgIgIAIgAUEIajYCGCACQekANgIUIAIgATYCECACQQM2AjwgAkIDNwIsIAJBkN/AADYCKCACIAJBEGo2AjggBSAEIAJBKGoQ3gEhAwsgAkFAayQAIANFBEAgACgCCCECIAAoAgAhA0EMQQQQPSIBRQ0BIAEgAjYCCCABIAI2AgQgASADNgIAIAEQACABEKsBIAAoAgQEQCAAKAIAEKsBCyAAQUBrJAAPC0Gwj8AAQTcgAEE4akHoj8AAQcSQwAAQ6QEAC0EMQQQQzgEAC4cBAQV/IwBBIGsiAyQAAn8gAkUEQEEAIQJBAAwBCwJAA0AgA0EIaiABEFYgAygCCCIFRQ0BIAMoAhggAygCFCEHIAMoAgwEQCAFEKsBCyAEQQFqIQQEQCAHEKsBCyACIARHDQALQQAMAQsgBCECQQELIQEgACACNgIEIAAgATYCACADQSBqJAALiQMCCH8BfiMAQUBqIgIkAAJAIAEoAgAQBSIBBEAgASgCACIDRQ0BIAEpAgQhCiABEKsBIAIgCjcCNCACIAM2AjAgAkEYaiIEIAJBMGoiBRBsIAJBEGogAkEgaigCACIGNgIAIAIgAikDGCIKNwMIIAJBKGoiBygCACEBIAJBLGoiCCgCACEJIAIoAiQhAyACQThqIAY2AgAgAiAKNwMwIAQgBRBsIAgoAgAhBCAHKAIAIQUgAigCJCEGIAIoAhwEQCACKAIYEKsBCwJAIARFBEAgAEEANgIAIAEEQCADEKsBCyAFRQ0BIAYQqwEMAQsgACAJNgIUIAAgATYCECAAIAM2AgwgACAENgIIIAAgBTYCBCAAIAY2AgALIAJBQGskAA8LIAJBLGpBADYCACACQfSRwAA2AiggAkIBNwIcIAJBqKbAADYCGCACQRhqQZCnwAAQ1AEACyACQSxqQQA2AgAgAkH0kcAANgIoIAJCATcCHCACQcCnwAA2AhggAkEYakHIp8AAENQBAAt9AQV/IwBBIGsiAyQAAkAgAkUNAANAAkAgA0EIaiABEFYgAygCCCIERQ0AIAMoAhggAygCFCEGIAMoAgwEQCAEEKsBCwRAIAYQqwELIAJBAWsiAg0BDAILC0EBIQcLAkAgB0UEQCAAIAEQVgwBCyAAQQA2AgALIANBIGokAAsJACAAQgA3AgALDQAgACgCACABEFpBAAvNAgECfyMAQRBrIgIkAAJAAn8CQCABQYABTwRAIAJBADYCDCABQYAQTw0BIAIgAUE/cUGAAXI6AA0gAiABQQZ2QcABcjoADEECDAILIAAoAggiAyAAKAIERgRAIAAgAxAQIAAoAgghAwsgACADQQFqNgIIIAAoAgAgA2ogAToAAAwCCyABQYCABE8EQCACIAFBP3FBgAFyOgAPIAIgAUEGdkE/cUGAAXI6AA4gAiABQQx2QT9xQYABcjoADSACIAFBEnZBB3FB8AFyOgAMQQQMAQsgAiABQT9xQYABcjoADiACIAFBDHZB4AFyOgAMIAIgAUEGdkE/cUGAAXI6AA1BAwshASABIABBBGooAgAgACgCCCIDa0sEQCAAIAMgARARIAAoAgghAwsgACgCACADaiACQQxqIAEQiwIaIAAgASADajYCCAsgAkEQaiQAC1oBAX8jAEEgayICJAAgAiAAKAIANgIEIAJBGGogAUEQaikCADcDACACQRBqIAFBCGopAgA3AwAgAiABKQIANwMIIAJBBGpB3JHAACACQQhqEN4BIAJBIGokAAsKACAAIAEQWkEAC8UBAQF/IwBB8ABrIgMkACADIAI2AgwgAyABNgIIIANBJGpBATYCACADQgI3AhQgA0Ggk8AANgIQIANBITYCLCADIANBKGo2AiAgAyADQQhqNgIoIANBADYCOCADQgE3AzAgA0FAayIBIANBMGpBmI/AABDyASADQRBq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CCAEIAM2AgQgBCACNgIAQcAAQQEQPSIDRQ0EQQxBBBA9IgJFDQUgAkLAADcCBCACIAM2AgAgBCACEAciAw0BIAIoAgAiA0UNByACKQIEIQUgAhCrASAAQQhqIAU3AgAgACADNgIEIABBDTYCACAEEKsBDAILQSRBARA9IgJFDQUgAEKkgICAwAQ3AwggACACNgIEIABBAjYCACACQSBqQZijwAAoAAA2AAAgAkEYakGQo8AAKQAANwAAIAJBEGpBiKPAACkAADcAACACQQhqQYCjwAApAAA3AAAgAkH4osAAKQAANwAADAELIAMoAgAiAkUNBSADKQIEIQUgAxCrASABIAU3AgQgASACNgIAIAFBIjYCJCABIAE2AiAgAUEBNgI8IAFCATcCLCABQbijwAA2AiggASABQSBqNgI4IAFBEGogAUEoahDQASAAQQI2AgAgACABKQMQNwIEIABBDGogAUEYaigCADYCACABKAIEBEAgASgCABCrAQsgBBCrAQsgAUFAayQADwtBDEEEEM4BAAtBwABBARDOAQALQQxBBBDOAQALQSRBARDOAQALIAFBPGpBADYCACABQfSRwAA2AjggAUIBNwIsIAFBwKfAADYCKCABQShqQcinwAAQ1AEAC5kDAgJ/AX4jAEFAaiIBJAAgAkEIaigCACEDIAIoAgAhAgJAAkACQEEMQQQQPSIEBEAgBCADNgIIIAQgAzYCBCAEIAI2AgBB2gBBARA9IgNFDQFBDEEEED0iAkUNAiACQtoANwIEIAIgAzYCAAJAIAQgAhAIIgNFBEAgAigCACIDRQ0FIAIpAgQhBSACEKsBIABBCGogBTcCACAAIAM2AgQgAEENNgIADAELIAMoAgAiAkUNBCADKQIEIQUgAxCrASABIAU3AgQgASACNgIAIAFBIjYCJCABIAE2AiAgAUEBNgI8IAFCATcCLCABQdijwAA2AiggASABQSBqNgI4IAFBEGogAUEoahDQASAAQQI2AgAgACABKQMQNwIEIABBDGogAUEYaigCADYCACABKAIEBEAgASgCABCrAQsLIAQQqwEgAUFAayQADwtBDEEEEM4BAAtB2gBBARDOAQALQQxBBBDOAQALIAFBPGpBADYCACABQfSRwAA2AjggAUIBNwIsIAFBwKfAADYCKCABQShqQcinwAAQ1AEAC8cCAQF/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IABBCGpBADYCACAAQQE2AgALzQEBA38jAEEgayICJAACQAJAIAFBAWoiAUUNACAAQQRqKAIAIgNBAXQiBCABIAEgBEkbIgFBCCABQQhLGyIBQX9zQR92IQQCQCADBEAgAkEBNgIYIAIgAzYCFCACIAAoAgA2AhAMAQsgAkEANgIYCyACIAEgBCACQRBqEIIBIAIoAgQhAyACKAIARQRAIAAgAzYCACAAQQRqIAE2AgAMAgsgAkEIaigCACIAQYGAgIB4Rg0BIABFDQAgAyAAEM4BAAsQzwEACyACQSBqJAALzwEBAn8jAEEgayIDJAACQAJAIAEgASACaiIBSw0AIABBBGooAgAiAkEBdCIEIAEgASAESRsiAUEIIAFBCEsbIgFBf3NBH3YhBAJAIAIEQCADQQE2AhggAyACNgIUIAMgACgCADYCEAwBCyADQQA2AhgLIAMgASAEIANBEGoQggEgAygCBCECIAMoAgBFBEAgACACNgIAIABBBGogATYCAAwCCyADQQhqKAIAIgBBgYCAgHhGDQEgAEUNACACIAAQzgEACxDPAQALIANBIGokAAsdACABKAIARQRAAAsgAEHEs8AANgIEIAAgATYCAAtVAQJ/IAEoAgAhAiABQQA2AgACQCACBEAgASgCBCEDQQhBBBA9IgFFDQEgASADNgIEIAEgAjYCACAAQcSzwAA2AgQgACABNgIADwsAC0EIQQQQzgEAC+0DAQF/IwBBMGsiAiQAAn8CQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgACgCAEEBaw4UAQIDBAUGBwgJCgsMDQ4PEBESExQACyACQcK5wAA2AihBIgwUCyACQam5wAA2AihBGQwTCyACQY25wAA2AihBHAwSCyACQfK4wAA2AihBGwwRCyACQdO4wAA2AihBHwwQCyACQa24wAA2AihBJgwPCyACQYW4wAA2AihBKAwOCyACQc63wAA2AihBNwwNCyACQae3wAA2AihBJwwMCyACQe+2wAA2AihBOAwLCyACQbe2wAA2AihBOAwKCyACQYm2wAA2AihBLgwJCyACQfG1wAA2AihBGAwICyACQeK1wAA2AihBDwwHCyACQda1wAA2AihBDAwGCyACQbu1wAA2AihBGwwFCyACQaC1wAA2AihBGwwECyACQdG0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ACAERgRAIAEgBBCDASABKAIIIQQLIAEoAgAgBGpB3AA6AAAgBEEBagwHCyADKAIAIARGBEAgASAEEIMBIAEoAgghBAsgASgCACAEakHcADoAACABIARBAWoiBDYCCCADKAIAIARGBEAgASAEEIMBIAEoAgghBAsgASgCACAEakEiOgAAIARBAWoMBgsgAygCACAERgRAIAEgBBCDASABKAIIIQQLIAEoAgAgBGpB3AA6AAAgASAEQQFqIgQ2AgggAygCACAERgRAIAEgBBCDASABKAIIIQQLIAEoAgAgBGpB4gA6AAAgBEEBagwFCyADKAIAIARGBEAgASAEEIMBIAEoAgghBAsgASgCACAEakHcADoAACABIARBAWoiBDYCCCADKAIAIARGBEAgASAEEIMBIAEoAgghBAsgASgCACAEakH0ADoAACAEQQFqDAQLIAMoAgAgBEYEQCABIAQQgwEgASgCCCEECyABKAIAIARqQdwAOgAAIAEgBEEBaiIENgIIIAMoAgAgBEYEQCABIAQQgwEgASgCCCEECyABKAIAIARqQe4AOgAAIARBAWoMAwsgAygCACAERgRAIAEgBBCDASABKAIIIQQLIAEoAgAgBGpB3AA6AAAgASAEQQFqIgQ2AgggAygCACAERgRAIAEgBBCDASABKAIIIQQLIAEoAgAgBGpB5gA6AAAgBEEBagwCCyADKAIAIARGBEAgASAEEIMBIAEoAgghBAsgASgCACAEakHcADoAACABIARBAWoiBDYCCCADKAIAIARGBEAgASAEEIMBIAEoAgghBAsgASgCACAEakHyADoAACAEQQFqDAELAn8CQAJAIAVBIE8EQCAFQYABSQ0BIAVBgBBPDQIgBiAFQT9xQYABcjoADSAGIAVBBnZBwAFyOgAMQQIMAwsgAygCACAERgRAIAEgBBCDASABKAIIIQQLIAEoAgAgBGpB3AA6AAAgASAEQQFqIgQ2AgggAygCACAERgRAIAEgBBCDASABKAIIIQQLIAEoAgAgBGpB9QA6AAAgASAEQQFqIgQ2AgggAygCACAERgRAIAEgBBCDASABKAIIIQQLIAEoAgAgBGpBMDoAACABIARBAWoiBDYCCCADKAIAIARGBEAgASAEEIMBIAEoAgghBAsgASgCACAEakEwOgAAIAEgBEEBaiIENgIIIAVBD3EiCEEKSSEHIAMoAgAgBEYEQCABIAQQgwEgASgCCCEECyABKAIAIARqIAVB8AFxQQR2QTByOgAAIAEgBEEBaiIENgIIIAMoAgAgBEYEQCABIAQQgwEgASgCCCEECyABKAIAIARqIAhBMHIgCEE3aiAHGzoAACAEQQFqDAMLIAMoAgAgBEYEQCABIAQQgwEgASgCCCEECyABKAIAIARqIAU6AAAgBEEBagwCCyAFQYCABE8EQCAGIAVBP3FBgAFyOgAPIAYgBUESdkHwAXI6AAwgBiAFQQZ2QT9xQYABcjoADiAGIAVBDHZBP3FBgAFyOgANQQQMAQsgBiAFQT9xQYABcjoADiAGIAVBDHZB4AFyOgAMIAYgBUEGdkE/cUGAAXI6AA1BAwshBSAFIAMoAgAgBGtLBEAgASAEIAUQhAEgASgCCCEECyABKAIAIARqIAZBDGogBRCLAhogBCAFagsiBDYCCCACIAlHDQALCyABQQRqKAIAIARGBEAgASAEEIMBIAEoAgghBAsgAEEANgIAIAEgBEEBajYCCCABKAIAIARqQSI6AAAgBkEQaiQAC0wBAX8gAUEEaigCACABKAIIIgJrQQNNBEAgASACQQQQhAEgASgCCCECCyAAQQA2AgAgASACQQRqNgIIIAEoAgAgAmpB7uqx4wY2AAALDQAgACABIAIgAxCXAQtSAQF/IAEoAggiAiABKAIERgRAIAEgAhCDASABKAIIIQILIAAgATYCBCAAQQA2AgAgASACQQFqNgIIIABBCGpBAToAACABKAIAIAJqQdsAOgAAC1IBAX8gASgCCCICIAEoAgRGBEAgASACEIMBIAEoAgghAgsgACABNgIEIABBADYCACABIAJBAWo2AgggAEEIakEBOgAAIAEoAgAgAmpB+wA6AAALngICAn8BfiMAQSBrIgUkACABKAIIIgQgASgCBEYEQCABIAQQgwEgASgCCCEECyABIARBAWo2AgggASgCACAEakH7ADoAACAFQRBqIAEgAiADEJcBAkAgBSgCEEUEQCABKAIIIgQgASgCBEYEQCABIAQQgwEgASgCCCEECyABKAIAIARqQTo6AAAgASAEQQFqIgQ2AgggASgCBCAERgRAIAEgBBCDASABKAIIIQQLIAAgATYCBCAAQQA2AgAgASAEQQFqNgIIIABBCGpBAToAACABKAIAIARqQfsAOgAADAELIAVBCGogBUEcaigCACIBNgIAIAUgBSkCFCIGNwMAIABBDGogATYCACAAIAY3AgQgAEEBNgIACyAFQSBqJAALFgAgACgCACIAKAIAIAAoAgQgARCAAgsdACABKAIARQRAAAsgAEGI1cAANgIEIAAgATYCAAtVAQJ/IAEoAgAhAiABQQA2AgACQCACBEAgASgCBCEDQQhBBBA9IgFFDQEgASADNgIEIAEgAjYCACAAQYjVwAA2AgQgACABNgIADwsAC0EIQQQQzgEAC5QEAQN/IwBBMGsiAiQAAn8CQAJAAkACQCAAKAIEIgMOAwACAwELIwBBEGsiACQAIABB0NbAADYCCCAAQQ42AgQgAEG/1sAANgIAIwBBEGsiASQAIAFBCGogAEEIaigCADYCACABIAApAgA3AwAjAEEQayIAJAAgACABKQIANwMIIABBCGpB9NTAAEEAIAEoAghBARCyAQALIAJBLGpBADYCACACQYjVwAA2AiggAkIBNwIcIAJBoNXAADYCGEEBIAEgAkEYahD3AQ0CGiADQQN0IQMgACgCACEAAkADQCACIAA2AhQgBARAIAJBADYCLCACQYjVwAA2AiggAkIBNwIcIAJBrNXAADYCGCABIAJBGGoQ9wENAgsgAkEBNgIsIAJCAjcCHCACQbTVwAA2AhggAkHMADYCBCACIAI2AiggAiACQRRqNgIAIAEgAkEYahD3AQ0BIABBCGohACAEQQFrIQQgA0EIayIDDQALQQAMAwtBAQwCCyACQSxqQQE2AgAgAkICNwIcIAJBtNXAADYCGCACQc0ANgIEIAIgACgCADYCACACIAI2AiggASACQRhqEPcBDAELIAJBDGpBzQA2AgAgAkEsakECNgIAIAJCAzcCHCACQczVwAA2AhggAkHNADYCBCACIAAoAgAiADYCACACIABBCGo2AgggAiACNgIoIAEgAkEYahD3AQsgAkEwaiQACwwAQsiF+aSet9TbEgshAQF/AkAgACgCBCIBRQ0AIABBCGooAgBFDQAgARCrAQsL1gIBAn8jAEEQayICJAAgACgCACEAAkACfwJAIAFBgAFPBEAgAkEANgIMIAFBgBBPDQEgAiABQT9xQYABcjoADSACIAFBBnZBwAFyOgAMQQIMAgsgACgCCCIDIAAoAgRGBEAgACADEBAgACgCCCEDCyAAIANBAWo2AgggACgCACADaiABOgAADAILIAFBgIAETwRAIAIgAUE/cUGAAXI6AA8gAiABQQZ2QT9xQYABcjoADiACIAFBDHZBP3FBgAFyOgANIAIgAUESdkEHcUHwAXI6AAxBBAwBCyACIAFBP3FBgAFyOgAOIAIgAUEMdkHgAXI6AAwgAiABQQZ2QT9xQYABcjoADUEDCyEBIAEgAEEEaigCACAAKAIIIgNrSwRAIAAgAyABEBEgACgCCCEDCyAAKAIAIANqIAJBDGogARCLAhogACABIANqNgIICyACQRBqJABBAAtaAQF/IwBBIGsiAiQAIAIgACgCADYCBCACQRhqIAFBEGopAgA3AwAgAkEQaiABQQhqKQIANwMAIAIgASkCADcDCCACQQRqQeDWwAAgAkEIahDeASACQSBqJAALkwMBBX8CQAJAAkACQCABQQlPBEBBEEEIELMBIAFLDQEMAgsgABCmASEEDAILQRBBCBCzASEBC0EIQQgQswEhA0EUQQgQswEhAkEQQQgQswEhBUEAQRBBCBCzAUECdGsiBkGAgHwgBSACIANqamtBd3FBA2siAyADIAZLGyABayAATQ0AIAFBECAAQQRqQRBBCBCzAUEFayAASxtBCBCzASIDakEQQQgQswFqQQRrEKYBIgJFDQAgAhDDASEAAkAgAUEBayIEIAJxRQRAIAAhAQwBCyACIARqQQAgAWtxEMMBIQJBEEEIELMBIQQgABC3ASACQQAgASACIABrIARLG2oiASAAayICayEEIAAQugFFBEAgASAEELsBIAAgAhC7ASAAIAIQpwEMAQsgACgCACEAIAEgBDYCBCABIAAgAmo2AgALIAEQugENASABELcBIgJBEEEIELMBIANqTQ0BIAEgAxDAASEAIAEgAxC7ASAAIAIgA2siAxC7ASAAIAMQpwEMAQsgBA8LIAEQwgEgARC6ARoL7SECD38BfiMAQRBrIgskAAJAAkAgAEH1AU8EQEEIQQgQswEhBkEUQQgQswEhBUEQQQgQswEhAUEAQRBBCBCzAUECdGsiAkGAgHwgASAFIAZqamtBd3FBA2siASABIAJLGyAATQ0CIABBBGpBCBCzASEEQdD8wAAoAgBFDQFBACAEayEDAkACQAJ/QQAgBEGAAkkNABpBHyAEQf///wdLDQAaIARB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Gg8LDwsgAkF4cUHU/MAAaiEBAn9BzPzAACgCACIDQQEgAkEDdnQiAnEEQCABKAIIDAELQcz8wAAgAiADcjYCACABCyEDIAEgADYCCCADIAA2AgwgACABNgIMIAAgAzYCCAtpACMAQTBrIgEkAEG0/MAALQAABEAgAUEcakEBNgIAIAFCAjcCDCABQcjXwAA2AgggAUHKADYCJCABIAA2AiwgASABQSBqNgIYIAEgAUEsajYCICABQQhqQfDXwAAQ1AEACyABQTBqJAAL3gEBA38jAEEgayIAJAACQEHI/MAAKAIAQf////8HcQRAQZCAwQAoAgANAQtBvPzAACgCAEG8/MAAQX82AgBFBEBBxPzAACgCACEBQcT8wABBuJvAADYCAEHA/MAAKAIAIQJBwPzAAEEBNgIAQbz8wABBADYCAAJAIAFFDQAgAiABKAIAEQYAIAFBBGooAgBFDQAgAUEIaigCABogAhCrAQsgAEEgaiQADwsACyAAQRxqQQA2AgAgAEH41sAANgIYIABCATcCDCAAQbTYwAA2AgggAEEIakHY2MAAENQBAAuLAgIEfwF+IwBBMGsiAiQAIAFBBGohBCABKAIERQRAIAEoAgAhAyACQRBqIgVBADYCACACQgE3AwggAiACQQhqNgIUIAJBKGogA0EQaikCADcDACACQSBqIANBCGopAgA3AwAgAiADKQIANwMYIAJBFGpB4NbAACACQRhqEN4BGiAEQQhqIAUoAgA2AgAgBCACKQMINwIACyACQSBqIgMgBEEIaigCADYCACABQQxqQQA2AgAgBCkCACEGIAFCATcCBCACIAY3AxhBDEEEED0iAUUEQEEMQQQQzgEACyABIAIpAxg3AgAgAUEIaiADKAIANgIAIABBiNnAADYCBCAAIAE2AgAgAkEwaiQAC60BAQN/IwBBMGsiAiQAIAFBBGohAyABKAIERQRAIAEoAgAhASACQRBqIgRBADYCACACQgE3AwggAiACQQhqNgIUIAJBKGogAUEQaikCADcDACACQSBqIAFBCGopAgA3AwAgAiABKQIANwMYIAJBFGpB4NbAACACQRhqEN4BGiADQQhqIAQoAgA2AgAgAyACKQMINwIACyAAQYjZwAA2AgQgACADNgIAIAJBMGokAAtFAQJ/IAEoAgQhAiABKAIAIQNBCEEEED0iAUUE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BnZBwAFyOgAMQQIMAgsgACgCCCIDIAAoAgRGBEAgACADEIMBIAAoAgghAwsgACADQQFqNgIIIAAoAgAgA2ogAToAAAwCCyABQYCABE8EQCACIAFBP3FBgAFyOgAPIAIgAUEGdkE/cUGAAXI6AA4gAiABQQx2QT9xQYABcjoADSACIAFBEnZBB3FB8AFyOgAMQQQMAQsgAiABQT9xQYABcjoADiACIAFBDHZB4AFyOgAMIAIgAUEGdkE/cUGAAXI6AA1BAwshASABIABBBGooAgAgACgCCCIDa0sEQCAAIAMgARCEASAAKAIIIQMLIAAoAgAgA2ogAkEMaiABEIsCGiAAIAEgA2o2AggLIAJBEGokAEEAC1oBAX8jAEEgayICJAAgAiAAKAIANgIEIAJBGGogAUEQaikCADcDACACQRBqIAFBCGopAgA3AwAgAiABKQIANwMIIAJBBGpB0NnAACACQQhqEN4BIAJBIGokAAtLAQF/IAIgACgCACIAQQRqKAIAIAAoAggiA2tLBEAgACADIAIQhAEgACgCCCEDCyAAKAIAIANqIAEgAhCLAhogACACIANqNgIIQQALGgAgACABQbj8wAAoAgAiAEHSACAAGxECAAALQAEBfyMAQSBrIgAkACAAQRxqQQA2AgAgAEH42cAANgIYIABCATcCDCAAQajawAA2AgggAEEIakGw2sAAENQBAAvpAwEGfyMAQTBrIgUkAAJAAkACQAJAAkAgASgCBCIDBEAgASgCACEHIANBAWtB/////wFxIgNBAWoiBkEHcSEEAn8gA0EHSQRAQQAhAyAHDAELIAdBPGohAiAGQfj///8DcSEGQQAhAwNAIAIoAgAgAkEIaygCACACQRBrKAIAIAJBGGsoAgAgAkEgaygCACACQShrKAIAIAJBMGsoAgAgAkE4aygCACADampqampqamohAyACQUBrIQIgBkEIayIGDQALIAJBPGsLIQIgBARAIAJBBGohAgNAIAIoAgAgA2ohAyACQQhqIQIgBEEBayIEDQALCyABQRRqKAIADQEgAyEEDAMLQQAhAyABQRRqKAIADQFBASECDAQLIAcoAgQNACADQRBJDQILIAMgA2oiBCADSQ0BCyAERQ0AAkAgBEF/SgRAIARBARA9IgJFDQEgBCEDDAMLEM8BAAsgBEEBEM4BAAtBASECQQAhAwsgAEEANgIIIAAgAzYCBCAAIAI2AgAgBSAANgIMIAVBIGogAUEQaikCADcDACAFQRhqIAFBCGopAgA3AwAgBSABKQIANwMQIAVBDGpB0NnAACAFQRBqEN4BBEBBwNrAAEEzIAVBKGpB9NrAAEGc28AAEOkBAAsgBUEwaiQAC2cBAn8gASgCACEDAkACQAJAIAFBCGooAgAiAUUEQEEBIQIMAQsgAUF/TA0BIAFBARA9IgJFDQILIAIgAyABEIsCIQIgACABNgIIIAAgATYCBCAAIAI2AgAPCxDPAQALIAFBARDOAQALUwEBfyMAQRBrIgIkACACIAA2AgggAiAAQQxqNgIMIAFBzNzAAEENQbDcwABBBSACQQhqQaDcwABBtdzAAEEFIAJBDGpBvNzAABD7ASACQRBqJAALDgAgACgCABoDQAwACwAL4QIBAn8jAEEgayICJAAgAkEBOgAYIAIgATYCFCACIAA2AhAgAkHQ38AANgIMIAJB3NzAADYCCCMAQRBrIgEkAAJAIAJBCGoiACgCDCICBEAgACgCCCIDRQ0BIAEgAjYCCCABIAA2AgQgASADNgIAIwBBEGsiACQAIABBCGogAUEIaigCADYCACAAIAEpAgA3AwAjAEEQayIBJAAgACgCACICQRRqKAIAIQMCQAJ/AkACQCACKAIEDgIAAQMLIAMNAkEAIQJB+NbAAAwBCyADDQEgAigCACIDKAIEIQIgAygCAAshAyABIAI2AgQgASADNgIAIAFBvNnAACAAKAIEIgEoAgggACgCCCABLQAQELIBAAsgAUEANgIEIAEgAjYCACABQajZwAAgACgCBCIBKAIIIAAoAgggAS0AEBCyAQALQfjWwABBK0H42MAAENkBAAtB+NbAAEErQejYwAAQ2QEAC28BAX8jAEEwayIDJAAgAyABNgIEIAMgADYCACADQRxqQQI2AgAgA0EsakHKADYCACADQgI3AgwgA0H83sAANgIIIANBygA2AiQgAyADQSBqNgIYIAMgAzYCKCADIANBBGo2AiAgA0EIaiACENQBAAtvAQF/IwBBMGsiAyQAIAMgATYCBCADIAA2AgAgA0EcakECNgIAIANBLGpBygA2AgAgA0ICNwIMIANBkOTAADYCCCADQcoANgIkIAMgA0EgajYCGCADIANBBGo2AiggAyADNgIgIANBCGogAhDUAQALbwEBfyMAQTBrIgMkACADIAE2AgQgAyAANgIAIANBHGpBAjYCACADQSxqQcoANgIAIANCAjcCDCADQbDkwAA2AgggA0HKADYCJCADIANBIGo2AhggAyADQQRqNgIoIAMgAzYCICADQQhqIAIQ1AEAC5AHAQh/AkACQCAAKAIIIgpBAUdBACAAKAIQIgNBAUcbRQRAAkAgA0EBRw0AIAEgAmohCSAAQRRqKAIAQQFqIQcgASEEA0ACQCAEIQMgB0EBayIHRQ0AIAMgCUYNAgJ/IAMsAAAiBUF/SgRAIAVB/wFxIQUgA0EBagwBCyADLQABQT9xIQggBUEfcSEEIAVBX00EQCAEQQZ0IAhyIQUgA0ECagwBCyADLQACQT9xIAhBBnRyIQggBUFwSQRAIAggBEEMdHIhBSADQQNqDAELIARBEnRBgIDwAHEgAy0AA0E/cSAIQQZ0cnIiBUGAgMQARg0DIANBBGoLIgQgBiADa2ohBiAFQYCAxABHDQEMAgsLIAMgCUYNACADLAAAIgRBf0ogBEFgSXIgBEFwSXJFBEAgBEH/AXFBEnRBgIDwAHEgAy0AA0E/cSADLQACQT9xQQZ0IAMtAAFBP3FBDHRycnJBgIDEAEYNAQsCQAJAIAZFDQAgAiAGTQRAQQAhAyACIAZGDQEMAgtBACEDIAEgBmosAABBQEgNAQsgASEDCyAGIAIgAxshAiADIAEgAxshAQsgCkUNAiAAQQxqKAIAIQYCQCACQRBPBEAgASACEPMBIQQMAQsgAkUEQEEAIQQMAQsgAkEDcSEFAkAgAkEBa0EDSQRAQQAhBCABIQMMAQsgAkF8cSEHQQAhBCABIQMDQCAEIAMsAABBv39KaiADLAABQb9/SmogAywAAkG/f0pqIAMsAANBv39KaiEEIANBBGohAyAHQQRrIgcNAAsLIAVFDQADQCAEIAMsAABBv39KaiEEIANBAWohAyAFQQFrIgUNAAsLIAQgBkkEQCAGIARrIgQhBgJAAkACQEEAIAAtACAiAyADQQNGG0EDcSIDQQFrDgIAAQILQQAhBiAEIQMMAQsgBEEBdiEDIARBAWpBAXYhBgsgA0EBaiEDIABBHGooAgAhBCAAQRhqKAIAIQUgACgCBCEAAkADQCADQQFrIgNFDQEgBSAAIAQoAhARAABFDQALQQEPC0EBIQMgAEGAgMQARg0CIAUgASACIAQoAgwRAQANAkEAIQMDQCADIAZGBEBBAA8LIANBAWohAyAFIAAgBCgCEBEAAEUNAAsgA0EBayAGSQ8LDAILIAAoAhggASACIABBHGooAgAoAgwRAQAhAwsgAw8LIAAoAhggASACIABBHGooAgAoAgwRAQALSAEBfyMAQSBrIgMkACADQRRqQQA2AgAgA0Hc3MAANgIQIANCATcCBCADIAE2AhwgAyAANgIYIAMgA0EYajYCACADIAIQ1AEAC28BAX8jAEEwayIDJAAgAyABNgIEIAMgADYCACADQRxqQQI2AgAgA0EsakHKADYCACADQgI3AgwgA0Hk5MAANgIIIANBygA2AiQgAyADQSBqNgIYIAMgA0EEajYCKCADIAM2AiAgA0EIaiACENQBAAslACABIAAtAABBAnQiAEGg/MAAaigCACAAQYz8wABqKAIAENgBCw4AIAA1AgBBASABEIUCC8QCAQN/IwBBgAFrIgQkAAJAAkACQAJAIAEoAgAiAkEQcUUEQCACQSBxDQEgADUCAEEBIAEQhQIhAAwECyAAKAIAIQBBACECA0AgAiAEakH/AGpBMEHXACAAQQ9xIgNBCkkbIANqOgAAIAJBAWshAiAAQQ9LIABBBHYhAA0ACyACQYABaiIAQYEBTw0BIAFBAUHg4MAAQQIgAiAEakGAAWpBACACaxDsASEADAMLIAAoAgAhAEEAIQIDQCACIARqQf8AakEwQTcgAEEPcSIDQQpJGyADajoAACACQQFrIQIgAEEPSyAAQQR2IQANAAsgAkGAAWoiAEGBAU8NASABQQFB4ODAAEECIAIgBGpBgAFqQQAgAmsQ7AEhAAwCCyAAQYABQdDgwAAQ1gEACyAAQYABQdDgwAAQ1gEACyAEQYABaiQAIAAL/wQBCn8jAEEwayIDJAAgA0EkaiABNgIAIANBAzoAKCADQoCAgICABDcDCCADIAA2AiAgA0EANgIYIANBADYCEAJ/AkACQCACKAIIIgpFBEAgAkEUaigCACIARQ0BIAIoAhAhASAAQQN0IQUgAEEBa0H/////AXFBAWohByACKAIAIQADQCAAQQRqKAIAIgQEQCADKAIgIAAoAgAgBCADKAIkKAIMEQEADQQLIAEoAgAgA0EIaiABQQRqKAIAEQAADQMgAUEIaiEBIABBCGohACAFQQhrIgUNAAsMAQsgAkEMaigCACIARQ0AIABBBXQhCyAAQQFrQf///z9xQQFqIQcgAigCACEAA0AgAEEEaigCACIBBEAgAygCICAAKAIAIAEgAygCJCgCDBEBAA0DCyADIAUgCmoiBEEcai0AADoAKCADIARBBGopAgBCIIk3AwggBEEYaigCACEGIAIoAhAhCEEAIQlBACEBAkACQAJAIARBFGooAgBBAWsOAgACAQsgBkEDdCAIaiIMQQRqKAIAQeYARw0BIAwoAgAoAgAhBgtBASEBCyADIAY2AhQgAyABNgIQIARBEGooAgAhAQJAAkACQCAEQQxqKAIAQQFrDgIAAgELIAFBA3QgCGoiBkEEaigCAEHmAEcNASAGKAIAKAIAIQELQQEhCQsgAyABNgIcIAMgCTYCGCAIIAQoAgBBA3RqIgEoAgAgA0EIaiABKAIEEQAADQIgAEEIaiEAIAsgBUEgaiIFRw0ACwsgAigCBCAHSwRAIAMoAiAgAigCACAHQQN0aiIAKAIAIAAoAgQgAygCJCgCDBEBAA0BC0EADAELQQELIANBMGokAAtvAQR/IwBBIGsiAiQAQQEhAwJAIAAgARDdAQ0AIAFBHGooAgAhBCABKAIYIAJBADYCHCACQdzcwAA2AhggAkIBNwIMIAJBwN7AADYCCCAEIAJBCGoQ3gENACAAQQRqIAEQ3QEhAwsgAkEgaiQAIAMLDABCuInPl4nG0fhMC4cGAQh/AkAgAkUNAEEAIAJBB2siBCACIARJGyEJIAFBA2pBfHEgAWshCkEAIQQDQAJAAkACQAJAAkACQAJAAkACQCABIARqLQAAIgdBGHRBGHUiCEEATgRAIAogBGtBA3EgCkF/RnINASAEIAlJDQIMCAtBASEGQQEhAwJAAkACQAJAAkACQAJAAkAgB0H05MAAai0AAEECaw4DAAECDgsgBEEBaiIFIAJJDQZBACEDDA0LQQAhAyAEQQFqIgUgAk8NDCABIAVqLAAAIQUgB0HgAWsiA0UNASADQQ1GDQIMAwsgAiAEQQFqIgNNBEBBACEDDAwLIAEgA2osAAAhBQJAAkACQCAHQfABaw4FAQAAAAIACyAIQQ9qQf8BcUECSwRAQQEhAwwOCyAFQX9MDQlBASEDDA0LIAVB8ABqQf8BcUEwSQ0JDAsLIAVBj39KDQoMCAsgBUFgcUGgf0cNCQwCCyAFQaB/Tg0IDAELAkAgCEEfakH/AXFBDE8EQCAIQX5xQW5HBEBBASEDDAsLIAVBf0wNAUEBIQMMCgsgBUG/f0oNCAwBC0EBIQMgBUFATw0IC0EAIQMgBEECaiIFIAJPDQcgASAFaiwAAEG/f0wNBUEBIQNBAiEGDAcLIAEgBWosAABBv39KDQUMBAsgBEEBaiEEDAcLA0AgASAEaiIDKAIAQYCBgoR4cQ0GIANBBGooAgBBgIGChHhxDQYgCSAEQQhqIgRLDQALDAULQQEhAyAFQUBPDQMLIAIgBEECaiIDTQRAQQAhAwwDCyABIANqLAAAQb9/SgRAQQIhBkEBIQMMAwtBACEDIARBA2oiBSACTw0CIAEgBWosAABBv39MDQBBAyEGQQEhAwwCCyAFQQFqIQQMAwtBASEDCyAAIAQ2AgQgAEEJaiAGOgAAIABBCGogAzoAACAAQQE2AgAPCyACIARNDQADQCABIARqLAAAQQBIDQEgAiAEQQFqIgRHDQALDAILIAIgBEsNAAsLIAAgATYCBCAAQQhqIAI2AgAgAEEANgIAC5ADAgV/An4jAEFAaiIFJABBASEHAkAgAC0ABA0AIAAtAAUhCSAAKAIAIgYoAgAiCEEEcUUEQCAGKAIYQZXgwABBl+DAACAJG0ECQQMgCRsgBkEcaigCACgCDBEBAA0BIAYoAhggASACIAYoAhwoAgwRAQANASAGKAIYQeHfwABBAiAGKAIcKAIMEQEADQEgAyAGIAQoAgwRAAAhBwwBCyAJRQRAIAYoAhhBkODAAEEDIAZBHGooAgAoAgwRAQANASAGKAIAIQgLIAVBAToAFyAFQTRqQfTfwAA2AgAgBSAINgIYIAUgBikCGDcDCCAFIAVBF2o2AhAgBikCCCEKIAYpAhAhCyAFIAYtACA6ADggBSAGKAIENgIcIAUgCzcDKCAFIAo3AyAgBSAFQQhqIgg2AjAgCCABIAIQ6gENACAFQQhqQeHfwABBAhDqAQ0AIAMgBUEYaiAEKAIMEQAADQAgBSgCMEGT4MAAQQIgBSgCNCgCDBEBACEHCyAAQQE6AAUgACAHOgAEIAVBQGskACAAC2MBAX8jAEEQayIDJAAgAyABNgIMIAMgADYCCCMAQSBrIgAkACAAQRRqQQE2AgAgAEIBNwIEIABByN/AADYCACAAQekANgIcIAAgA0EIajYCGCAAIABBGGo2AhAgACACENQBAAsRACABIAAoAgAgACgCBBDYAQtcAQJ/IwBBIGsiAiQAIAFBHGooAgAhAyABKAIYIAJBGGogACgCACIAQRBqKQIANwMAIAJBEGogAEEIaikCADcDACACIAApAgA3AwggAyACQQhqEN4BIAJBIGokAAsWACABIAAoAgAiACgCACAAKAIEENgBCxQAIAAoAgAgASAAKAIEKAIMEQAAC1cBAn8jAEEgayICJAAgAUEcaigCACEDIAEoAhggAkEYaiAAQRBqKQIANwMAIAJBEGogAEEIaikCADcDACACIAApAgA3AwggAyACQQhqEN4BIAJBIGokAAuAAQEBfyMAQUBqIgUkACAFIAE2AgwgBSAANgIIIAUgAzYCFCAFIAI2AhAgBUEsakECNgIAIAVBPGpB6gA2AgAgBUICNwIcIAVB5N/AADYCGCAFQekANgI0IAUgBUEwajYCKCAFIAVBEGo2AjggBSAFQQhqNgIwIAVBGGogBBDUAQALuAUBDH8jAEEwayIFJAAgBUEKNgIoIAVCioCAgBA3AyAgBSACNgIcIAVBADYCGCAFIAI2AhQgBSABNgIQIAUgAjYCDCAFQQA2AgggACgCBCELIAAoAgAhDCAAKAIIIQ0CfwNAAkAgA0UEQAJAIAIgB0kNAANAIAEgB2ohBgJ/IAIgB2siBEEITwRAIAUhCQJAAkACQAJAIAZBA2pBfHEiACAGRg0AIAAgBmsiACAEIAAgBEkbIgNFDQBBACEAQQEhCANAIAAgBmotAABBCkYNBCADIABBAWoiAEcNAAsgAyAEQQhrIgBLDQIMAQsgBEEIayEAQQAhAwsDQAJAIAMgBmoiDigCAEGKlKjQAHMiCEF/cyAIQYGChAhrcUGAgYKEeHENACAOQQRqKAIAQYqUqNAAcyIIQX9zIAhBgYKECGtxQYCBgoR4cQ0AIANBCGoiAyAATQ0BCwsgAyAETQ0AIAMgBEHM48AAENYBAAtBACEIIAMgBEcEQANAIAMgBmotAABBCkYEQCADIQBBASEIDAMLIAQgA0EBaiIDRw0ACwsgBCEACyAJIAA2AgQgCSAINgIAIAUoAgQhACAFKAIADAELQQAhAEEAIARFDQAaA0BBASAAIAZqLQAAQQpGDQEaIAQgAEEBaiIARw0ACyAEIQBBAAtBAUcEQCACIQcMAgsCQCAAIAdqIgBBAWoiB0UgAiAHSXINACAAIAFqLQAAQQpHDQBBACEDIAciBCEADAQLIAIgB08NAAsLQQEhAyACIgAgCiIERw0BC0EADAILAkAgDS0AAARAIAxBjODAAEEEIAsoAgwRAQANAQsgASAKaiEGIAAgCmshCSANIAAgCkcEfyAGIAlqQQFrLQAAQQpGBUEACzoAACAEIQogDCAGIAkgCygCDBEBAEUNAQsLQQELIAVBMGokAAumBgIFfwJ+AkACfwJAIAIoAgAiBUEUTgRAIABC//+D/qbe4RFYBEAgAEL/wdcvVg0CIAUhBAwECyACIAVBEGsiBDYCACABIAVqIgNBBGsgACAAQoCAhP6m3uERgCIAQoCAhP6m3uERfn0iCELkAIAiCULkAIKnQQF0QeLgwABqLwAAOwAAIANBBmsgCEKQzgCAQuQAgqdBAXRB4uDAAGovAAA7AAAgA0EIayAIQsCEPYBC5ACCp0EBdEHi4MAAai8AADsAACADQQprIAhCgMLXL4CnQeQAcEEBdEHi4MAAai8AADsAACADQQxrIAhCgMivoCWAp0HkAHBBAXRB4uDAAGovAAA7AAAgA0EOayAIQoCglKWNHYCnQf//A3FB5ABwQQF0QeLgwABqLwAAOwAAIAEgBGogCEKAgOmDsd4WgKdB/wFxQeQAcEEBdEHi4MAAai8AADsAACAIIAlC5AB+facMAgtBquLAAEEcQcjiwAAQ2QEACyABIAVqIgRBBGsgACAAQoDC1y+AIgBCgMLXL359pyIDQeQAbiIGQeQAcEEBdEHi4MAAai8AADsAACAEQQZrIANBkM4AbkH//wNxQeQAcEEBdEHi4MAAai8AADsAACABIAVBCGsiBGogA0HAhD1uQf8BcUHkAHBBAXRB4uDAAGovAAA7AAAgAyAGQeQAbGsLIQMgASAFakECayADQQF0QeLgwABqLwAAOwAACwJAIACnIgNBj84ATQRAIAQhBQwBCyABIARBBGsiBWogAyADQZDOAG4iA0GQzgBsayIGQf//A3FB5ABuIgdBAXRB4uDAAGovAAA7AAAgASAEakECayAGIAdB5ABsa0H//wNxQQF0QeLgwABqLwAAOwAACwJAIANB//8DcSIEQeMATQRAIAMhBAwBCyABIAVBAmsiBWogAyAEQeQAbiIEQeQAbGtB//8DcUEBdEHi4MAAai8AADsAAAsgBEH//wNxQQpPBEAgAiAFQQJrIgI2AgAgASACaiAEQf//A3FBAXRB4uDAAGovAAA7AAAPCyACIAVBAWsiAjYCACABIAJqIARBMGo6AAALgQYBB38CfyABBEBBK0GAgMQAIAAoAgAiCEEBcSIBGyEKIAEgBWoMAQsgACgCACEIQS0hCiAFQQFqCyEHAkAgCEEEcUUEQEEAIQIMAQsCQCADQRBPBEAgAiADEPMBIQYMAQsgA0UEQAwBCyADQQNxIQkCQCADQQFrQQNJBEAgAiEBDAELIANBfHEhCyACIQEDQCAGIAEsAABBv39KaiABLAABQb9/SmogASwAAkG/f0pqIAEsAANBv39KaiEGIAFBBGohASALQQRrIgsNAAsLIAlFDQADQCAGIAEsAABBv39KaiEGIAFBAWohASAJQQFrIgkNAAsLIAYgB2ohBwsCQAJAIAAoAghFBEBBASEBIABBGGooAgAiByAAQRxqKAIAIgAgCiACIAMQ9AENAQwCCwJAAkACQAJAIAcgAEEMaigCACIGSQRAIAhBCHENBCAGIAdrIgYhB0EBIAAtACAiASABQQNGG0EDcSIBQQFrDgIBAgMLQQEhASAAQRhqKAIAIgcgAEEcaigCACIAIAogAiADEPQBDQQMBQtBACEHIAYhAQwBCyAGQQF2IQEgBkEBakEBdiEHCyABQQFqIQEgAEEcaigCACEGIABBGGooAgAhCCAAKAIEIQACQANAIAFBAWsiAUUNASAIIAAgBigCEBEAAEUNAAtBAQ8LQQEhASAAQYCAxABGDQEgCCAGIAogAiADEPQBDQEgCCAEIAUgBigCDBEBAA0BQQAhAQJ/A0AgByABIAdGDQEaIAFBAWohASAIIAAgBigCEBEAAEUNAAsgAUEBawsgB0khAQwBCyAAKAIEIQsgAEEwNgIEIAAtACAhDEEBIQEgAEEBOgAgIABBGGooAgAiCCAAQRxqKAIAIgkgCiACIAMQ9AENACAGIAdrQQFqIQECQANAIAFBAWsiAUUNASAIQTAgCSgCEBEAAEUNAAtBAQ8LQQEhASAIIAQgBSAJKAIMEQEADQAgACAMOgAgIAAgCzYCBEEADwsgAQ8LIAcgBCAFIAAoAgwRAQAL4wEBAX8jAEEQayICJAAgAkEANgIMIAAgAkEMagJ/IAFBgAFPBEAgAUGAEE8EQCABQYCABE8EQCACIAFBP3FBgAFyOgAPIAIgAUEGdkE/cUGAAXI6AA4gAiABQQx2QT9xQYABcjoADSACIAFBEnZBB3FB8AFyOgAMQQQMAwsgAiABQT9xQYABcjoADiACIAFBDHZB4AFyOgAMIAIgAUEGdkE/cUGAAXI6AA1BAwwCCyACIAFBP3FBgAFyOgANIAIgAUEGdkHAAXI6AAxBAgwBCyACIAE6AAxBAQsQ6gEgAkEQaiQAC1cBAX8jAEEgayICJAAgAiAANgIEIAJBGGogAUEQaikCADcDACACQRBqIAFBCGopAgA3AwAgAiABKQIANwMIIAJBBGpB2OLAACACQQhqEN4BIAJBIGokAAsOACAAKAIAIAEgAhDqAQvmAQEBfyMAQRBrIgIkACAAKAIAIAJBADYCDCACQQxqAn8gAUGAAU8EQCABQYAQTwRAIAFBgIAETwRAIAIgAUE/cUGAAXI6AA8gAiABQQZ2QT9xQYABcjoADiACIAFBDHZBP3FBgAFyOgANIAIgAUESdkEHcUHwAXI6AAxBBAwDCyACIAFBP3FBgAFyOgAOIAIgAUEMdkHgAXI6AAwgAiABQQZ2QT9xQYABcjoADUEDDAILIAIgAUE/cUGAAXI6AA0gAiABQQZ2QcABcjoADEECDAELIAIgAToADEEBCxDqASACQRBqJAALWgEBfyMAQSBrIgIkACACIAAoAgA2AgQgAkEYaiABQRBqKQIANwMAIAJBEGogAUEIaikCADcDACACIAEpAgA3AwggAkEEakHY4sAAIAJBCGoQ3gEgAkEgaiQACzQAIABBAzoAICAAQoCAgICABDcCACAAIAE2AhggAEEANgIQIABBADYCCCAAQRxqIAI2AgAL2AYBCH8CQAJAIABBA2pBfHEiAiAAayIEIAFLIARBBEtyDQAgASAEayIGQQRJDQAgBkEDcSEHQQAhAQJAIAAgAkYNACAEQQNxIQMCQCACIABBf3NqQQNJBEAgACECDAELIARBfHEhCCAAIQIDQCABIAIsAABBv39KaiACLAABQb9/SmogAiwAAkG/f0pqIAIsAANBv39KaiEBIAJBBGohAiAIQQRrIggNAAsLIANFDQADQCABIAIsAABBv39KaiEBIAJBAWohAiADQQFrIgMNAAsLIAAgBGohAAJAIAdFDQAgACAGQXxxaiICLAAAQb9/SiEFIAdBAUYNACAFIAIsAAFBv39KaiEFIAdBAkYNACAFIAIsAAJBv39KaiEFCyAGQQJ2IQQgASAFaiEDA0AgACEBIARFDQIgBEHAASAEQcABSRsiBUEDcSEGIAVBAnQhCAJAIAVB/AFxIgdFBEBBACECDAELIAEgB0ECdGohCUEAIQIDQCAARQ0BIAIgACgCACICQX9zQQd2IAJBBnZyQYGChAhxaiAAQQRqKAIAIgJBf3NBB3YgAkEGdnJBgYKECHFqIABBCGooAgAiAkF/c0EHdiACQQZ2ckGBgoQIcWogAEEMaigCACICQX9zQQd2IAJBBnZyQYGChAhxaiECIABBEGoiACAJRw0ACwsgBCAFayEEIAEgCGohACACQQh2Qf+B/AdxIAJB/4H8B3FqQYGABGxBEHYgA2ohAyAGRQ0ACwJ/QQAgAUUNABogASAHQQJ0aiIBKAIAIgBBf3NBB3YgAEEGdnJBgYKECHEiACAGQQFGDQAaIAAgASgCBCIAQX9zQQd2IABBBnZyQYGChAhxaiIAIAZBAkYNABogACABKAIIIgBBf3NBB3YgAEEGdnJBgYKECHFqCyIAQQh2Qf+BHHEgAEH/gfwHcWpBgYAEbEEQdiADag8LIAFFBEBBAA8LIAFBA3EhAgJAIAFBAWtBA0kEQAwBCyABQXxxIQEDQCADIAAsAABBv39KaiAALAABQb9/SmogACwAAkG/f0pqIAAsAANBv39KaiEDIABBBGohACABQQRrIgENAAsLIAJFDQADQCADIAAsAABBv39KaiEDIABBAWohACACQQFrIgINAAsLIAMLOQACQAJ/IAJBgIDEAEcEQEEBIAAgAiABKAIQEQAADQEaCyADDQFBAAsPCyAAIAMgBCABKAIMEQEAC7YIAQR/IwBB8ABrIgUkACAFIAM2AgwgBSACNgIIAkACQAJAAkAgBQJ/AkACQCABQYECTwRAA0AgACAGaiAGQQFrIgghBkGAAmosAABBv39MDQALIAhBgQJqIgYgAUkNAiABQYECayAIRw0EIAUgBjYCFAwBCyAFIAE2AhQLIAUgADYCEEHc3MAAIQZBAAwBCyAAIAhqQYECaiwAAEG/f0wNASAFIAY2AhQgBSAANgIQQfTmwAAhBkEFCzYCHCAFIAY2AhgCQCABIAJJIgYgASADSXJFBEACfwJAAkAgAiADTQRAAkACQCACRQ0AIAEgAk0EQCABIAJGDQEMAgsgACACaiwAAEFASA0BCyADIQILIAUgAjYCICACIAEiBkkEQCACQQFqIgZBACACQQNrIgMgAiADSRsiA0kNBiAAIAZqIAAgA2prIQYDQCAGQQFrIQYgACACaiACQQFrIgMhAiwAAEFASA0ACyADQQFqIQYLAkAgBkUNACABIAZNBEAgASAGRg0BDAoLIAAgBmosAABBv39MDQkLIAEgBkYNBwJAIAAgBmoiAiwAACIDQX9MBEAgAi0AAUE/cSEAIANBH3EhASADQV9LDQEgAUEGdCAAciEADAQLIAUgA0H/AXE2AiRBAQwECyACLQACQT9xIABBBnRyIQAgA0FwTw0BIAAgAUEMdHIhAAwCCyAFQeQAakHpADYCACAFQdwAakHpADYCACAFQdQAakHKADYCACAFQcQAakEENgIAIAVCBDcCNCAFQdjnwAA2AjAgBUHKADYCTCAFIAVByABqNgJAIAUgBUEYajYCYCAFIAVBEGo2AlggBSAFQQxqNgJQIAUgBUEIajYCSAwICyABQRJ0QYCA8ABxIAItAANBP3EgAEEGdHJyIgBBgIDEAEYNBQsgBSAANgIkQQEgAEGAAUkNABpBAiAAQYAQSQ0AGkEDQQQgAEGAgARJGwshACAFIAY2AiggBSAAIAZqNgIsIAVBxABqQQU2AgAgBUHsAGpB6QA2AgAgBUHkAGpB6QA2AgAgBUHcAGpB6wA2AgAgBUHUAGpB7AA2AgAgBUIFNwI0IAVBrOjAADYCMCAFQcoANgJMIAUgBUHIAGo2AkAgBSAFQRhqNgJoIAUgBUEQajYCYCAFIAVBKGo2AlggBSAFQSRqNgJQIAUgBUEgajYCSAwFCyAFIAIgAyAGGzYCKCAFQcQAakEDNgIAIAVB3ABqQekANgIAIAVB1ABqQekANgIAIAVCAzcCNCAFQZznwAA2AjAgBUHKADYCTCAFIAVByABqNgJAIAUgBUEYajYCWCAFIAVBEGo2AlAgBSAFQShqNgJIDAQLIAMgBkHw6MAAENoBAAsgACABQQAgBiAEEPUBAAtB3NzAAEErIAQQ2QEACyAAIAEgBiABIAQQ9QEACyAFQTBqIAQQ1AEACxkAIAAoAhggASACIABBHGooAgAoAgwRAQALVwECfyMAQSBrIgIkACAAQRxqKAIAIQMgACgCGCACQRhqIAFBEGopAgA3AwAgAkEQaiABQQhqKQIANwMAIAIgASkCADcDCCADIAJBCGoQ3gEgAkEgaiQACw0AIAAtAABBEHFBBHYLDQAgAC0AAEEgcUEFdgvEAQEBfyMAQRBrIgckACAAKAIYIAEgAiAAQRxqKAIAKAIMEQEAIQEgB0EAOgANIAcgAToADCAHIAA2AgggB0EIaiADIAQgBSAGEOIBIQECfyAHLQAMIgAgBy0ADUUNABogAEH/AXEhAkEBIAINABogASgCACIALQAAQQRxRQRAIAAoAhhBm+DAAEECIABBHGooAgAoAgwRAQAMAQsgACgCGEGa4MAAQQEgAEEcaigCACgCDBEBAAsgB0EQaiQAQf8BcUEARwvPAQEBfyMAQRBrIgskACAAKAIYIAEgAiAAQRxqKAIAKAIMEQEAIQEgC0EAOgANIAsgAToADCALIAA2AgggC0EIaiADIAQgBSAGEOIBIAcgCCAJIAoQ4gEhAQJ/IAstAAwiACALLQANRQ0AGiAAQf8BcSECQQEgAg0AGiABKAIAIgAtAABBBHFFBEAgACgCGEGb4MAAQQIgAEEcaigCACgCDBEBAAwBCyAAKAIYQZrgwABBASAAQRxqKAIAKAIMEQEACyALQRBqJABB/wFxQQBHC9UBAQF/IwBBEGsiDiQAIAAoAhggASACIABBHGooAgAoAgwRAQAhASAOQQA6AA0gDiABOgAMIA4gADYCCCAOQQhqIAMgBCAFIAYQ4gEgByAIIAkgChDiASALIAwgDUGElMAAEOIBIQACfyAOLQAMIgEgDi0ADUUNABpBASABDQAaIAAoAgAiAC0AAEEEcUUEQCAAKAIYQZvgwABBAiAAQRxqKAIAKAIMEQEADAELIAAoAhhBmuDAAEEBIABBHGooAgAoAgwRAQALIA5BEGokAEH/AXFBAEcLtgcBDn8CQAJAIAIoAhgiC0EiIAJBHGooAgAiDSgCECIOEQAARQRAAkAgAUUEQAwBCyAAIAFqIQ8gACEHAkADQAJAIAcsAAAiAkF/SgRAIAdBAWohCSACQf8BcSEEDAELIActAAFBP3EhBSACQR9xIQQgAkFfTQRAIARBBnQgBXIhBCAHQQJqIQkMAQsgBy0AAkE/cSAFQQZ0ciEFIAdBA2ohCSACQXBJBEAgBSAEQQx0ciEEDAELIARBEnRBgIDwAHEgCS0AAEE/cSAFQQZ0cnIiBEGAgMQARg0CIAdBBGohCQtBMCEFQYKAxAAhAgJAAn8CQAJAAkACQAJAAkACQCAEDiMIAQEBAQEBAQECBAEBAwEBAQEBAQEBAQEBAQEBAQEBAQEBBQALIARB3ABGDQQLIAQQ/gFFDQQgBEEBcmdBAnZBB3MMBQtB9AAhBQwFC0HyACEFDAQLQe4AIQUMAwsgBCEFDAILQYGAxAAhAiAEIQUgBBD/AQ0BIARBAXJnQQJ2QQdzCyEFIAQhAgsCQAJAIAJBgIDEAGsiCkEDIApBA0kbQQFGDQAgAyAGSw0BAkAgA0UNACABIANNBEAgASADRg0BDAMLIAAgA2osAABBQEgNAgsCQCAGRQ0AIAEgBk0EQCABIAZHDQMMAQsgACAGaiwAAEG/f0wNAgsgCyAAIANqIAYgA2sgDSgCDBEBAARAQQEPC0EFIQgDQCAIIQwgAiEKQYGAxAAhAkHcACEDAkACQAJAAkACQAJAIApBgIDEAGsiEEEDIBBBA0kbQQFrDgMBBQACC0EAIQhB/QAhAyAKIQICQAJAAkAgDEH/AXFBAWsOBQcFAAECBAtBAiEIQfsAIQMMBQtBAyEIQfUAIQMMBAtBBCEIQdwAIQMMAwtBgIDEACECIAUiA0GAgMQARw0DCwJ/QQEgBEGAAUkNABpBAiAEQYAQSQ0AGkEDQQQgBEGAgARJGwsgBmohAwwECyAMQQEgBRshCEEwQdcAIAogBUECdHZBD3EiAkEKSRsgAmohAyAFQQFrQQAgBRshBQsgCiECCyALIAMgDhEAAEUNAAtBAQ8LIAYgB2sgCWohBiAJIgcgD0cNAQwCCwsgACABIAMgBkGM48AAEPUBAAsgA0UEQEEAIQMMAQsgASADTQRAIAEgA0YNAQwECyAAIANqLAAAQb9/TA0DCyALIAAgA2ogASADayANKAIMEQEARQ0BC0EBDwsgC0EiIA4RAAAPCyAAIAEgAyABQZzjwAAQ9QEAC/oCAQV/IABBC3QhBEEgIQJBICEDAkADQAJAAkBBfyACQQF2IAFqIgJBAnRBuPXAAGooAgBBC3QiBSAERyAEIAVLGyIFQQFGBEAgAiEDDAELIAVB/wFxQf8BRw0BIAJBAWohAQsgAyABayECIAEgA0kNAQwCCwsgAkEBaiEBCwJAAkAgAUEfTQRAIAFBAnQhBUHDBSEDIAFBH0cEQCAFQbz1wABqKAIAQRV2IQMLQQAhAiABIAFBAWsiBE8EQCAEQSBPDQIgBEECdEG49cAAaigCAEH///8AcSECCyADIAVBuPXAAGooAgBBFXYiAUF/c2pFDQIgACACayEEIAFBwwUgAUHDBUsbIQIgA0EBayEAQQAhAwNAAkAgASACRwRAIAMgAUG49sAAai0AAGoiAyAETQ0BDAULIAJBwwVB/PvAABDVAQALIAAgAUEBaiIBRw0ACyAAIQEMAgsgAUEgQfz7wAAQ1QEACyAEQSBB3PTAABDVAQALIAFBAXEL2AEAAkAgAEEgSQ0AAkACf0EBIABB/wBJDQAaIABBgIAESQ0BAkAgAEGAgAhPBEAgAEHLpgxrQbXbK0kgAEGe9AtrQeILSXINBCAAQeHXC2tBnxhJIABBop0La0EOSXINBCAAQX5xQZ7wCkYNBCAAQWBxQeDNCkcNAQwECyAAQefuwABBKkG778AAQcABQfvwwABBtgMQhAIPC0EAIABBue4Ka0EHSQ0AGiAAQYCAxABrQfCDdEkLDwsgAEHI6cAAQShBmOrAAEGgAkG47MAAQa8CEIQCDwtBAAsLACACIAAgARDYAQvVAwEHf0EBIQMCQCABKAIYIgZBJyABQRxqKAIAKAIQIgcRAAANAEGCgMQAIQFBMCECAkACfwJAAkACQAJAAkACQAJAIAAoAgAiAA4oCAEBAQEBAQEBAgQBAQMBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBBQALIABB3ABGDQQLIAAQ/gFFDQQgAEEBcmdBAnZBB3MMBQtB9AAhAgwFC0HyACECDAQLQe4AIQIMAwsgACECDAILQYGAxAAhASAAEP8BBEAgACECDAILIABBAXJnQQJ2QQdzCyECIAAhAQtBBSEEA0AgBCEFIAEhAEGBgMQAIQFB3AAhAwJAAkACQAJAAkACQCAAQYCAxABrIghBAyAIQQNJG0EBaw4DAQUAAgtBACEEQf0AIQMgACEBAkACQAJAIAVB/wFxQQFrDgUHBQABAgQLQQIhBEH7ACEDDAULQQMhBEH1ACEDDAQLQQQhBEHcACEDDAMLQYCAxAAhASACIQMgAkGAgMQARw0DCyAGQScgBxEAACEDDAQLIAVBASACGyEEQTBB1wAgACACQQJ0dkEPcSIBQQpJGyABaiEDIAJBAWtBACACGyECCyAAIQELIAYgAyAHEQAARQ0AC0EBDwsgAwsOACAAMQAAQQEgARCFAgsOACAAKQMAQQEgARCFAgvdAgEHf0EBIQkCQAJAIAJFDQAgASACQQF0aiEKIABBgP4DcUEIdiELIABB/wFxIQ0DQCABQQJqIQwgByABLQABIgJqIQggCyABLQAAIgFHBEAgASALSw0CIAghByAMIgEgCkYNAgwBCwJAAkAgByAITQRAIAQgCEkNASADIAdqIQEDQCACRQ0DIAJBAWshAiABLQAAIAFBAWohASANRw0AC0EAIQkMBQsgByAIQajpwAAQ2gEACyAIIARBqOnAABDXAQALIAghByAMIgEgCkcNAAsLIAZFDQAgBSAGaiEDIABB//8DcSEBA0ACQCAFQQFqIQAgBS0AACICQRh0QRh1IgRBAE4EfyAABSAAIANGDQEgBS0AASAEQf8AcUEIdHIhAiAFQQJqCyEFIAEgAmsiAUEASA0CIAlBAXMhCSADIAVHDQEMAgsLQdzcwABBK0G46cAAENkBAAsgCUEBcQvBAgIFfwF+IwBBMGsiBSQAQSchAwJAIABCkM4AVARAIAAhCAwBCwNAIAVBCWogA2oiBEEEayAAIABCkM4AgCIIQpDOAH59pyIGQf//A3FB5ABuIgdBAXRB4uDAAGovAAA7AAAgBEECayAGIAdB5ABsa0H//wNxQQF0QeLgwABqLwAAOwAAIANBBGshAyAAQv/B1y9WIAghAA0ACwsgCKciBEHjAEsEQCADQQJrIgMgBUEJamogCKciBCAEQf//A3FB5ABuIgRB5ABsa0H//wNxQQF0QeLgwABqLwAAOwAACwJAIARBCk8EQCADQQJrIgMgBUEJamogBEEBdEHi4MAAai8AADsAAAwBCyADQQFrIgMgBUEJamogBEEwajoAAAsgAiABQdzcwABBACAFQQlqIANqQScgA2sQ7AEgBUEwaiQACxwAIAEoAhhBhPXAAEEFIAFBHGooAgAoAgwRAQALzgIBA38gACgCAC0AACECIwBBgAFrIgQkAAJAAkACQAJAIAEoAgAiAEEQcUUEQCAAQSBxDQEgAq1C/wGDQQEgARCFAiECDAQLQQAhAANAIAAgBGpB/wBqQTBB1wAgAkEPcSIDQQpJGyADajoAACAAQQFrIQAgAkH/AXEiA0EEdiECIANBD0sNAAsgAEGAAWoiAkGBAU8NASABQQFB4ODAAEECIAAgBGpBgAFqQQAgAGsQ7AEhAgwDC0EAIQADQCAAIARqQf8AakEwQTcgAkEPcSIDQQpJGyADajoAACAAQQFrIQAgAkH/AXEiA0EEdiECIANBD0sNAAsgAEGAAWoiAkGBAU8NASABQQFB4ODAAEECIAAgBGpBgAFqQQAgAGsQ7AEhAgwCCyACQYABQdDgwAAQ1gEACyACQYABQdDgwAAQ1gEACyAEQYABaiQAIAILDAAgACgCACABEN0BC+0EAgZ/An4jAEEgayIDJAACfyAAKAIAIgItAABFBEAgASgCGEHw9MAAQQQgAUEcaigCACgCDBEBAAwBC0EBIQAgAyACQQFqNgIMIAMgASgCGEHs9MAAQQQgAUEcaigCACgCDBEBADoAGCADIAE2AhAgA0EAOgAZIANBADYCFCADQQxqIQcjAEFAaiIBJAAgA0EQaiIEAn8gBC0ACARAIAQoAgQhBUEBDAELIAQoAgQhBSAEKAIAIgIoAgAiBkEEcUUEQEEBIAIoAhhBleDAAEGf4MAAIAUbQQJBASAFGyACQRxqKAIAKAIMEQEADQEaIAcgAkGw4MAAKAIAEQAADAELIAVFBEAgAigCGEGd4MAAQQIgAkEcaigCACgCDBEBAARAQQAhBUEBDAILIAIoAgAhBgsgAUEBOgAXIAFBNGpB9N/AADYCACABIAY2AhggASACKQIYNwMIIAEgAUEXajYCECACKQIIIQggAikCECEJIAEgAi0AIDoAOCABIAIoAgQ2AhwgASAJNwMoIAEgCDcDICABIAFBCGo2AjBBASAHIAFBGGpBsODAACgCABEAAA0AGiABKAIwQZPgwABBAiABKAI0KAIMEQEACzoACCAEIAVBAWo2AgQgAUFAayQAIAQhAiADLQAYIQECQCADKAIUIgRFBEAgASEADAELIAENACACKAIAIQECQCAEQQFHDQAgAy0AGUUNACABLQAAQQRxDQAgASgCGEGg4MAAQQEgAUEcaigCACgCDBEBAA0BCyABKAIYQbzewABBASABQRxqKAIAKAIMEQEAIQALIABB/wFxQQBHCyADQSBqJAALnAEBAn8gAkEPSwRAIABBACAAa0EDcSIDaiEEIAMEQANAIAAgAToAACAAQQFqIgAgBEkNAAsLIAQgAiADayICQXxxIgNqIQAgA0EBTgRAIAFB/wFxQYGChAhsIQMDQCAEIAM2AgAgBEEEaiIEIABJDQALCyACQQNxIQILIAIEQCAAIAJqIQIDQCAAIAE6AAAgAEEBaiIAIAJJDQALCwuzAgEHfwJAIAIiBEEPTQRAIAAhAgwBCyAAQQAgAGtBA3EiA2ohBSADBEAgACECIAEhBgNAIAIgBi0AADoAACAGQQFqIQYgAkEBaiICIAVJDQALCyAFIAQgA2siCEF8cSIHaiECAkAgASADaiIDQQNxIgQEQCAHQQFIDQEgA0F8cSIGQQRqIQFBACAEQQN0IglrQRhxIQQgBigCACEGA0AgBSAGIAl2IAEoAgAiBiAEdHI2AgAgAUEEaiEBIAVBBGoiBSACSQ0ACwwBCyAHQQFIDQAgAyEBA0AgBSABKAIANgIAIAFBBGohASAFQQRqIgUgAkkNAAsLIAhBA3EhBCADIAdqIQELIAQEQCACIARqIQMDQCACIAEtAAA6AAAgAUEBaiEBIAJBAWoiAiADSQ0ACwsgAAtoAQV+IAAgA0L/////D4MiBCABQv////8PgyIFfiIGIAQgAUIgiCIHfiIEIAUgA0IgiCIIfnwiAUIghnwiBTcDACAAIAUgBlStIAcgCH4gASAEVK1CIIYgAUIgiIR8fCACIAN+fDcDCAtDAQN/AkAgAkUNAANAIAAtAAAiBCABLQAAIgVGBEAgAEEBaiEAIAFBAWohASACQQFrIgINAQwCCwsgBCAFayEDCyADCwv0ewUAQYCAwAALwT5hdHRlbXB0IHRvIGFkZCB3aXRoIG92ZXJmbG93Q29pbmRlbm9tYW1vdW50AAUAAAAAAAAAAQAAAAYAAAAHAAAACAAAAAkAAAAFAAAAAAAAAAEAAAAKAAAACwAAAAwAAAANAAAADgAAAA8AAAAQAAAAEQAAAAUAAAAAAAAAAQAAABIAAABibG9ja3RyYW5zYWN0aW9uY29udHJhY3RoZWlnaHR0aW1lY2hhaW5faWRzZW5kZXJmdW5kc2FkZHJlc3NpbmRleGNhbGxlZCBgUmVzdWx0Ojp1bndyYXAoKWAgb24gYW4gYEVycmAgdmFsdWUTAAAAIAAAAAgAAAAUAAAAL1VzZXJzL2RlYXJrYW5lLy5jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL2Nvc213YXNtLXN0ZC0xLjEuOS9zcmMvZXhwb3J0cy5ycwAAAAABEABhAAAAjQAAAA0AAAAAARAAYQAAAG8AAAANAAAAAAEQAGEAAADqAAAADQAAAHdhc21jdXN0b21iYW5rQmFua01zZ2J1cm5zZW5kdG9fYWRkcmVzc1dhc21Nc2djbGVhcl9hZG1pbmNvbnRyYWN0X2FkZHJ1cGRhdGVfYWRtaW5hZG1pbm1pZ3JhdGVuZXdfY29kZV9pZG1zZ2luc3RhbnRpYXRlY29kZV9pZGxhYmVsZXhlY3V0ZVN1Yk1zZ2dhc19saW1pdFJlcGx5T25uZXZlcnN1Y2Nlc3NlcnJvcmFsd2F5c29rRW1wdHlFdmVudHR5cGVhdHRyaWJ1dGVzQXR0cmlidXRla2V5dmFsdWVSZXNwb25zZWV2ZW50c0NvbnRyYWN0VmVyc2lvbnZlcnNpb25jb250cmFjdF9pbmZvABUAAAAMAAAABAAAABYAAAAXAAAAGAAAAGEgRGlzcGxheSBpbXBsZW1lbnRhdGlvbiByZXR1cm5lZCBhbiBlcnJvciB1bmV4cGVjdGVkbHkABQAAAAAAAAABAAAAGQAAAC9ydXN0Yy84OTdlMzc1NTNiYmE4YjQyNzUxYzY3NjU4OTY3ODg5ZDExZWNkMTIwL2xpYnJhcnkvYWxsb2Mvc3JjL3N0cmluZy5ycwAIAxAASwAAAM4JAAAJAAAAY3dfY291bnRlcjo6bXNnOjpFeGVjdXRlTXNnY3dfY291bnRlcjo6bXNnOjpHZXRDb3VudFJlc3BvbnNlY3dfY291bnRlcjo6bXNnOjpRdWVyeU1zZ2Nvc213YXNtX3N0ZDo6cmVzdWx0czo6Y29udHJhY3RfcmVzdWx0OjpDb250cmFjdFJlc3VsdDxjb3Ntd2FzbV9zdGQ6OnJlc3VsdHM6OnJlc3BvbnNlOjpSZXNwb25zZT5jb3Ntd2FzbV9zdGQ6OnJlc3VsdHM6OmNvbnRyYWN0X3Jlc3VsdDo6Q29udHJhY3RSZXN1bHQ8Y29zbXdhc21fc3RkOjpiaW5hcnk6OkJpbmFyeT5jb3Ntd2FzbV9zdGQ6OnR5cGVzOjpNZXNzYWdlSW5mb2Nvc213YXNtX3N0ZDo6dHlwZXM6OkVudmN3X2NvdW50ZXI6OnN0YXRlOjpTdGF0ZWN3X2NvdW50ZXI6Om1zZzo6SW5zdGFudGlhdGVNc2djdzI6OkNvbnRyYWN0VmVyc2lvbgAAAAUAAAAEAAAABAAAABoAAAAbAAAAHAAAAG1pc3NpbmcgZmllbGQgYGAMBRAADwAAABsFEAABAAAAdW5rbm93biBmaWVsZCBgYCwgZXhwZWN0ZWQgACwFEAAPAAAAOwUQAAwAAABgLCB0aGVyZSBhcmUgbm8gZmllbGRzAAAsBRAADwAAAFgFEAAWAAAAZHVwbGljYXRlIGZpZWxkIGAAAACABRAAEQAAABsFEAABAAAAdW5rbm93biB2YXJpYW50IGAAAACkBRAAEQAAADsFEAAMAAAAaW52YWxpZCBVaW50NjQgJycgLSDIBRAAEAAAANgFEAAEAAAAaW52YWxpZCBVaW50MTI4ICcAAADsBRAAEQAAANgFEAAEAAAAdWxsc3RhdGVhY3Rpb25pbmNyZW1lbnRzcmMvY29udHJhY3QucnMAACcGEAAPAAAANAAAAA0AAAByZXNldGNyYXRlcy5pbzpjdy1jb3VudGVyMC4xLjBtZXRob2Rvd25lcmNvdW50VW5hdXRob3JpemVkAAB2BhAADAAAAAwFEAAAAAAAcQYQAAUAAAAeBhAACQAAAEgGEAAFAAAAZ2V0X2NvdW50AAAArAYQAAkAAABHZXRDb3VudFJlc3BvbnNlU3RhdGUvcnVzdGMvODk3ZTM3NTUzYmJhOGI0Mjc1MWM2NzY1ODk2Nzg4OWQxMWVjZDEyMC9saWJyYXJ5L2NvcmUvc3JjL2l0ZXIvYWRhcHRlcnMvZW51bWVyYXRlLnJz1QYQAFsAAAAwAAAACQAAAGF0dGVtcHQgdG8gYWRkIHdpdGggb3ZlcmZsb3cAAAAAYXR0ZW1wdCB0byBtdWx0aXBseSB3aXRoIG92ZXJmbG93AAAAKAAAAAgAAAAEAAAAKQAAACoAAAArAAAADAAAAAQAAAAsAAAALQAAAC4AAABhIERpc3BsYXkgaW1wbGVtZW50YXRpb24gcmV0dXJuZWQgYW4gZXJyb3IgdW5leHBlY3RlZGx5ACgAAAAAAAAAAQAAABkAAAAvcnVzdGMvODk3ZTM3NTUzYmJhOGI0Mjc1MWM2NzY1ODk2Nzg4OWQxMWVjZDEyMC9saWJyYXJ5L2FsbG9jL3NyYy9zdHJpbmcucnMA+AcQAEsAAADOCQAACQAAAGNvc213YXNtX3N0ZDo6cmVzdWx0czo6c3lzdGVtX3Jlc3VsdDo6U3lzdGVtUmVzdWx0PGNvc213YXNtX3N0ZDo6cmVzdWx0czo6Y29udHJhY3RfcmVzdWx0OjpDb250cmFjdFJlc3VsdDxjb3Ntd2FzbV9zdGQ6OmJpbmFyeTo6QmluYXJ5Pj4oAAAABAAAAAQAAAAvAAAAMAAAADEAAABpbnRlcm5hbCBlcnJvcjogZW50ZXJlZCB1bnJlYWNoYWJsZSBjb2RlOiAAAPQIEAAqAAAAL3J1c3RjLzg5N2UzNzU1M2JiYThiNDI3NTFjNjc2NTg5Njc4ODlkMTFlY2QxMjAvbGlicmFyeS9jb3JlL3NyYy9pdGVyL3RyYWl0cy9hY2N1bS5ycwAAACgJEABVAAAAjQAAAAEAAABtaXNzaW5nIGZpZWxkIGBgkAkQAA8AAACfCRAAAQAAAGR1cGxpY2F0ZSBmaWVsZCBgAAAAsAkQABEAAACfCRAAAQAAAHVua25vd24gdmFyaWFudCBgYCwgZXhwZWN0ZWQgAAAA1AkQABEAAADlCRAADAAAACgAAAAEAAAABAAAADIAAAAvVXNlcnMvZGVhcmthbmUvLmNhcmdvL3JlZ2lzdHJ5L3NyYy9naXRodWIuY29tLTFlY2M2Mjk5ZGI5ZWM4MjMvYmFzZTY0LTAuMTMuMC9zcmMvZGVjb2RlLnJzABQKEABbAAAAbgAAAC8AAABhdHRlbXB0IHRvIHN1YnRyYWN0IHdpdGggb3ZlcmZsb3cAAAAUChAAWwAAAAMBAAA3AAAAFAoQAFsAAAADAQAAJAAAABQKEABbAAAABAEAACkAAAAUChAAWwAAACEBAAARAAAAFAoQAFsAAAAqAQAAKQAAABQKEABbAAAAKgEAABYAAAAUChAAWwAAAC4BAAApAAAAFAoQAFsAAAAuAQAAKAAAABQKEABbAAAALQEAABoAAAAUChAAWwAAADMBAAARAAAAFAoQAFsAAABBAQAADgAAABQKEABbAAAARAEAACcAAAAUChAAWwAAAEQBAAASAAAAFAoQAFsAAABHAQAACQAAABQKEABbAAAAWAEAABMAAAAUChAAWwAAAGYBAAApAAAAFAoQAFsAAAB4AQAADQAAABQKEABbAAAAggEAABEAAAAUChAAWwAAAIoBAAAVAAAAFAoQAFsAAACOAQAAMQAAAEltcG9zc2libGU6IG11c3Qgb25seSBoYXZlIDAgdG8gOCBpbnB1dCBieXRlcyBpbiBsYXN0IGNodW5rLCB3aXRoIG5vIGludmFsaWQgbGVuZ3Roc+QLEABUAAAAFAoQAFsAAACdAQAADgAAABQKEABbAAAAqAEAAA0AAAAUChAAWwAAALEBAAAJAAAAT3ZlcmZsb3cgd2hlbiBjYWxjdWxhdGluZyBvdXRwdXQgYnVmZmVyIGxlbmd0aAAAFAoQAFsAAACTAAAAIAAAABQKEABbAAAAJwIAAAUAAABJbnZhbGlkIFVURjgrAAAAFAAAAAQAAAAzAAAAL1VzZXJzL2RlYXJrYW5lLy5jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL2Jhc2U2NC0wLjEzLjAvc3JjL2VuY29kZS5ycwDcDBAAWwAAADQAAAAFAAAAaW50ZWdlciBvdmVyZmxvdyB3aGVuIGNhbGN1bGF0aW5nIGJ1ZmZlciBzaXplAAAA3AwQAFsAAAAvAAAAEQAAACgAAAAIAAAABAAAADQAAAD0CBAAAAAAAGludmFsaWQgYmFzZTY0OiCgDRAAEAAAACgAAAAAAAAAAQAAADUAAAA2AAAANgAAAC9Vc2Vycy9kZWFya2FuZS8uY2FyZ28vcmVnaXN0cnkvc3JjL2dpdGh1Yi5jb20tMWVjYzYyOTlkYjllYzgyMy9jb3Ntd2FzbS1zdGQtMS4xLjkvc3JjL3NlY3Rpb25zLnJzAADQDRAAYgAAABoAAAAQAAAA0A0QAGIAAAAaAAAABQAAANANEABiAAAAOQAAABgAAABDYW5ub3QgcmVhZCBzZWN0aW9uIGxlbmd0aAAAZA4QABoAAADQDRAAYgAAADcAAAAJAAAAVEw7RFI6IFZhbHVlIG11c3Qgbm90IGJlIGVtcHR5IGluIFN0b3JhZ2U6OnNldCBidXQgaW4gbW9zdCBjYXNlcyB5b3UgY2FuIHVzZSBTdG9yYWdlOjpyZW1vdmUgaW5zdGVhZC4gTG9uZyBzdG9yeTogR2V0dGluZyBlbXB0eSB2YWx1ZXMgZnJvbSBzdG9yYWdlIGlzIG5vdCB3ZWxsIHN1cHBvcnRlZCBhdCB0aGUgbW9tZW50LiBTb21lIG9mIG91ciBpbnRlcm5hbCBpbnRlcmZhY2VzIGNhbm5vdCBkaWZmZXJlbnRpYXRlIGJldHdlZW4gYSBub24tZXhpc3RlbnQga2V5IGFuZCBhbiBlbXB0eSB2YWx1ZS4gUmlnaHQgbm93LCB5b3UgY2Fubm90IHJlbHkgb24gdGhlIGJlaGF2aW91ciBvZiBlbXB0eSB2YWx1ZXMuIFRvIHByb3RlY3QgeW91IGZyb20gdHJvdWJsZSBsYXRlciBvbiwgd2Ugc3RvcCBoZXJlLiBTb3JyeSBmb3IgdGhlIGluY29udmVuaWVuY2UhIFdlIGhpZ2hseSB3ZWxjb21lIHlvdSB0byBjb250cmlidXRlIHRvIENvc21XYXNtLCBtYWtpbmcgdGhpcyBtb3JlIHNvbGlkIG9uZSB3YXkgb3IgdGhlIG90aGVyLpgOEAAIAgAAL1VzZXJzL2RlYXJrYW5lLy5jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL2Nvc213YXNtLXN0ZC0xLjEuOS9zcmMvaW1wb3J0cy5ycwAAAKgQEABhAAAAawAAAA0AAAAoAAAABAAAAAQAAAA3AAAAOAAAADkAAAA6AAAAaW5wdXQgdG9vIGxvbmcgZm9yIGFkZHJfdmFsaWRhdGVhZGRyX3ZhbGlkYXRlIGVycm9yZWQ6IABYERAAFwAAAGlucHV0IHRvbyBsb25nIGZvciBhZGRyX2Nhbm9uaWNhbGl6ZWFkZHJfY2Fub25pY2FsaXplIGVycm9yZWQ6IACcERAAGwAAAGFkZHJfaHVtYW5pemUgZXJyb3JlZDogAMAREAAXAAAATWVzc2FnZVRvb0xvbmcgbXVzdCBub3QgaGFwcGVuLiBUaGlzIGlzIGEgYnVnIGluIHRoZSBWTS7gERAAOAAAAKgQEABhAAAACAEAABIAAACoEBAAYQAAACUBAAASAAAASW52YWxpZEhhc2hGb3JtYXQgbXVzdCBub3QgaGFwcGVuLiBUaGlzIGlzIGEgYnVnIGluIHRoZSBWTS4AQBIQADsAAACoEBAAYQAAAD8BAAASAAAARXJyb3IgY29kZSAyIHVudXNlZCBzaW5jZSBDb3NtV2FzbSAwLjE1LiBUaGlzIGlzIGEgYnVnIGluIHRoZSBWTS4AAACUEhAAQQAAAKgQEABhAAAAPgEAABIAAACoEBAAYQAAAF8BAAASAAAAqBAQAGEAAABeAQAAEgAAAFJlZ2lvbiBwb2ludGVyIGlzIG51bGwAABATEAAWAAAAL1VzZXJzL2RlYXJrYW5lLy5jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL2Nvc213YXNtLXN0ZC0xLjEuOS9zcmMvbWVtb3J5LnJzMBMQAGAAAAA5AAAABQAAAFJlZ2lvbiBzdGFydHMgYXQgbnVsbCBwb2ludGVyAAAAoBMQAB0AAAAwExAAYAAAAD8AAAAFAAAAVW5rbm93biBlcnJvcjogANgTEAAPAAAASW52YWxpZCByZWNvdmVyeSBwYXJhbWV0ZXIuIFN1cHBvcnRlZCB2YWx1ZXM6IDAgYW5kIDEuAADwExAANgAAAEludmFsaWQgc2lnbmF0dXJlIGZvcm1hdDAUEAAYAAAASW52YWxpZCBoYXNoIGZvcm1hdABQFBAAEwAAAFVua25vd25FcnJlcnJvcl9jb2RlKAAAAAQAAAAEAAAAOwAAAEludmFsaWRSZWNvdmVyeVBhcmFtSW52YWxpZFNpZ25hdHVyZUZvcm1hdEludmFsaWRIYXNoRm9ybWF0Q29udmVyc2lvbiBlcnJvcjogAAAAyxQQABIAAABEaXZpZGUgYnkgemVybzog6BQQABAAAABPdmVyZmxvdzogAAAAFRAACgAAAEVycm9yIHNlcmlhbGl6aW5nIHR5cGUgOiAAAAAUFRAAFwAAACsVEAACAAAARXJyb3IgcGFyc2luZyBpbnRvIHR5cGUgQBUQABgAAAArFRAAAgAAACBub3QgZm91bmQAAPQIEAAAAAAAaBUQAAoAAABDYW5ub3QgZGVjb2RlIFVURjggYnl0ZXMgaW50byBzdHJpbmc6IAAAhBUQACYAAABJbnZhbGlkIGhleCBzdHJpbmc6ILQVEAAUAAAASW52YWxpZCBkYXRhIHNpemU6IGV4cGVjdGVkPSBhY3R1YWw90BUQABwAAADsFRAACAAAAEludmFsaWQgQmFzZTY0IHN0cmluZzogAAQWEAAXAAAAR2VuZXJpYyBlcnJvcjogACQWEAAPAAAAUmVjb3ZlciBwdWJrZXkgZXJyb3I6IAAAPBYQABYAAABWZXJpZmljYXRpb24gZXJyb3I6IFwWEAAUAAAAQ29udmVyc2lvbk92ZXJmbG93c291cmNlKAAAAAQAAAAEAAAAPAAAAERpdmlkZUJ5WmVybygAAAAEAAAABAAAAD0AAABPdmVyZmxvdygAAAAEAAAABAAAAD4AAABTZXJpYWxpemVFcnJzb3VyY2VfdHlwZW1zZ1BhcnNlRXJydGFyZ2V0X3R5cGVOb3RGb3VuZGtpbmRJbnZhbGlkVXRmOEludmFsaWRIZXhJbnZhbGlkRGF0YVNpemVleHBlY3RlZAAAACgAAAAEAAAABAAAAD8AAABhY3R1YWxJbnZhbGlkQmFzZTY0R2VuZXJpY0VyclJlY292ZXJQdWJrZXlFcnIAAAAoAAAABAAAAAQAAABAAAAAVmVyaWZpY2F0aW9uRXJyACgAAAAEAAAABAAAAEEAAABTaGxTaHJQb3dNdWxTdWJBZGRDYW5ub3QgIHdpdGggIGFuZCC+FxAABwAAAMUXEAAGAAAAyxcQAAUAAABPdmVyZmxvd0Vycm9yb3BlcmF0aW9uAAAoAAAABAAAAAQAAAAdAAAAb3BlcmFuZDFvcGVyYW5kMkNvbnZlcnNpb25PdmVyZmxvd0Vycm9yACgAAAAEAAAABAAAAEIAAAB2YWx1ZUNhbm5vdCBkZXZpZGUgIGJ5IHplcm8ATRgQAA4AAABbGBAACAAAAERpdmlkZUJ5WmVyb0Vycm9yb3BlcmFuZGludmFsaWRfcmVxdWVzdGludmFsaWRfcmVzcG9uc2Vub19zdWNoX2NvbnRyYWN0dW5rbm93bnVuc3VwcG9ydGVkX3JlcXVlc3QAAACMGBAADwAAAJsYEAAQAAAAqxgQABAAAAC7GBAABwAAAMIYEAATAAAAYWRkcmVycm9ycmVzcG9uc2VyZXF1ZXN0SW52YWxpZCBwdWJsaWMga2V5IGZvcm1hdAAAABgZEAAZAAAAR2VuZXJpYyBlcnJvcgAAADwZEAANAAAAQmF0Y2ggZXJyb3IAVBkQAAsAAABJbnZhbGlkUHVia2V5Rm9ybWF0QmF0Y2hFcnJvawAAAIMZEAACAAAABBkQAAUAAAC7FxAAuBcQALUXEACyFxAArxcQAKwXEABFAAAACAAAAAQAAABGAAAARwAAAEUAAAAIAAAABAAAAEgAAADEGRAAAAAAAEpTT04gaGFzIGEgY29tbWEgYWZ0ZXIgdGhlIGxhc3QgdmFsdWUgaW4gYW4gYXJyYXkgb3IgbWFwLkpTT04gaGFzIG5vbi13aGl0ZXNwYWNlIHRyYWlsaW5nIGNoYXJhY3RlcnMgYWZ0ZXIgdGhlIHZhbHVlLkZvdW5kIGEgbG9uZSBzdXJyb2dhdGUsIHdoaWNoIGNhbiBleGlzdCBpbiBKU09OIGJ1dCBjYW5ub3QgYmUgZW5jb2RlZCB0byBVVEYtOC5PYmplY3Qga2V5IGlzIG5vdCBhIHN0cmluZy5JbnZhbGlkIHVuaWNvZGUgY29kZSBwb2ludC5JbnZhbGlkIHR5cGVJbnZhbGlkIG51bWJlci5JbnZhbGlkIGVzY2FwZSBzZXF1ZW5jZS5FeHBlY3RlZCB0aGlzIGNoYXJhY3RlciB0byBzdGFydCBhIEpTT04gdmFsdWUuRXhwZWN0ZWQgdG8gcGFyc2UgZWl0aGVyIGEgYHRydWVgLCBgZmFsc2VgLCBvciBhIGBudWxsYC5FeHBlY3RlZCB0aGlzIGNoYXJhY3RlciB0byBiZSBlaXRoZXIgYSBgJywnYCBvciBhIGAnfSdgLkV4cGVjdGVkIGEgbG93IHN1cnJvZ2F0ZSAoREMwMOKAk0RGRkYpLkV4cGVjdGVkIHRoaXMgY2hhcmFjdGVyIHRvIGJlIGVpdGhlciBhIGAnLCdgIG9yYSBgJ10nYC5FeHBlY3RlZCBhIGhpZ2ggc3Vycm9nYXRlIChEODAw4oCTREJGRikuRXhwZWN0ZWQgdGhpcyBjaGFyYWN0ZXIgdG8gYmUgYSBgJzonYC5FT0Ygd2hpbGUgcGFyc2luZyBhIEpTT04gdmFsdWUuRU9GIHdoaWxlIHBhcnNpbmcgYSBzdHJpbmcuRU9GIHdoaWxlIHBhcnNpbmcgYW4gb2JqZWN0LkVPRiB3aGlsZSBwYXJzaW5nIGEgbGlzdC5Db250cm9sIGNoYXJhY3RlciBmb3VuZCBpbiBzdHJpbmcuL1VzZXJzL2RlYXJrYW5lLy5jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL3NlcmRlLWpzb24td2FzbS0wLjQuMS9zcmMvZGUvdW5lc2NhcGUucnPkHBAAaAAAACUAAAAVAAAAAAAAAGF0dGVtcHQgdG8gYWRkIHdpdGggb3ZlcmZsb3fkHBAAaAAAADMAAAApAAAAAAAAAGF0dGVtcHQgdG8gc3VidHJhY3Qgd2l0aCBvdmVyZmxvd05vbi1oZXggQVNDSUkgY2hhcmFjdGVyIGZvdW5kAADkHBAAaAAAAJkAAAAOAAAAL1VzZXJzL2RlYXJrYW5lLy5jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL3NlcmRlLWpzb24td2FzbS0wLjQuMS9zcmMvZGUvbW9kLnJzAOAdEABjAAAAJAAAAAkAAADgHRAAYwAAAH0AAAAiAAAA4B0QAGMAAACBAAAALAAAAEJ1ZmZlciBpcyBmdWxsAAB0HhAADgAAAC9Vc2Vycy9kZWFya2FuZS8uY2FyZ28vcmVnaXN0cnkvc3JjL2dpdGh1Yi5jb20tMWVjYzYyOTlkYjllYzgyMy9zZXJkZS1qc29uLXdhc20tMC40LjEvc3JjL3Nlci9tb2QucnOMHhAAZAAAALUAAAAJAAAAjB4QAGQAAADXAAAACQAAAGludGVybmFsIGVycm9yOiBlbnRlcmVkIHVucmVhY2hhYmxlIGNvZGU6IAAAEB8QACoAQdC+wAALIWF0dGVtcHQgdG8gc3VidHJhY3Qgd2l0aCBvdmVyZmxvdwBBgL/AAAv0JmF0dGVtcHQgdG8gYWRkIHdpdGggb3ZlcmZsb3cvVXNlcnMvZGVhcmthbmUvLmNhcmdvL3JlZ2lzdHJ5L3NyYy9naXRodWIuY29tLTFlY2M2Mjk5ZGI5ZWM4MjMvYmFzZTY0LTAuMTMuMC9zcmMvZW5jb2RlLnJzAJwfEABbAAAAkgAAACcAAAB1c2l6ZSBvdmVyZmxvdyB3aGVuIGNhbGN1bGF0aW5nIGI2NCBsZW5ndGgAAJwfEABbAAAAlwAAABkAAACcHxAAWwAAALYAAAAgAAAAnB8QAFsAAAC3AAAAOgAAAJwfEABbAAAAtwAAACUAAACcHxAAWwAAAPcAAAAYAAAAnB8QAFsAAAD8AAAALwAAAJwfEABbAAAA/AAAABwAAACcHxAAWwAAAP0AAAA2AAAAnB8QAFsAAAD9AAAAIQAAAJwfEABbAAAAEwEAAC4AAACcHxAAWwAAABMBAAAJAAAAnB8QAFsAAAAUAQAACQAAAJwfEABbAAAACwEAAC4AAACcHxAAWwAAAAsBAAAJAAAAnB8QAFsAAAANAQAADwAAAJwfEABbAAAADAEAAAkAAACcHxAAWwAAAA8BAAAJAAAAnB8QAFsAAAARAQAACQAAAEltcG9zc2libGUgcmVtYWluZGVyVCEQABQAAACcHxAAWwAAACoBAAAWAAAAnB8QAFsAAAA7AQAACQAAAEludmFsaWQgbGFzdCBzeW1ib2wgLCBvZmZzZXQgLgAAkCEQABQAAACkIRAACQAAAK0hEAABAAAARW5jb2RlZCB0ZXh0IGNhbm5vdCBoYXZlIGEgNi1iaXQgcmVtYWluZGVyLgDIIRAAKwAAAEludmFsaWQgYnl0ZSAAAAD8IRAADQAAAKQhEAAJAAAArSEQAAEAAABPdmVyZmxvdyB3aGVuIGNhbGN1bGF0aW5nIG51bWJlciBvZiBjaHVua3MgaW4gaW5wdXQvVXNlcnMvZGVhcmthbmUvLmNhcmdvL3JlZ2lzdHJ5L3NyYy9naXRodWIuY29tLTFlY2M2Mjk5ZGI5ZWM4MjMvYmFzZTY0LTAuMTMuMC9zcmMvZGVjb2RlLnJzAABXIhAAWwAAALkAAAAFAAAAISIjJCUmJygpKissLTAxMjM0NTY3ODlAQUJDREVGR0hJSktMTU5QUVJTVFVWWFlaW2BhYmNkZWhpamtsbXBxckFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5KywuL0FCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5Li8wMTIzNDU2Nzg5QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5LV9BQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsv////////////////////////////////////////////AAECAwQFBgcICQoLDP//DQ4PEBESExQVFv///////xcYGRobHB0eHyAhIiMkJf8mJygpKiss/y0uLzD/////MTIzNDU2//83ODk6Ozz//z0+P/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8+P////zQ1Njc4OTo7PD3/////////AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBn///////8aGxwdHh8gISIjJCUmJygpKissLS4vMDEyM///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAE2Nzg5Ojs8PT4//////////wIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRob////////HB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDX//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wABAgMEBQYHCAkKC/////////8MDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJf///////yYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////z7//zQ1Njc4OTo7PD3/////////AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBn/////P/8aGxwdHh8gISIjJCUmJygpKissLS4vMDEyM///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////Pv///z80NTY3ODk6Ozw9/////////wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ////////GhscHR4fICEiIyQlJicoKSorLC0uLzAxMjP/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////BCQQAMQjEACEIxAARCMQAAQjEADEIhAARCkQAEQoEABEJxAARCYQAEQlEABEJBAATgAAAAgAAAAEAAAATwAAAFAAAABOAAAACAAAAAQAAABRAAAAYG9uZSBvZiCZKhAABwAAACwgAACoKhAAAgAAAJgqEAABAAAAmCoQAAEAAABgIG9yIGAAAJgqEAABAAAAxCoQAAYAAACYKhAAAQAAAC9Vc2Vycy9kZWFya2FuZS8uY2FyZ28vcmVnaXN0cnkvc3JjL2dpdGh1Yi5jb20tMWVjYzYyOTlkYjllYzgyMy9zZXJkZS0xLjAuMTUwL3NyYy9kZS9tb2QucnNleHBsaWNpdCBwYW5pYwAAAOQqEABbAAAA7QgAABIAAABTAAAABAAAAAQAAABUAAAAVQAAAFYAAABjYWxsZWQgYE9wdGlvbjo6dW53cmFwKClgIG9uIGEgYE5vbmVgIHZhbHVlbWVtb3J5IGFsbG9jYXRpb24gb2YgIGJ5dGVzIGZhaWxlZAoAAKMrEAAVAAAAuCsQAA4AAABsaWJyYXJ5L3N0ZC9zcmMvYWxsb2MucnPYKxAAGAAAAFUBAAAJAAAAY2Fubm90IG1vZGlmeSB0aGUgcGFuaWMgaG9vayBmcm9tIGEgcGFuaWNraW5nIHRocmVhZAAsEAA0AAAAbGlicmFyeS9zdGQvc3JjL3Bhbmlja2luZy5yczwsEAAcAAAAfQAAAAkAAAA8LBAAHAAAAEcCAAAPAAAAPCwQABwAAABGAgAADwAAAFcAAAAMAAAABAAAAFgAAABTAAAACAAAAAQAAABZAAAAWgAAABAAAAAEAAAAWwAAAFwAAABTAAAACAAAAAQAAABdAAAAXgAAAF8AAAAEAAAABAAAAGAAAABhAAAAYgAAAF8AAAAEAAAABAAAAGMAAABsaWJyYXJ5L2FsbG9jL3NyYy9yYXdfdmVjLnJzY2FwYWNpdHkgb3ZlcmZsb3cAAAAULRAAEQAAAPgsEAAcAAAABgIAAAUAAABhIGZvcm1hdHRpbmcgdHJhaXQgaW1wbGVtZW50YXRpb24gcmV0dXJuZWQgYW4gZXJyb3IAXwAAAAAAAAABAAAAGQAAAGxpYnJhcnkvYWxsb2Mvc3JjL2ZtdC5yc4QtEAAYAAAAZAIAAAkAAAApbGlicmFyeS9hbGxvYy9zcmMvdmVjL21vZC5ycykgc2hvdWxkIGJlIDw9IGxlbiAoaXMgYGF0YCBzcGxpdCBpbmRleCAoaXMgAAAA4C0QABUAAADJLRAAFwAAAKwtEAABAAAArS0QABwAAADLBwAADQAAAF8AAAAEAAAABAAAAGQAAABieXRlc2Vycm9yAABfAAAABAAAAAQAAABlAAAARnJvbVV0ZjhFcnJvcgAAAGNhbGxlZCBgT3B0aW9uOjp1bndyYXAoKWAgb24gYSBgTm9uZWAgdmFsdWVudW1iZXIgd291bGQgYmUgemVybyBmb3Igbm9uLXplcm8gdHlwZW51bWJlciB0b28gc21hbGwgdG8gZml0IGluIHRhcmdldCB0eXBlbnVtYmVyIHRvbyBsYXJnZSB0byBmaXQgaW4gdGFyZ2V0IHR5cGVpbnZhbGlkIGRpZ2l0IGZvdW5kIGluIHN0cmluZ2Nhbm5vdCBwYXJzZSBpbnRlZ2VyIGZyb20gZW1wdHkgc3RyaW5nKS4uAD0vEAACAAAAaW5kZXggb3V0IG9mIGJvdW5kczogdGhlIGxlbiBpcyAgYnV0IHRoZSBpbmRleCBpcyAAAEgvEAAgAAAAaC8QABIAAAA6AAAAXC4QAAAAAACMLxAAAQAAAIwvEAABAAAAcGFuaWNrZWQgYXQgJycsILQvEAABAAAAtS8QAAMAAABcLhAAAAAAAG0AAAAAAAAAAQAAAG4AAABgOiAAXC4QAAAAAADhLxAAAgAAAG0AAAAMAAAABAAAAG8AAABwAAAAcQAAACAgICAgewosCiwgIHsgfSB9KAooLApbAG0AAAAEAAAABAAAAHIAAABdbGlicmFyeS9jb3JlL3NyYy9mbXQvbnVtLnJzNTAQABsAAABlAAAAFAAAADB4MDAwMTAyMDMwNDA1MDYwNzA4MDkxMDExMTIxMzE0MTUxNjE3MTgxOTIwMjEyMjIzMjQyNTI2MjcyODI5MzAzMTMyMzMzNDM1MzYzNzM4Mzk0MDQxNDI0MzQ0NDU0NjQ3NDg0OTUwNTE1MjUzNTQ1NTU2NTc1ODU5NjA2MTYyNjM2NDY1NjY2NzY4Njk3MDcxNzI3Mzc0NzU3Njc3Nzg3OTgwODE4MjgzODQ4NTg2ODc4ODg5OTA5MTkyOTM5NDk1OTY5Nzk4OTlhc3NlcnRpb24gZmFpbGVkOiAqY3VyciA+IDE5AAA1MBAAGwAAAOUBAAAFAAAAbQAAAAQAAAAEAAAAcwAAAHQAAAB1AAAAbGlicmFyeS9jb3JlL3NyYy9mbXQvbW9kLnJzAHAxEAAbAAAAdAkAAB4AAABwMRAAGwAAAHsJAAAWAAAAbGlicmFyeS9jb3JlL3NyYy9zbGljZS9tZW1jaHIucnOsMRAAIAAAAGgAAAAnAAAAcmFuZ2Ugc3RhcnQgaW5kZXggIG91dCBvZiByYW5nZSBmb3Igc2xpY2Ugb2YgbGVuZ3RoINwxEAASAAAA7jEQACIAAAByYW5nZSBlbmQgaW5kZXggIDIQABAAAADuMRAA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"
}
Parameter | Type | Description |
---|---|---|
code_info_response | CodeInfoResponse | Contract code info |
data | Byte Array | Raw data in base64 encoding |
CodeInfoResponse
Parameter | Type | Description |
---|---|---|
code_id | Int | ID of the contract code |
creator | String | Creator address |
data_hash | String | Contract code hash in hexadecimal |
instantiate_permission | AccessConfig | Access configuration |
AccessConfig
Parameter | Type | Description |
---|---|---|
permission | AccessType | Permission configuration |
addresses | String Array |
AccessType
ID | Acces Type |
---|---|
0 | AccessTypeUnspecified |
1 | AccessTypeNobody |
3 | AccessTypeEverybody |
4 | AccessTypeAnyOfAddresses |
Codes
Gets the metadata for all stored contract codes
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
limit = 2
pagination = PaginationOption(limit=limit)
response = await client.fetch_codes(pagination=pagination)
print(response)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/cosmos/cosmos-sdk/types/query"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
pagination := query.PageRequest{Limit: 2}
ctx := context.Background()
res, err := chainClient.FetchCodes(ctx, &pagination)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
pagination | Paging | Pagination of results | No |
Response Parameters
Response Example:
{
"codeInfos":[
{
"codeId":"1",
"creator":"inj180rl9ezc4389t72pc3vvlkxxs5d9jx60w9eeu3",
"dataHash":"y9Pfljq5aQPc3nx8Apg3IeUw4JZ15GQe6mp577XlaQc=",
"instantiatePermission":{
"permission":"ACCESS_TYPE_EVERYBODY",
"addresses":[
]
}
},
{
"codeId":"2",
"creator":"inj180rl9ezc4389t72pc3vvlkxxs5d9jx60w9eeu3",
"dataHash":"rKYFl6749PJgIK4stNXmpWv7UdX+4rcR6UaGK4JUhu8=",
"instantiatePermission":{
"permission":"ACCESS_TYPE_EVERYBODY",
"addresses":[
]
}
}
],
"pagination":{
"nextKey":"AAAAAAAAAAM=",
"total":"0"
}
}
{
"code_infos": [
{
"id": 1,
"creator": "inj180rl9ezc4389t72pc3vvlkxxs5d9jx60w9eeu3",
"data_hash": "CBD3DF963AB96903DCDE7C7C02983721E530E09675E4641EEA6A79EFB5E56907",
"instantiate_permission": {
"permission": "Everybody"
}
},
{
"id": 2,
"creator": "inj180rl9ezc4389t72pc3vvlkxxs5d9jx60w9eeu3",
"data_hash": "ACA60597AEF8F4F26020AE2CB4D5E6A56BFB51D5FEE2B711E946862B825486EF",
"instantiate_permission": {
"permission": "Everybody"
}
}
],
"pagination": {
"next_key": "AAAAAAAAAAM="
}
}
Parameter | Type | Description |
---|---|---|
code_infos | CodeInfoResponse Array | Contract code info |
pagination | PageResponse | Pagination of results |
CodeInfoResponse
Parameter | Type | Description |
---|---|---|
code_id | Int | ID of the contract code |
creator | String | Creator address |
data_hash | String | Contract code hash in hexadecimal |
instantiate_permission | AccessConfig | Access configuration |
AccessConfig
Parameter | Type | Description |
---|---|---|
permission | AccessType | Permission configuration |
addresses | String Array |
AccessType
ID | Acces Type |
---|---|
0 | AccessTypeUnspecified |
1 | AccessTypeNobody |
3 | AccessTypeEverybody |
4 | AccessTypeAnyOfAddresses |
PinnedCodes
Gets the pinned code ids
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
limit = 2
pagination = PaginationOption(limit=limit)
response = await client.fetch_pinned_codes(pagination=pagination)
print(response)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/cosmos/cosmos-sdk/types/query"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
pagination := query.PageRequest{Limit: 2}
ctx := context.Background()
res, err := chainClient.FetchPinnedCodes(ctx, &pagination)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
pagination | Paging | Pagination of results | No |
Response Parameters
Response Example:
{
"codeIds":[
"135",
"136"
],
"pagination":{
"nextKey":"AAAAAAAAAIk=",
"total":"0"
}
}
{
"code_ids": [
135,
136
],
"pagination": {
"next_key": "AAAAAAAAAIk="
}
}
Parameter | Type | Description |
---|---|---|
code_ids | Int Array | Array of contract code IDs |
pagination | PageResponse | Pagination of results |
ContractsByCreator
Gets the contracts by creator
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
from pyinjective.async_client import AsyncClient
from pyinjective.client.model.pagination import PaginationOption
from pyinjective.core.network import Network
async def main() -> None:
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
creator = "inj1h3gepa4tszh66ee67he53jzmprsqc2l9npq3ty"
limit = 2
pagination = PaginationOption(limit=limit)
response = await client.fetch_contracts_by_creator(creator_address=creator, pagination=pagination)
print(response)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/cosmos/cosmos-sdk/types/query"
"os"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
creator := "inj1h3gepa4tszh66ee67he53jzmprsqc2l9npq3ty"
pagination := query.PageRequest{Limit: 2}
ctx := context.Background()
res, err := chainClient.FetchContractsByCreator(ctx, creator, &pagination)
if err != nil {
fmt.Println(err)
}
str, _ := json.MarshalIndent(res, "", " ")
fmt.Print(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
creator_address | String | Address of the contract creator | Yes |
pagination | Paging | Pagination of results | No |
Response Parameters
Response Example:
{
"contractAddresses":[
"inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7"
],
"pagination":{
"nextKey":"",
"total":"0"
}
}
{
"contract_addresses": [
"inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7"
],
"pagination": {}
}
Parameter | Type | Description |
---|---|---|
contract_addresses | String Array | Array of all the contracts created by the specified creator |
pagination | PageResponse | Pagination of results |
MsgExecuteContract
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import os
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
# initialize grpc client
# set custom cookie location (optional) - defaults to current dir
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
# prepare tx msg
# NOTE: COIN MUST BE SORTED IN ALPHABETICAL ORDER BY DENOMS
funds = [
composer.coin(
amount=69,
denom="factory/inj1hdvy6tl89llqy3ze8lv6mz5qh66sx9enn0jxg6/inj12ngevx045zpvacus9s6anr258gkwpmthnz80e9",
),
composer.coin(amount=420, denom="peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7"),
composer.coin(amount=1, denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"),
]
msg = composer.MsgExecuteContract(
sender=address.to_acc_bech32(),
contract="inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7",
msg='{"increment":{}}',
funds=funds,
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The Injective Chain address of the sender | Yes |
contract | String | The Injective Chain address of the contract | Yes |
msg | Bytes | JSON encoded message to pass to the contract | Yes |
funds | Coin Array | List of Coins to be sent to the contract. Note that the coins must be alphabetically sorted by denoms | No |
Coin
Parameter | Type | Description |
---|---|---|
denom | String | Denom of the Coin |
amount | String | Amount of Coin |
Response Example:
txhash: "814807A5C827FC385DF6108E52494E63A2010F36B1D6F36E43B2AEED5D530D60"
raw_log: "[]"
gas wanted: 217930
gas fee: 0.000108965 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
MsgExecuteContract (second example)
This example shows how to interact with a contract to execute the guardian_set_info
functionality using the post_message
method in the contract.
The parameter sent to the post_message
function has to be encoded in Base64 format.
Request Parameters
Request Example: ``` python import asyncio import base64 import json import logging
from pyinjective.composer import Composer as ProtoMsgComposer from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE from pyinjective.async_client import AsyncClient from pyinjective.transaction import Transaction from pyinjective.core.network import Network from pyinjective.wallet import PrivateKey, Address
async def main() -> None: # select network: local, testnet, mainnet network = Network.testnet() composer = ProtoMsgComposer(network=network.string())
# initialize grpc client client = AsyncClient(network) await client.sync_timeout_height()
# load account priv_key = PrivateKey.from_hex("5d386fbdbf11f1141010f81a46b40f94887367562bd33b452bbaa6ce1cd1381e") pub_key = priv_key.to_public_key() address = pub_key.to_address() await client.fetch_account(address.to_acc_bech32())
contract_message = '{"guardian_set_info":{}}' encoded_message = base64.b64encode(contract_message.encode(encoding="utf-8")).decode()
execute_message_parameter = { "post_message": { "message": encoded_message, "nonce": 1} }
# prepare tx msg msg = composer.MsgExecuteContract( sender=address.to_acc_bech32(), contract="inj14hj2tavq8fpesdwxxcu44rty3hh90vhujaxlnz", msg=json.dumps(execute_message_parameter), )
# build sim tx tx = ( Transaction() .with_messages(msg) .with_sequence(client.get_sequence()) .with_account_num(client.get_number()) .with_chain_id(network.chain_id) ) sim_sign_doc = tx.get_sign_doc(pub_key) sim_sig = priv_key.sign(sim_sign_doc.SerializeToString()) sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx try: sim_res = await client.simulate(sim_tx_raw_bytes) except RpcError as ex: print(ex) return
# build tx gas_price = GAS_PRICE gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation gas_fee = '{:.18f}'.format((gas_price * gas_limit) / pow(10, 18)).rstrip('0') fee = [composer.Coin( amount=gas_price * gas_limit, denom=network.fee_denom, )] tx = tx.with_gas(gas_limit).with_fee(fee).with_memo('').with_timeout_height(client.timeout_height) sign_doc = tx.get_sign_doc(pub_key) sig = priv_key.sign(sign_doc.SerializeToString()) tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode res = await client.broadcast_tx_sync_mode(tx_raw_bytes) print(res) print("gas wanted: {}".format(gas_limit)) print("gas fee: {} INJ".format(gas_fee))
if name == "main": asyncio.get_event_loop().run_until_complete(main())
| Parameter | Type | Description | Required |
|-----------|------------|-------------------------------------------------------------------------------------------------------|----------|
| sender | String | The Injective Chain address of the sender | Yes |
| contract | String | The Injective Chain address of the contract | Yes |
| msg | Bytes | JSON encoded message to pass to the contract | Yes |
### Response Parameters
> Response Example:
``` python
txhash: "03DDA0A4B49EF093CCC2999435D6D23C71A570B84E588137A0D314F73F5A336B"
raw_log: "[]"
gas wanted: 139666
gas fee: 0.000069833 INJ
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
- Wasmx
Wasmx smart contract interactions.
MsgExecuteContractCompat
IP rate limit group: chain
Request Parameters
Request Example:
import asyncio
import json
import os
import dotenv
from grpc import RpcError
from pyinjective.async_client import AsyncClient
from pyinjective.constant import GAS_FEE_BUFFER_AMOUNT, GAS_PRICE
from pyinjective.core.network import Network
from pyinjective.transaction import Transaction
from pyinjective.wallet import PrivateKey
async def main() -> None:
dotenv.load_dotenv()
configured_private_key = os.getenv("INJECTIVE_PRIVATE_KEY")
# select network: local, testnet, mainnet
network = Network.testnet()
client = AsyncClient(network)
composer = await client.composer()
await client.sync_timeout_height()
# load account
priv_key = PrivateKey.from_hex(configured_private_key)
pub_key = priv_key.to_public_key()
address = pub_key.to_address()
await client.fetch_account(address.to_acc_bech32())
# prepare tx msg
# NOTE: COIN MUST BE SORTED IN ALPHABETICAL ORDER BY DENOMS
funds = (
"69factory/inj1hdvy6tl89llqy3ze8lv6mz5qh66sx9enn0jxg6/inj12ngevx045zpvacus9s6anr258gkwpmthnz80e9,"
"420peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7,"
"1peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"
)
msg = composer.msg_execute_contract_compat(
sender=address.to_acc_bech32(),
contract="inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7",
msg=json.dumps({"increment": {}}),
funds=funds,
)
# build sim tx
tx = (
Transaction()
.with_messages(msg)
.with_sequence(client.get_sequence())
.with_account_num(client.get_number())
.with_chain_id(network.chain_id)
)
sim_sign_doc = tx.get_sign_doc(pub_key)
sim_sig = priv_key.sign(sim_sign_doc.SerializeToString())
sim_tx_raw_bytes = tx.get_tx_data(sim_sig, pub_key)
# simulate tx
try:
sim_res = await client.simulate(sim_tx_raw_bytes)
except RpcError as ex:
print(ex)
return
# build tx
gas_price = GAS_PRICE
gas_limit = int(sim_res["gasInfo"]["gasUsed"]) + GAS_FEE_BUFFER_AMOUNT # add buffer for gas fee computation
gas_fee = "{:.18f}".format((gas_price * gas_limit) / pow(10, 18)).rstrip("0")
fee = [
composer.coin(
amount=gas_price * gas_limit,
denom=network.fee_denom,
)
]
tx = tx.with_gas(gas_limit).with_fee(fee).with_memo("").with_timeout_height(client.timeout_height)
sign_doc = tx.get_sign_doc(pub_key)
sig = priv_key.sign(sign_doc.SerializeToString())
tx_raw_bytes = tx.get_tx_data(sig, pub_key)
# broadcast tx: send_tx_async_mode, send_tx_sync_mode, send_tx_block_mode
res = await client.broadcast_tx_sync_mode(tx_raw_bytes)
print(res)
print("gas wanted: {}".format(gas_limit))
print("gas fee: {} INJ".format(gas_fee))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"encoding/json"
"fmt"
"os"
wasmxtypes "github.com/InjectiveLabs/sdk-go/chain/wasmx/types"
"github.com/InjectiveLabs/sdk-go/client"
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
"github.com/InjectiveLabs/sdk-go/client/common"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
)
func main() {
network := common.LoadNetwork("testnet", "lb")
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
if err != nil {
panic(err)
}
senderAddress, cosmosKeyring, err := chainclient.InitCosmosKeyring(
os.Getenv("HOME")+"/.injectived",
"injectived",
"file",
"inj-user",
"12345678",
"f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3", // keyring will be used if pk not provided
false,
)
if err != nil {
panic(err)
}
clientCtx, err := chainclient.NewClientContext(
network.ChainId,
senderAddress.String(),
cosmosKeyring,
)
if err != nil {
fmt.Println(err)
return
}
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
chainClient, err := chainclient.NewChainClient(
clientCtx,
network,
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
)
if err != nil {
panic(err)
}
firstAmount := 69
firstToken := "factory/inj1hdvy6tl89llqy3ze8lv6mz5qh66sx9enn0jxg6/inj12ngevx045zpvacus9s6anr258gkwpmthnz80e9"
secondAmount := 420
secondToken := "peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7"
thirdAmount := 1
thirdToken := "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"
funds := fmt.Sprintf(
"%v%s,%v%s,%v%s",
firstAmount,
firstToken,
secondAmount,
secondToken,
thirdAmount,
thirdToken,
)
message := wasmxtypes.MsgExecuteContractCompat{
Sender: senderAddress.String(),
Contract: "inj1ady3s7whq30l4fx8sj3x6muv5mx4dfdlcpv8n7",
Msg: "{\"increment\": {}}",
Funds: funds,
}
// AsyncBroadcastMsg, SyncBroadcastMsg, QueueBroadcastMsg
response, err := chainClient.AsyncBroadcastMsg(&message)
if err != nil {
panic(err)
}
str, _ := json.MarshalIndent(response, "", " ")
fmt.Println(string(str))
}
Parameter | Type | Description | Required |
---|---|---|---|
sender | String | The Injective Chain address of the sender | Yes |
contract | String | The Injective Chain address of the contract | Yes |
msg | String | JSON encoded message to pass to the contract | Yes |
funds | String | String with comma separated list of amounts and token denoms to transfer to the contract. Note that the coins must be alphabetically sorted by denoms | No |
Response Parameters
Response Example:
Paramter | Type | Description |
---|---|---|
tx_response | TxResponse | Transaction details |
TxResponse
Parameter | Type | Description |
---|---|---|
height | Integer | The block height |
tx_hash | String | Transaction hash |
codespace | String | Namespace for the code |
code | Integer | Response code (zero for success, non-zero for errors) |
data | String | Bytes, if any |
raw_log | String | The output of the application's logger (raw string) |
logs | ABCIMessageLog Array | The output of the application's logger (typed) |
info | String | Additional information |
gas_wanted | Integer | Amount of gas requested for the transaction |
gas_used | Integer | Amount of gas consumed by the transaction |
tx | Any | The request transaction bytes |
timestamp | String | Time of the previous block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time |
events | Event Array | Events defines all the events emitted by processing a transaction. Note, these events include those emitted by processing all the messages and those emitted from the ante. Whereas Logs contains the events, with additional metadata, emitted only by processing the messages. |
ABCIMessageLog
Parameter | Type | Description |
---|---|---|
msg_index | Integer | The message index |
log | String | The log message |
events | StringEvent Array | Event objects that were emitted during the execution |
Event
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | EventAttribute Array | All event object details |
StringEvent
Parameter | Type | Description |
---|---|---|
type | String | Event type |
attributes | Attribute Array | Event data |
EventAttribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
index | Boolean | If attribute is indexed |
Attribute
Parameter | Type | Description |
---|---|---|
key | String | Attribute key |
value | String | Attribute value |
- Historical Queries
Execute historical chain queries by passing the block height in the headers. Keep in mind that the chain node being used in the query should not be pruned for the height specified.
Publicly maintained nodes are being pruned every 5-10 days.
To find the available chain queries visit Swagger for Mainnet and Testnet.
Request Parameters
Request Example:
import requests
import asyncio
import logging
async def main() -> None:
block_height = "9858070"
lcd = "https://testnet.lcd.injective.network/injective/exchange/v1beta1/derivative/orderbook/0x2e94326a421c3f66c15a3b663c7b1ab7fb6a5298b3a57759ecf07f0036793fc9"
lcd_request = requests.get(lcd, headers={"Content-Type": "application/json", "x-cosmos-block-height": "{}".format(block_height)}).json()
print(lcd_request)
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
asyncio.get_event_loop().run_until_complete(main())
package main
import (
"fmt"
"io/ioutil"
"net/http"
"time"
)
func queryAtHeight(url, method string, height int64) ([]byte, error) {
client := &http.Client{
Timeout: time.Second * 10,
}
req, err := http.NewRequest(method, url, nil)
if err != nil {
return nil, fmt.Errorf("new request err: %w", err)
}
req.Header.Set("x-cosmos-block-height", fmt.Sprintf("%d", height))
response, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("exec request err: %w", err)
}
defer response.Body.Close()
return ioutil.ReadAll(response.Body)
}
func main() {
result, err := queryAtHeight("https://testnet.lcd.injective.network/injective/exchange/v1beta1/derivative/orderbook/0x2e94326a421c3f66c15a3b663c7b1ab7fb6a5298b3a57759ecf07f0036793fc9", "GET", 9858070)
if err != nil {
panic(err)
}
fmt.Println("query result:", string(result))
}
Parameter | Type | Description | Required |
---|---|---|---|
block_height | String | The block height at which we want to execute the query | Yes |
Response Example:
query result: {'buys_price_level': [{'p': '30624950000.000000000000000000', 'q': '4.000000000000000000'}, {'p': '29885630000.000000000000000000', 'q': '3.000000000000000000'}, {'p': '29710520000.000000000000000000', 'q': '3.000000000000000000'}, {'p': '29321790000.000000000000000000', 'q': '2.000000000000000000'}, {'p': '28861950000.000000000000000000', 'q': '1.000000000000000000'}, {'p': '28766450000.000000000000000000', 'q': '1.000000000000000000'}, {'p': '28386560000.000000000000000000', 'q': '4.000000000000000000'}, {'p': '28378550000.000000000000000000', 'q': '2.000000000000000000'}, {'p': '27677610000.000000000000000000', 'q': '6.000000000000000000'}, {'p': '26828710000.000000000000000000', 'q': '1.000000000000000000'}, {'p': '26773560000.000000000000000000', 'q': '8.000000000000000000'}, {'p': '26479000000.000000000000000000', 'q': '9.000000000000000000'}, {'p': '26203470000.000000000000000000', 'q': '16.000000000000000000'}, {'p': '26038150000.000000000000000000', 'q': '14.000000000000000000'}], 'sells_price_level': []}
query result: {
"buys_price_level": [
{
"p": "30624950000.000000000000000000",
"q": "4.000000000000000000"
},
{
"p": "29885630000.000000000000000000",
"q": "3.000000000000000000"
},
{
"p": "29710520000.000000000000000000",
"q": "3.000000000000000000"
},
{
"p": "29321790000.000000000000000000",
"q": "2.000000000000000000"
},
{
"p": "28861950000.000000000000000000",
"q": "1.000000000000000000"
},
{
"p": "28766450000.000000000000000000",
"q": "1.000000000000000000"
},
{
"p": "28386560000.000000000000000000",
"q": "4.000000000000000000"
},
{
"p": "28378550000.000000000000000000",
"q": "2.000000000000000000"
},
{
"p": "27677610000.000000000000000000",
"q": "6.000000000000000000"
},
{
"p": "26828710000.000000000000000000",
"q": "1.000000000000000000"
},
{
"p": "26773560000.000000000000000000",
"q": "8.000000000000000000"
},
{
"p": "26479000000.000000000000000000",
"q": "9.000000000000000000"
},
{
"p": "26203470000.000000000000000000",
"q": "16.000000000000000000"
},
{
"p": "26038150000.000000000000000000",
"q": "14.000000000000000000"
}
],
"sells_price_level": [
]
}
- HealthAPI
HealthAPI (HTTP) checks if backend data is up-to-date and reliable or not.
GetStatus
IP rate limit group: chain
To check the health of a node, the GetStatus API can be queried to obtain the Indexer height (localHeight
) and the network height (horacleHeight
). Next, the chain node height can be queried directly from the node (e.g. curl --insecure http://sentry.lcd.injective.network:26657/abci_info | grep last_block_height
or in Python (await async_client.get_latest_block()).block.header.height
). Comparing last_block_height
with horacleHeight
gives a sense of the chain node's health, with a threshold of a 20 block difference being a good starting point for detecting unhealthy nodes. localHeight
and horacleHeight
can also be compared to check Indexer health, though an error should already be returned from the API query if the Indexer is deemed unhealthy (more than 20 block height difference).
If LB/K8S endpoints are being used, there is no need to do these checks, as the cluster has built-in liveliness checks and excludes unhealthy nodes if any are detected.
A recommended health check frequency of once every 20-30 seconds is recommended.
Notes
horacleHeight: the network height of the chain (average returned by multiple nodes in the network)
localHeight: the latest synced block on the indexer
lastBlock: the latest synced block on the chain
Request Example:
import requests
def main() -> None:
r = requests.get('https://sentry.lcd.injective.network:4444/api/health/v1/status', verify=False)
print(r.text)
if __name__ == '__main__':
main()
package main
import (
"crypto/tls"
"fmt"
"io/ioutil"
"net/http"
"time"
)
func queryHealthAPI(url, method string) ([]byte, error) {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{
Transport: tr,
Timeout: time.Second * 10,
}
req, err := http.NewRequest(method, url, nil)
if err != nil {
return nil, fmt.Errorf("new request err: %w", err)
}
response, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("exec request err: %w", err)
}
defer response.Body.Close()
return ioutil.ReadAll(response.Body)
}
func main() {
result, err := queryHealthAPI("https://sentry.lcd.injective.network:4444/api/health/v1/status", "GET")
if err != nil {
panic(err)
}
fmt.Println("query result:", string(result))
}
Response Parameters
Response Example:
{
"s": "",
"data": {
"localHeight": 26953309,
"localTimestamp": 1677042872,
"horacleHeight": 26953309,
"horacleTimestamp": 1677042872
}
}
Parameter | Type | Description |
---|---|---|
s | String | Status of the response |
errmsg | String | Error message, if any |
data | HealthStatus | Height and time information for checking health |
HealthStatus
Parameter | Type | Description |
---|---|---|
localHeight | Integer | Injective Indexer block height |
localTimestamp | Integer | Timestamp of localHeight |
horacleHeight | Integer | Height of the network according to the Injective height oracle |
horacleTimestamp | Integer | Timestamp of horacleHeight |
Glossary
Injective Chain
The Injective Chain refers to the blockchain running the Injective Protocol. It is is the fundamental piece of infrastructure and ultimate source of truth for any trades happening on the network.
Validator / Injective Node
A validator is a node for the Injective Chain. The term node itself refers to a host computer in a network. In the context of blockchains, nodes are the computers participating in producing new blocks and validating new transactions in a peer-to-peer fashion. All on-chain code for Injective is executed on the hardware of every validator, in contrast to a CEX where code is executed on a central server.
On-chain Matching
The matching algorithm is executed as part of validating the chain. It is executed on the hardware of every validator. Therefore it must be deterministic, so every validator comes to the same matching result. For fairness reasons the matching algorithm consists of frequent batch auctions (FBA).
Frequent Batch Auction (FBA)
Frequent Batch Auctions (FBA) are ensuring fair order matching prices by calculating one uniform clearing price over all orders in the same block. Rather than calculating the clearing price for every order, the FBA algorithm calculates the clearing price for a batch of orders. For more details, here.
Relayer
The Injective Chain itself provides no historical data, no detailed statistics and no front-end. This is the role of the relayer. A relayer will index data emitted from the Injective Chain to provide an additional API and front-end.
Mempool
A mempool refers to pending transactions in a blockchain. It is the place where transactions are stored before they are included in a block.
gRPC
gRPC is a high-performance, open-source, general-purpose RPC framework that is used by the Injective Chain. It is used to communicate with the Injective Chain and the relayer.
Mark Price
Mark price refers to the oracle price for the underlying asset in a futures market. It is used to determine when a position is liquidable. Only when the mark price falls below your position's liquidation price, the position can be liquidated. The mark price is further used for market settlements, either in the case of an emergency stop due to the insurance fund draining or in the case of planned settlements for time-expiry future markets.
Perpetual Swap
A perpetual swap is a futures contract without expiry date. Since those contracts never expire with a settlement price, a new mechanism is used to align future contract prices with the mark price: the funding rate.
Funding Rate
In perpetual swaps a funding rate is used to align future contract prices with the mark price. The funding rate is calculated by keeping track of the volume weighted average of the deltas from mark price vs. trade execution price. It is applied to a position proportionally to the position's size.
FAQ
1. What are the trading fees on Injective?
Trading fees differ per market and are defined through governance for both maker and taker orders. The fees can also be reduced based on your tier which is determined based on your staked INJ and 30-day trailing fees.
Note that if you place trades through the API, you will only pay 60% of the trading fees regardless if your order is filled as a maker or taker. In every exchange-related message you can set recipient_fee to your own address in order to collect 40% of the trading fees. On the DEX UI, recipient_fee is set to the relayer's address which acts as a source of revenue but on the API you can set this field to any address of your choosing, including your own.
The DEX UI will also show you the full fees but if you have placed a trade through the API you would have paid only 60% of those fees.
2. What are the gas fees on Injective?
If you place trades through the UI on one of the available relayers you can experience gas-less trading, if you place trades from the API you will pay gas fees in INJ but they will be very low at an average of 0.00005 INJ per message. Note that the INJ to pay for gas must be in the bank balance (wallet) and not the subaccount (trading account).
3. How can I calculate the gas fees in INJ?
The minimum gas price currently accepted by nodes is 160000000. In order to find the exact INJ amount paid you multiply the gas wanted by the minimum gas price and divide by 1e18 (because INJ token has 18 decimals). For instance, if gas wanted is 104519 then you would calculate it as follows:
160000000 * 104519 / 1e18 = 0.00001672304 INJ
4. Which API nodes can I connect to?
The SDKs default to using a load balanced endpoint. It is possible also to run a local node. The guide to set up your own node can be found here.
5. Does Injective have an API support channel?
Yes, you can join the Discord and Telegram API channels to ask any questions you might have or if you need any support.
6. Can I get the order_hash (order_id) right after I send a new order?
Yes, you can actually fetch the order_hash before you even send the transaction through our simulation, you can see the Chain API examples on how to use the simulation.
A better alternative is to set a client order id (cid) to the orders. It is possible to then cancel the orders by cid instead of hash. With this it is no longer necessary to calculate the order hash in advance.
7. Are there limits in the API requests?
All public nodes have limits to the number of request they allow per IP. Please check the rate limits page.
8. What is the normal order latency I can expect?
There's no guarantee on when the chain will process your transaction. It depends on the peer to peer gossip of the network and whether your transaction reaches a given block producer to get included in a block. You can read more details about this here https://docs.tendermint.com/v0.35/assets/img/tm-transaction-flow.258ca020.png as well as the docs here https://docs.tendermint.com/v0.35/introduction/what-is-tendermint.html
We strongly recommend following the guide to setup your own infrastructure which will ultimately reduce latency to a great extent.
Following we include more details regarding transactions latency and blocks production:
- Validators might miss consensus rounds which will delay block production (instead of a 800ms block, we’ll have a 5000ms block). This happens very rarely and it’s due to issues on the validator node (they have a big chain state and they need to download a pruned snapshot, hardware resources etc.). We’re working with all validators to ensure these don’t take place anymore. This was the issue you mentioned last time with block 61885380 above. Additionally, we can decrease the block proposal timeout so we can lower the delayed block from a missed consensus round if this ever takes place again.
- Even though the Tendermint/CometBFT docs don’t make this clear, transactions are only executed in the next block - a concept called deferred/next-block execution. You can find more details/discussion on Github from the core teams: https://github.com/tendermint/tendermint/issues/7898. This means that if you send txs in block N, they are only executed in block N+1.
- There’s a max block gas limit which is currently set to 50M. This prevents spamming/DDoS attacks since if it has very high or even -1, this would allow one to send huge transactions and delay block time by minutes since the node would take a while to process each tx. We’ve observed that we’re currently hitting the block gas limit and we’re going to put up a proposal soon to increase it. This means that even though the validator mempool might have 100 txs, only 40 or 50 will be included (up to 50M gas) so you’re experiencing unnecessary delay. As an example, this tx spent 1M gas: https://explorer.injective.network/transaction/2CC4E5A54D23AF6CC599E7A4328CAE2EFBF6719F40976985E2381A3411B6DD0A/. There are other txs that spend 200K or even 3-5M in gas. Based on some empirical observations, a reasonable gas increase in the block will not cause any performance issues but we’re running more extensive tests and we’ll put up a proposal soon. We’ll be increasing this value progressively as we scale up along with some on-chain improvements.
- As more nodes get online in the network, this will increase the P2P latency. Gossip latency might increase depending on the peers on the node you sent your tx. Consider this scenario:
A. There are 400 nodes online in the network, the node you broadcast to has 40 peers but none of these peers is the validator proposing the next block.
B. Your node will gossip to its 40 peers, then these 40 peers will gossip to the next peers etc.
C. We don’t have metrics as to how long it takes for a tx to be gossiped but there’s some latency involved here since every node will run checkTx/validations before it includes the tx in its mempool.
On the other hand, your node might have direct peering with the block proposer for the upcoming block so you have zero P2P latency.
9. Can I have my own client id to send messages through the API?
No, we don't store private information on the Injective Chain.
10. Would I save gas fees if I batch messages in transactions?
Yes, a transaction includes fields such as messages, fee, signatures, memo and timeout height. When you send a batch of messages in a single transaction, the transaction size is less than the cumulative transaction size of individual transactions which ultimately results in less gas fees.
11. What is the timeout_height?
The timeout_height specifies a height at which your transaction will timeout and eventually prevents it from being committed past a certain height. Essentially, the transaction will be discarded from the mempool (timeout) after the block with number timeout_height has been mined and your sequence number is cleared if a bad transaction with a lower account sequence does not get processed correctly.
12. Do fee discounts apply to all markets?
Discounts apply to all markets apart from markets that have negative maker fees or markets that have been explicitly excluded.
13. What is the block time on the network?
The average block time is 800ms.
14. Does gas fee affect block inclusion and transaction ordering?
Gas fee affects block inclusion but not ordering, currently there's no ordering of transactions other than the order they've arrived (based on the sequence number). For more information refer to the Tendermint docs
15. When may I see account sequence mismatch errors?
On a high-level, when a sentry node receives a transaction it runs a CheckTx
to verify the validity of the transaction which includes stateless and stateful checks. One of those checks is to verify that the sender’s sequence number is valid - the sequence number is primarily used for replay protection and it also affects the ordering logic of transactions.
When you broadcast multiple transactions sequentially to the node the sequence is incremented by one for each transaction and your transactions will be included in a block in the order they arrive (based on the sequence). Should the transaction pass all the checks from CheckTx
then it is included in the nodes’ mempool (an in-memory pool of transactions unique to each node) which will be gossiped to other peers in the network prior to consensus. When the transaction reaches the proposer validator node then it will be included in a block. Note that in Tendermint BFT (cosmos-sdk consensus algorithm) finality is absolute, meaning that transactions are finalized when they are included in a block.
There are a couple of reasons you might see account sequence mismatch errors:
1) If you run a trading bot and at the same time you try to broadcast a transaction on the DEX you'll end up with a sequence mismatch since the bot will fetch the sequence from the node and the same will happen with the Frontend so you end up broadcasting a transaction with the same sequence number. Similarly, if you run a trading bot with the same private key you'll also see sequence mismatch errors, thus you should use the private key only at one platform at a time.
2) In the examples we're using a function to handle the sequence locally because if you send multiple transactions in a single block the only way to do that is to use local sequence as until the tx is confirmed the peers in the network are not aware that the sequence has been increased. Essentially, we fetch the sequence the first time through the node directly and then handle it locally for consecutive transactions. If you use sync/async and fetch the sequence from the node every time opposed to handling it locally then you'll occasionally end up with a sequence mismatch.
You can refer to these functions below for sdk-python.
https://github.com/InjectiveLabs/sdk-python/blob/master/pyinjective/wallet.py#L269
https://github.com/InjectiveLabs/sdk-python/blob/master/pyinjective/wallet.py#L296
On the other hand, if you use broadcast mode you essentially expect the tx to be included in a block and then you'll get a response back from the sentry - that's not really recommended since it's wasting a lot of resources from the sentry and it's slower on the client-side too but in this case it guarantees that the sequence will always be unique and you can fetch it from the node every time you send a tx.
3) If you broadcasted a transaction with gas fee lower than the minimum threshold on the node then this transaction will remain in the mempool until the node is restarted and the transaction is discarded or until the transaction expires (if you've set a timeout_height before you broadcasted it). If a transaction is stuck in the mempool then you won't be able to broadcast transactions to that node (and potentially to other nodes in the network if it has been gossiped) since the account sequence will be incorrect. To ensure that transactions don't get stuck in the mempool please use the gas fee set in the examples.
16. What are the broadcast modes I can use to send a transaction?
Sync: Wait for the tx to pass/fail CheckTx
Async: Don’t wait for the tx to pass/fail CheckTx; send and return tx immediately
17. When may I see a max subscriptions per client error?
You can open up to 5 chain channels per IP, if you run more than 5 trading bots from the same IP then this error would naturally show up and you should use a different IP. Every trading bot should open one chain channel only, thus if you're seeing this error and don't have 5 distinct trading bots then it indicates an issue in your logic. If you want to broadcast multiple transactions in a single block you can use sync mode and open one channel only. You can refer here for the chain channel initialization in sdk-python.
18. How long does it take until the Exchange API returns my orders/trades after the transaction has been sent?
This depends on a lot of factors such as the P2P network topology and geolocation of the client-server. When you broadcast a transaction, the following cycle takes place:
1) The transaction is gossiped to other peers in the network
2) The transaction eventually reaches the proposer node
3) Validators participating in the consensus round sign the block and it's produced on-chain
4) The block information is gossiped to the read-only peers (sentry nodes)
5) The events emitted by the chain are picked up by the indexer (Exchange API) and included in a MongoDB
6) Exchange API will query MongoDB to fetch you the data
7) Geolocation between client-sentry will determine the latency until the data is served on the client
Error Codes
Error | Description |
---|---|
2 | Spot market was not found or is no longer active |
5 | Invalid market ID |
6 | Subaccount has insufficient deposits |
7 | Invalid order type, sender or fee_recipient address |
8 | Position quantity is insufficient for the order (i.e. an RO order cannot be placed if a better order, that would flip the position exists) |
9 | Invalid order hash |
10 | Subaccount ID is invalid or does not correspond to the sender's address |
16 | Invalid price (i.e. the order price is nil, negative or has wrong tick sizes) |
17 | Invalid quantity (i.e. the order quantity is nil, negative or has wrong tick sizes) |
26 | Order has insufficient margin (i.e. if the margin is less than the initial margin ratio) |
27 | Derivative market was not found or is no longer active |
28 | Position not found (i.e. when placing RO order with no position open) |
29 | Position direction does not oppose the RO order (i.e. when trying to place a sell RO with a short position) |
30 | Price surpasses bankruptcy price (i.e. when trying to place an order that would close the position below the bankruptcy price) |
32 | Invalid trigger price |
36 | Invalid minimum order margin (margin is not a multiple of the tick size) |
37 | Exceeds the order side count in derivatives (per market, per subaccount & per side) |
39 | Cannot place a conditional market order when a conditional market order in the same relative direction already exists |
58 | Message contains cancel all MarketIDs but no SubaccountID or duplicate values |
59 | Post-only order exceeds top of book price |
60 | Limit order cannot be atomic |
81 | No margin locked in the subaccount (when placing RO conditional order with no position or vanilla order) |
95 | Insufficient balance |
96 | Exchange is in post-only mode (the chain has resumed activities after an upgrade and trading has not been enabled yet) |
97 | Client order ID already exists |
98 | Client order ID is invalid. Max length is 36 characters |