Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
71b34aa
[CHORE] Updated project version to v1.12.0-rc1
aarmoa Jul 28, 2025
8c6b3f5
Merge pull request #392 from InjectiveLabs/chore/sync_with_master_aft…
aarmoa Jul 28, 2025
95f9b21
feat: added a new example script to search for liquidable positions
aarmoa Aug 1, 2025
65f0426
fix: fix liquidation price calculation in the liquidable positions ex…
aarmoa Aug 1, 2025
a7d26e6
fix: fixed the position liquidation price calculation in the liquidab…
aarmoa Aug 1, 2025
987e82b
fix: fixed the position liquidation price calculation in the liquidab…
aarmoa Aug 1, 2025
1c7fb55
fix: solved pre-commit issues
aarmoa Aug 1, 2025
26b9e06
Merge pull request #395 from InjectiveLabs/feat/add_liquidable_positi…
aarmoa Aug 1, 2025
bdd321b
Update README.md
aarmoa Jul 29, 2025
251ae51
(fix) Fixed the v1 AsyncClient orderbooks queries to include the dept…
aarmoa Aug 20, 2025
10509e6
(fix) Fixed pre-commit errors
aarmoa Aug 20, 2025
c22a799
(fix) Fixed pre-commit errors
aarmoa Aug 20, 2025
403ccff
(feat) Updated proto definitions to match Injective core v1.16.4 and …
aarmoa Sep 23, 2025
76e43be
(fix) Fixed pre-commit issues
aarmoa Sep 23, 2025
6a54b6a
(fix) Updated the official tokens JSON files URLs
aarmoa Sep 23, 2025
0c7e085
(fix) Fixed pre-commit issues
aarmoa Sep 23, 2025
15adf6d
Merge pull request #399 from InjectiveLabs/feat/sync_dev_with_master_…
aarmoa Sep 24, 2025
05d6a6e
Merge branch 'master' of https://github.com/InjectiveLabs/sdk-python …
aarmoa Oct 23, 2025
226c092
Merge pull request #401 from InjectiveLabs/chore/sync_dev_with_master…
aarmoa Oct 23, 2025
e42bd38
(feat) Updated proto definitions to injective-core v1.17.0-beta.3 and…
aarmoa Oct 23, 2025
4d134c8
(fix) Fixed pre-commit errors
aarmoa Oct 23, 2025
74bd9d2
(feat) Updated proto definitions to injective-core v1.17.0 and indexe…
aarmoa Nov 10, 2025
8645426
Merge pull request #400 from InjectiveLabs/cp-652/update_protos_for_v…
aarmoa Nov 10, 2025
629d62e
(fix) Updated CHANGELOG.md to include v1.12.0 details
aarmoa Nov 10, 2025
162ad40
(fix) Fixed pre-commit issues
aarmoa Nov 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

All notable changes to this project will be documented in this file.

## [1.12.0] - 2025-11-10
### Changed
- Updated all compiled protos for compatibility with Injective core v1.17.0 and Indexer v1.17.16
- Included the OpenNotionalCap in derivative markets
- Added support for market orders creation with the MsgBatchUpdateOrders message
- Support for order failure events and conditional orders trigger failures in the chainstrem updates

## [1.11.2] - 2025-09-24
### Added
- Added support in v2 Composer to create the new exchange module MsgCancelPostOnlyMode message
Expand Down
7 changes: 1 addition & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,14 @@ fix-generated-proto-imports:
@find ./pyinjective/proto -type f -name "*.py" -exec sed -i "" -e "s/from google.api/from pyinjective.proto.google.api/g" {} \;

define clean_repos
rm -Rf cosmos-sdk
rm -Rf ibc-go
rm -Rf cometbft
rm -Rf wasmd
rm -Rf injective-core
rm -Rf injective-indexer
endef

clean-all:
$(call clean_repos)

clone-injective-indexer:
git clone https://github.com/InjectiveLabs/injective-indexer.git -b v1.16.91 --depth 1 --single-branch
git clone https://github.com/InjectiveLabs/injective-indexer.git -b v1.17.16 --depth 1 --single-branch

clone-all: clone-injective-indexer

