From 1606c4ec2ecbb1f657e10b33dc0893c8e0c08142 Mon Sep 17 00:00:00 2001 From: abel Date: Thu, 18 Jan 2024 15:27:09 -0300 Subject: [PATCH] (fix) Updated the logic to create the MsgLiquidatePosition. Added a new example script on how to broadcast a MsgLiquidatePosition --- CHANGELOG.md | 4 + .../chain_client/77_MsgLiquidatePosition.py | 101 ++++++++++++++++++ pyinjective/composer.py | 10 +- pyproject.toml | 2 +- 4 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 examples/chain_client/77_MsgLiquidatePosition.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 8be39513..2fee1443 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to this project will be documented in this file. +## [1.1.1] - 2024-01-18 +### Changed +- Updated the logic to create a `MsgLiquidatePosition` message + ## [1.1.0] - 2024-01-15 ### Added - Added new functions in all Market classes to convert values from extended chain format (the ones provided by chain streams) into human-readable format diff --git a/examples/chain_client/77_MsgLiquidatePosition.py b/examples/chain_client/77_MsgLiquidatePosition.py new file mode 100644 index 00000000..65e7f12b --- /dev/null +++ b/examples/chain_client/77_MsgLiquidatePosition.py @@ -0,0 +1,101 @@ +import asyncio +import uuid + +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: + # 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("f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3") + 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.DerivativeOrder( + market_id=market_id, + subaccount_id=subaccount_id, + fee_recipient=fee_recipient, + price=39.01, # This should be the liquidation price + quantity=0.147, + leverage=1, + cid=cid, + is_buy=False, + ) + + # prepare tx msg + msg = composer.MsgLiquidatePosition( + 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()) diff --git a/pyinjective/composer.py b/pyinjective/composer.py index e40e36e2..720920d1 100644 --- a/pyinjective/composer.py +++ b/pyinjective/composer.py @@ -671,9 +671,15 @@ def MsgBatchUpdateOrders(self, sender: str, **kwargs): binary_options_orders_to_create=kwargs.get("binary_options_orders_to_create"), ) - def MsgLiquidatePosition(self, sender: str, subaccount_id: str, market_id: str): + def MsgLiquidatePosition( + self, + sender: str, + subaccount_id: str, + market_id: str, + order: Optional[injective_dot_exchange_dot_v1beta1_dot_exchange__pb2.DerivativeOrder] = None, + ): return injective_exchange_tx_pb.MsgLiquidatePosition( - sender=sender, subaccount_id=subaccount_id, market_id=market_id + sender=sender, subaccount_id=subaccount_id, market_id=market_id, order=order ) def MsgIncreasePositionMargin( diff --git a/pyproject.toml b/pyproject.toml index a15c4162..870533bc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "injective-py" -version = "1.1.0" +version = "1.1.1" description = "Injective Python SDK, with Exchange API Client" authors = ["Injective Labs "] license = "Apache-2.0"