Expand Down
13 changes: 8 additions & 5 deletions buf.gen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,21 @@ inputs:
- module: buf.build/googleapis/googleapis
- module: buf.build/cosmos/ics23
- git_repo: https://github.com/InjectiveLabs/ibc-go
tag: v8.7.0-evm-comet1-inj
tag: v8.7.0-inj.3
- git_repo: https://github.com/InjectiveLabs/wasmd
tag: v0.53.3-evm-comet1-inj
tag: v0.53.3-inj.2
- git_repo: https://github.com/InjectiveLabs/cometbft
tag: v1.0.1-inj.3
tag: v1.0.1-inj.4
- git_repo: https://github.com/InjectiveLabs/cosmos-sdk
tag: v0.50.13-evm-comet1-inj.6
tag: v0.50.14-inj
# - git_repo: https://github.com/InjectiveLabs/wasmd
# branch: v0.51.x-inj
# subdir: proto
- git_repo: https://github.com/InjectiveLabs/hyperlane-cosmos
tag: v1.0.1-inj
subdir: proto
- git_repo: https://github.com/InjectiveLabs/injective-core
tag: v1.16.4
tag: v1.17.0
subdir: proto
# - git_repo: https://github.com/InjectiveLabs/injective-core
# branch: master
Expand Down
76 changes: 76 additions & 0 deletions examples/chain_client/10_SearchLiquidablePositions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import asyncio
from decimal import Decimal

from pyinjective.async_client_v2 import AsyncClient
from pyinjective.core.network import Network


def adjusted_margin(
quantity: Decimal, margin: Decimal, is_long: bool, cumulative_funding_entry: Decimal, cumulative_funding: Decimal
) -> Decimal:
unrealized_funding_payment = (cumulative_funding - cumulative_funding_entry) * quantity * (-1 if is_long else 1)
return margin + unrealized_funding_payment


async def main() -> None:
# select network: local, testnet, mainnet
network = Network.mainnet()

# initialize grpc client
client = AsyncClient(network)

positions_per_market = dict()

positions_dict = await client.fetch_chain_positions()
liquidable_positions = []

for position in positions_dict["state"]:
if position["marketId"] not in positions_per_market:
positions_per_market[position["marketId"]] = []
positions_per_market[position["marketId"]].append(position)

derivative_markets = await client.fetch_chain_derivative_markets(
status="Active",
market_ids=list(positions_per_market.keys()),
)

for market in derivative_markets["markets"]:
client_market = (await client.all_derivative_markets())[market["market"]["marketId"]]
market_mark_price = client_market._from_extended_chain_format(Decimal(market["markPrice"]))
for position in positions_per_market[client_market.id]:
is_long = position["position"]["isLong"]
quantity = client_market._from_extended_chain_format(Decimal(position["position"]["quantity"]))
entry_price = client_market._from_extended_chain_format(Decimal(position["position"]["entryPrice"]))
margin = client_market._from_extended_chain_format(Decimal(position["position"]["margin"]))
cumulative_funding_entry = client_market._from_extended_chain_format(
Decimal(position["position"]["cumulativeFundingEntry"])
)
market_cumulative_funding = client_market._from_extended_chain_format(
Decimal(market["perpetualInfo"]["fundingInfo"]["cumulativeFunding"])
)

adj_margin = adjusted_margin(quantity, margin, is_long, cumulative_funding_entry, market_cumulative_funding)
adjusted_unit_margin = (adj_margin / quantity) * (-1 if is_long else 1)
maintenance_margin_ratio = client_market.maintenance_margin_ratio * (-1 if is_long else 1)

liquidation_price = (entry_price + adjusted_unit_margin) / (Decimal(1) + maintenance_margin_ratio)

should_be_liquidated = (is_long and market_mark_price <= liquidation_price) or (
not is_long and market_mark_price >= liquidation_price
)

if should_be_liquidated:
position_side = "Long" if is_long else "Short"
print(
f"{position_side} position for market {client_market.id} and subaccount "
f"{position['subaccountId']} should be liquidated (liquidation price: "
f"{liquidation_price.normalize()} / mark price: {market_mark_price.normalize()})"
)
liquidable_positions.append(position)

# print(f"\n\n\n")
# print(json.dumps(liquidable_positions, indent=4))


if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
8 changes: 8 additions & 0 deletions examples/chain_client/7_ChainStream.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ async def main() -> None:
subaccount_ids=[subaccount_id], market_ids=[inj_usdt_perp_market]
)
oracle_price_filter = composer.chain_stream_oracle_price_filter(symbols=["INJ", "USDT"])
order_failures_filter = composer.chain_stream_order_failures_filter(
accounts=["inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r"]
)
conditional_order_trigger_failures_filter = composer.chain_stream_conditional_order_trigger_failures_filter(
subaccount_ids=[subaccount_id], market_ids=[inj_usdt_perp_market]
)

task = asyncio.get_event_loop().create_task(
client.listen_chain_stream_updates(
Expand All @@ -66,6 +72,8 @@ async def main() -> None:
derivative_orderbooks_filter=derivative_orderbooks_filter,
positions_filter=positions_filter,
oracle_price_filter=oracle_price_filter,
order_failures_filter=order_failures_filter,
conditional_order_trigger_failures_filter=conditional_order_trigger_failures_filter,
)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ async def main() -> None:
min_price_tick_size=Decimal("0.01"),
min_quantity_tick_size=Decimal("0.01"),
min_notional=Decimal("1"),
open_notional_cap=composer.uncapped_open_notional_cap(),
)

# broadcast the transaction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ async def main() -> None:
new_initial_margin_ratio=Decimal("0.40"),
new_maintenance_margin_ratio=Decimal("0.085"),
new_reduce_margin_ratio=Decimal("3.5"),
new_open_notional_cap=composer.uncapped_open_notional_cap(),
)

# broadcast the transaction
Expand Down
68 changes: 68 additions & 0 deletions examples/chain_client/exchange/30_MsgOffsetPosition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import asyncio
import json
import os

import dotenv

from pyinjective.async_client_v2 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()

gas_price = await client.current_chain_gas_price()
# adjust gas price to make it valid even if it changes between the time it is requested and the TX is broadcasted
gas_price = int(gas_price * 1.1)

message_broadcaster = MsgBroadcasterWithPk.new_using_simulation(
network=network,
private_key=configured_private_key,
gas_price=gas_price,
client=client,
composer=composer,
)

# 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())

offsetting_subaccount_ids = {
"0xbdaedec95d563fb05240d6e01821008454c24c36000000000000000000000000",
"0xaf79152ac5df276d9a8e1e2e22822f9713474902000000000000000000000000",
}

# prepare tx msg
message = composer.msg_offset_position(
sender=address.to_acc_bech32(),
subaccount_id=address.get_subaccount_id(index=0),
market_id="0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6",
offsetting_subaccount_ids=offsetting_subaccount_ids,
)

# broadcast the transaction
result = await message_broadcaster.broadcast([message])
print("---Transaction Response---")
print(json.dumps(result, indent=2))

gas_price = await client.current_chain_gas_price()
# adjust gas price to make it valid even if it changes between the time it is requested and the TX is broadcasted
gas_price = int(gas_price * 1.1)
message_broadcaster.update_gas_price(gas_price=gas_price)


if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ async def main() -> None:
min_price_tick_size=Decimal("0.001"),
min_quantity_tick_size=Decimal("0.01"),
min_notional=Decimal("1"),
open_notional_cap=composer.uncapped_open_notional_cap(),
)

# broadcast the transaction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ async def main() -> None:
min_price_tick_size=Decimal("0.001"),
min_quantity_tick_size=Decimal("0.01"),
min_notional=Decimal("1"),
open_notional_cap=composer.uncapped_open_notional_cap(),
)

# broadcast the transaction
Expand Down
29 changes: 29 additions & 0 deletions examples/chain_client/exchange/9_MsgBatchUpdateOrders.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,21 @@ async def main() -> None:
),
]

derivative_market_orders_to_create = [
composer.derivative_order(
market_id=derivative_market_id_create,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal(25100),
quantity=Decimal(0.1),
margin=composer.calculate_margin(
quantity=Decimal(0.1), price=Decimal(25100), leverage=Decimal(1), is_reduce_only=False
),
order_type="BUY",
cid=str(uuid.uuid4()),
),
]

spot_orders_to_create = [
composer.spot_order(
market_id=spot_market_id_create,
Expand All @@ -125,13 +140,27 @@ async def main() -> None:
),
]

spot_market_orders_to_create = [
composer.spot_order(
market_id=spot_market_id_create,
subaccount_id=subaccount_id,
fee_recipient=fee_recipient,
price=Decimal("3.5"),
quantity=Decimal("1"),
order_type="BUY",
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,
spot_market_orders_to_create=spot_market_orders_to_create,
derivative_market_orders_to_create=derivative_market_orders_to_create,
)

# broadcast the transaction
Expand Down
24 changes: 24 additions & 0 deletions examples/chain_client/exchange/query/66_OpenInterest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import asyncio
import json

from pyinjective.async_client_v2 import AsyncClient
from pyinjective.core.network import Network


async def main() -> None:
"""
Demonstrate fetching denom min notionals using AsyncClient.
"""
# Select network: choose between Network.mainnet(), Network.testnet(), or Network.devnet()
network = Network.testnet()

# Initialize the Async Client
client = AsyncClient(network)

market_id = "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6"
open_interest = await client.fetch_open_interest(market_id=market_id)
print(json.dumps(open_interest, indent=2))


if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ async def main() -> None:
# initialize grpc client
client = AsyncClient(network)

deposits = await client.fetch_denom_decimal(denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5")
deposits = await client.fetch_auction_exchange_transfer_denom_decimal(
denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"
)
print(deposits)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ async def main() -> None:
# initialize grpc client
client = AsyncClient(network)

deposits = await client.fetch_denom_decimals(denoms=["inj", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"])
deposits = await client.fetch_auction_exchange_transfer_denom_decimals(
denoms=["inj", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"]
)
print(deposits)


Expand Down
Loading