diff --git a/CHANGELOG.md b/CHANGELOG.md index 6225b4ea..a6094ec5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to this project will be documented in this file. +## [1.3.0] - 2024-02-12 +### Changed +- Removed `asyncio` from the dependencies + ## [1.2.0] - 2024-01-25 ### Changed - Updated reference gas cost for all messages in the gas estimator diff --git a/examples/chain_client/0_LocalOrderHash.py b/examples/chain_client/0_LocalOrderHash.py index a25398c6..770ad5bf 100644 --- a/examples/chain_client/0_LocalOrderHash.py +++ b/examples/chain_client/0_LocalOrderHash.py @@ -113,7 +113,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) @@ -150,7 +150,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) @@ -240,7 +240,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/13_MsgIncreasePositionMargin.py b/examples/chain_client/13_MsgIncreasePositionMargin.py index f54910f8..775a41e5 100644 --- a/examples/chain_client/13_MsgIncreasePositionMargin.py +++ b/examples/chain_client/13_MsgIncreasePositionMargin.py @@ -66,7 +66,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/15_MsgWithdraw.py b/examples/chain_client/15_MsgWithdraw.py index a8c267d8..b198c0aa 100644 --- a/examples/chain_client/15_MsgWithdraw.py +++ b/examples/chain_client/15_MsgWithdraw.py @@ -57,7 +57,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/16_MsgSubaccountTransfer.py b/examples/chain_client/16_MsgSubaccountTransfer.py index d87eb0ed..b68717b2 100644 --- a/examples/chain_client/16_MsgSubaccountTransfer.py +++ b/examples/chain_client/16_MsgSubaccountTransfer.py @@ -64,7 +64,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/17_MsgBatchUpdateOrders.py b/examples/chain_client/17_MsgBatchUpdateOrders.py index 557ffe46..9efdc0a0 100644 --- a/examples/chain_client/17_MsgBatchUpdateOrders.py +++ b/examples/chain_client/17_MsgBatchUpdateOrders.py @@ -153,7 +153,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/18_MsgBid.py b/examples/chain_client/18_MsgBid.py index 8e5f8d5e..1efaa3e3 100644 --- a/examples/chain_client/18_MsgBid.py +++ b/examples/chain_client/18_MsgBid.py @@ -56,7 +56,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/19_MsgGrant.py b/examples/chain_client/19_MsgGrant.py index 32a82fe7..111a050c 100644 --- a/examples/chain_client/19_MsgGrant.py +++ b/examples/chain_client/19_MsgGrant.py @@ -76,7 +76,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/1_MsgSend.py b/examples/chain_client/1_MsgSend.py index 6389c8be..1d926898 100644 --- a/examples/chain_client/1_MsgSend.py +++ b/examples/chain_client/1_MsgSend.py @@ -61,7 +61,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/20_MsgExec.py b/examples/chain_client/20_MsgExec.py index d5ff2dc5..1203ff90 100644 --- a/examples/chain_client/20_MsgExec.py +++ b/examples/chain_client/20_MsgExec.py @@ -83,7 +83,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/21_MsgRevoke.py b/examples/chain_client/21_MsgRevoke.py index 82663004..91bb192d 100644 --- a/examples/chain_client/21_MsgRevoke.py +++ b/examples/chain_client/21_MsgRevoke.py @@ -61,7 +61,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/22_MsgSendToEth.py b/examples/chain_client/22_MsgSendToEth.py index 59bdc877..06e2d78c 100644 --- a/examples/chain_client/22_MsgSendToEth.py +++ b/examples/chain_client/22_MsgSendToEth.py @@ -70,7 +70,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/23_MsgRelayPriceFeedPrice.py b/examples/chain_client/23_MsgRelayPriceFeedPrice.py index cc7055c9..b59b34a3 100644 --- a/examples/chain_client/23_MsgRelayPriceFeedPrice.py +++ b/examples/chain_client/23_MsgRelayPriceFeedPrice.py @@ -61,7 +61,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/24_MsgRewardsOptOut.py b/examples/chain_client/24_MsgRewardsOptOut.py index 5fa2f429..8beaa1f4 100644 --- a/examples/chain_client/24_MsgRewardsOptOut.py +++ b/examples/chain_client/24_MsgRewardsOptOut.py @@ -56,7 +56,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/25_MsgDelegate.py b/examples/chain_client/25_MsgDelegate.py index ada14ce0..e32f6691 100644 --- a/examples/chain_client/25_MsgDelegate.py +++ b/examples/chain_client/25_MsgDelegate.py @@ -61,7 +61,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/26_MsgWithdrawDelegatorReward.py b/examples/chain_client/26_MsgWithdrawDelegatorReward.py deleted file mode 100644 index f9370c23..00000000 --- a/examples/chain_client/26_MsgWithdrawDelegatorReward.py +++ /dev/null @@ -1,81 +0,0 @@ -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" - - msg = composer.MsgWithdrawDelegatorReward( - delegator_address=address.to_acc_bech32(), validator_address=validator_address - ) - - # 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()) diff --git a/examples/chain_client/2_MsgDeposit.py b/examples/chain_client/2_MsgDeposit.py index 80587c55..80b9f652 100644 --- a/examples/chain_client/2_MsgDeposit.py +++ b/examples/chain_client/2_MsgDeposit.py @@ -57,7 +57,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/30_ExternalTransfer.py b/examples/chain_client/30_ExternalTransfer.py index 7ab6e0f2..3200be34 100644 --- a/examples/chain_client/30_ExternalTransfer.py +++ b/examples/chain_client/30_ExternalTransfer.py @@ -64,7 +64,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py b/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py index 57f5537b..2a58e173 100644 --- a/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py +++ b/examples/chain_client/31_MsgCreateBinaryOptionsLimitOrder.py @@ -81,7 +81,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py b/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py index 473e8e53..2d07658f 100644 --- a/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py +++ b/examples/chain_client/32_MsgCreateBinaryOptionsMarketOrder.py @@ -75,7 +75,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py b/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py index 15159f00..82107f3c 100644 --- a/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py +++ b/examples/chain_client/33_MsgCancelBinaryOptionsOrder.py @@ -66,7 +66,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py b/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py index 55c308be..0f39dcdb 100644 --- a/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py +++ b/examples/chain_client/34_MsgAdminUpdateBinaryOptionsMarket.py @@ -74,7 +74,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py b/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py index 7e865320..7b8a6567 100644 --- a/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py +++ b/examples/chain_client/35_MsgInstantBinaryOptionsMarketLaunch.py @@ -76,7 +76,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/36_MsgRelayProviderPrices.py b/examples/chain_client/36_MsgRelayProviderPrices.py index 4ee5fc3f..1e3b9c8f 100644 --- a/examples/chain_client/36_MsgRelayProviderPrices.py +++ b/examples/chain_client/36_MsgRelayProviderPrices.py @@ -66,7 +66,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/3_MsgCreateSpotLimitOrder.py b/examples/chain_client/3_MsgCreateSpotLimitOrder.py index dd06672a..d3ca5f16 100644 --- a/examples/chain_client/3_MsgCreateSpotLimitOrder.py +++ b/examples/chain_client/3_MsgCreateSpotLimitOrder.py @@ -77,7 +77,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/40_MsgExecuteContract.py b/examples/chain_client/40_MsgExecuteContract.py index f2d1b719..d18c6398 100644 --- a/examples/chain_client/40_MsgExecuteContract.py +++ b/examples/chain_client/40_MsgExecuteContract.py @@ -33,12 +33,12 @@ async def main() -> None: # prepare tx msg # NOTE: COIN MUST BE SORTED IN ALPHABETICAL ORDER BY DENOMS funds = [ - composer.Coin( + composer.coin( amount=69, denom="factory/inj1hdvy6tl89llqy3ze8lv6mz5qh66sx9enn0jxg6/inj12ngevx045zpvacus9s6anr258gkwpmthnz80e9", ), - composer.Coin(amount=420, denom="peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7"), - composer.Coin(amount=1, denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"), + composer.coin(amount=420, denom="peggy0x44C21afAaF20c270EBbF5914Cfc3b5022173FEB7"), + composer.coin(amount=1, denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5"), ] msg = composer.MsgExecuteContract( sender=address.to_acc_bech32(), @@ -71,7 +71,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/41_MsgCreateInsuranceFund.py b/examples/chain_client/41_MsgCreateInsuranceFund.py index 74f94bfa..99c10fc0 100644 --- a/examples/chain_client/41_MsgCreateInsuranceFund.py +++ b/examples/chain_client/41_MsgCreateInsuranceFund.py @@ -65,7 +65,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/42_MsgUnderwrite.py b/examples/chain_client/42_MsgUnderwrite.py index 20c65a64..16b75e70 100644 --- a/examples/chain_client/42_MsgUnderwrite.py +++ b/examples/chain_client/42_MsgUnderwrite.py @@ -61,7 +61,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/43_MsgRequestRedemption.py b/examples/chain_client/43_MsgRequestRedemption.py index 4413044b..ecc2793c 100644 --- a/examples/chain_client/43_MsgRequestRedemption.py +++ b/examples/chain_client/43_MsgRequestRedemption.py @@ -61,7 +61,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/48_WithdrawValidatorCommissionAndRewards.py b/examples/chain_client/48_WithdrawValidatorCommissionAndRewards.py deleted file mode 100644 index 2f67f6c4..00000000 --- a/examples/chain_client/48_WithdrawValidatorCommissionAndRewards.py +++ /dev/null @@ -1,86 +0,0 @@ -import asyncio -import os - -import dotenv -from grpc import RpcError - -from pyinjective.async_client import AsyncClient -from pyinjective.composer import Composer as ProtoMsgComposer -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") - - """For a validator to withdraw his rewards & commissions simultaneously""" - # select network: local, testnet, mainnet - network = Network.testnet() - composer = ProtoMsgComposer(network=network.string()) - - # initialize grpc client - client = AsyncClient(network, insecure=False) - await client.sync_timeout_height() - - # load account - # private key is that from the validator's wallet - 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" - - msg0 = composer.MsgWithdrawDelegatorReward( - delegator_address=address.to_acc_bech32(), validator_address=validator_address - ) - - msg1 = composer.MsgWithdrawValidatorCommission(validator_address=validator_address) - - # build sim tx - tx = ( - Transaction() - .with_messages(msg0, msg1) - .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()) diff --git a/examples/chain_client/4_MsgCreateSpotMarketOrder.py b/examples/chain_client/4_MsgCreateSpotMarketOrder.py index 06a42a96..5229632f 100644 --- a/examples/chain_client/4_MsgCreateSpotMarketOrder.py +++ b/examples/chain_client/4_MsgCreateSpotMarketOrder.py @@ -75,7 +75,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/5_MsgCancelSpotOrder.py b/examples/chain_client/5_MsgCancelSpotOrder.py index 63167309..970b2190 100644 --- a/examples/chain_client/5_MsgCancelSpotOrder.py +++ b/examples/chain_client/5_MsgCancelSpotOrder.py @@ -63,7 +63,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py b/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py index e46f1acb..41a19307 100644 --- a/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py +++ b/examples/chain_client/6_MsgCreateDerivativeLimitOrder.py @@ -77,7 +77,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/72_MsgMint.py b/examples/chain_client/72_MsgMint.py index d38449be..b6617431 100644 --- a/examples/chain_client/72_MsgMint.py +++ b/examples/chain_client/72_MsgMint.py @@ -26,7 +26,7 @@ async def main() -> None: 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") + amount = composer.coin(amount=1_000_000_000, denom="factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test") message = composer.msg_mint( sender=address.to_acc_bech32(), diff --git a/examples/chain_client/73_MsgBurn.py b/examples/chain_client/73_MsgBurn.py index 441f4ee8..c4aa013a 100644 --- a/examples/chain_client/73_MsgBurn.py +++ b/examples/chain_client/73_MsgBurn.py @@ -26,7 +26,7 @@ async def main() -> None: pub_key = priv_key.to_public_key() address = pub_key.to_address() - amount = composer.Coin(amount=100, denom="factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test") + amount = composer.coin(amount=100, denom="factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test") message = composer.msg_burn( sender=address.to_acc_bech32(), diff --git a/examples/chain_client/76_MsgExecuteContractCompat.py b/examples/chain_client/76_MsgExecuteContractCompat.py index 892c125f..a195c7c4 100644 --- a/examples/chain_client/76_MsgExecuteContractCompat.py +++ b/examples/chain_client/76_MsgExecuteContractCompat.py @@ -68,7 +68,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/77_MsgLiquidatePosition.py b/examples/chain_client/77_MsgLiquidatePosition.py index 6dcbacfb..d80ba385 100644 --- a/examples/chain_client/77_MsgLiquidatePosition.py +++ b/examples/chain_client/77_MsgLiquidatePosition.py @@ -83,7 +83,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py b/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py index e7e06c62..37b305ed 100644 --- a/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py +++ b/examples/chain_client/7_MsgCreateDerivativeMarketOrder.py @@ -76,7 +76,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/8_MsgCancelDerivativeOrder.py b/examples/chain_client/8_MsgCancelDerivativeOrder.py index 6a59167a..43180b1f 100644 --- a/examples/chain_client/8_MsgCancelDerivativeOrder.py +++ b/examples/chain_client/8_MsgCancelDerivativeOrder.py @@ -63,7 +63,7 @@ async def main() -> None: 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( + composer.coin( amount=gas_price * gas_limit, denom=network.fee_denom, ) diff --git a/examples/chain_client/distribution/10_SetWithdrawAddress.py b/examples/chain_client/distribution/10_SetWithdrawAddress.py new file mode 100644 index 00000000..b317a998 --- /dev/null +++ b/examples/chain_client/distribution/10_SetWithdrawAddress.py @@ -0,0 +1,46 @@ +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()) diff --git a/examples/chain_client/distribution/11_WithdrawDelegatorReward.py b/examples/chain_client/distribution/11_WithdrawDelegatorReward.py new file mode 100644 index 00000000..02facdc7 --- /dev/null +++ b/examples/chain_client/distribution/11_WithdrawDelegatorReward.py @@ -0,0 +1,47 @@ +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()) diff --git a/examples/chain_client/distribution/12_WithdrawValidatorCommission.py b/examples/chain_client/distribution/12_WithdrawValidatorCommission.py new file mode 100644 index 00000000..cd351d1f --- /dev/null +++ b/examples/chain_client/distribution/12_WithdrawValidatorCommission.py @@ -0,0 +1,45 @@ +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()) diff --git a/examples/chain_client/distribution/13_FundCommunityPool.py b/examples/chain_client/distribution/13_FundCommunityPool.py new file mode 100644 index 00000000..c60475c8 --- /dev/null +++ b/examples/chain_client/distribution/13_FundCommunityPool.py @@ -0,0 +1,47 @@ +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()) diff --git a/examples/chain_client/distribution/1_ValidatorDistributionInfo.py b/examples/chain_client/distribution/1_ValidatorDistributionInfo.py new file mode 100644 index 00000000..13161630 --- /dev/null +++ b/examples/chain_client/distribution/1_ValidatorDistributionInfo.py @@ -0,0 +1,16 @@ +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()) diff --git a/examples/chain_client/distribution/2_ValidatorOutstandingRewards.py b/examples/chain_client/distribution/2_ValidatorOutstandingRewards.py new file mode 100644 index 00000000..31833682 --- /dev/null +++ b/examples/chain_client/distribution/2_ValidatorOutstandingRewards.py @@ -0,0 +1,16 @@ +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()) diff --git a/examples/chain_client/distribution/3_ValidatorCommission.py b/examples/chain_client/distribution/3_ValidatorCommission.py new file mode 100644 index 00000000..a82e191b --- /dev/null +++ b/examples/chain_client/distribution/3_ValidatorCommission.py @@ -0,0 +1,16 @@ +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()) diff --git a/examples/chain_client/distribution/4_ValidatorSlashes.py b/examples/chain_client/distribution/4_ValidatorSlashes.py new file mode 100644 index 00000000..08dbfea1 --- /dev/null +++ b/examples/chain_client/distribution/4_ValidatorSlashes.py @@ -0,0 +1,20 @@ +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()) diff --git a/examples/chain_client/distribution/5_DelegationRewards.py b/examples/chain_client/distribution/5_DelegationRewards.py new file mode 100644 index 00000000..da112263 --- /dev/null +++ b/examples/chain_client/distribution/5_DelegationRewards.py @@ -0,0 +1,19 @@ +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()) diff --git a/examples/chain_client/distribution/6_DelegationTotalRewards.py b/examples/chain_client/distribution/6_DelegationTotalRewards.py new file mode 100644 index 00000000..c67dc94f --- /dev/null +++ b/examples/chain_client/distribution/6_DelegationTotalRewards.py @@ -0,0 +1,18 @@ +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()) diff --git a/examples/chain_client/distribution/7_DelegatorValidators.py b/examples/chain_client/distribution/7_DelegatorValidators.py new file mode 100644 index 00000000..f03fb8ec --- /dev/null +++ b/examples/chain_client/distribution/7_DelegatorValidators.py @@ -0,0 +1,18 @@ +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()) diff --git a/examples/chain_client/distribution/8_DelegatorWithdrawAddress.py b/examples/chain_client/distribution/8_DelegatorWithdrawAddress.py new file mode 100644 index 00000000..d3c27091 --- /dev/null +++ b/examples/chain_client/distribution/8_DelegatorWithdrawAddress.py @@ -0,0 +1,18 @@ +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()) diff --git a/examples/chain_client/distribution/9_CommunityPool.py b/examples/chain_client/distribution/9_CommunityPool.py new file mode 100644 index 00000000..7a803d03 --- /dev/null +++ b/examples/chain_client/distribution/9_CommunityPool.py @@ -0,0 +1,15 @@ +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()) diff --git a/poetry.lock b/poetry.lock index 72bd53e3..082dfb36 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1395,13 +1395,13 @@ test = ["eth-utils (>=1.0.1,<3)", "hypothesis (>=3.44.24,<=6.31.6)", "pytest (>= [[package]] name = "identify" -version = "2.5.33" +version = "2.5.34" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.33-py2.py3-none-any.whl", hash = "sha256:d40ce5fcd762817627670da8a7d8d8e65f24342d14539c59488dc603bf662e34"}, - {file = "identify-2.5.33.tar.gz", hash = "sha256:161558f9fe4559e1557e1bff323e8631f6a0e4837f7497767c1782832f16b62d"}, + {file = "identify-2.5.34-py2.py3-none-any.whl", hash = "sha256:a4316013779e433d08b96e5eabb7f641e6c7942e4ab5d4c509ebd2e7a8994aed"}, + {file = "identify-2.5.34.tar.gz", hash = "sha256:ee17bc9d499899bc9eaec1ac7bf2dc9eedd480db9d88b96d123d3b64a9d34f5d"}, ] [package.extras] @@ -1785,13 +1785,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "3.6.0" +version = "3.6.1" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" files = [ - {file = "pre_commit-3.6.0-py2.py3-none-any.whl", hash = "sha256:c255039ef399049a5544b6ce13d135caba8f2c28c3b4033277a788f434308376"}, - {file = "pre_commit-3.6.0.tar.gz", hash = "sha256:d30bad9abf165f7785c15a21a1f46da7d0677cb00ee7ff4c579fd38922efe15d"}, + {file = "pre_commit-3.6.1-py2.py3-none-any.whl", hash = "sha256:9fe989afcf095d2c4796ce7c553cf28d4d4a9b9346de3cda079bcf40748454a4"}, + {file = "pre_commit-3.6.1.tar.gz", hash = "sha256:c90961d8aa706f75d60935aba09469a6b0bcb8345f127c3fbee4bdc5f114cf4b"}, ] [package.dependencies] @@ -1912,13 +1912,13 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pytest" -version = "7.4.4" +version = "8.0.0" description = "pytest: simple powerful testing with Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, - {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, + {file = "pytest-8.0.0-py3-none-any.whl", hash = "sha256:50fb9cbe836c3f20f0dfa99c565201fb75dc54c8d76373cd1bde06b06657bdb6"}, + {file = "pytest-8.0.0.tar.gz", hash = "sha256:249b1b0864530ba251b7438274c4d251c58d868edaaec8762893ad4a0d71c36c"}, ] [package.dependencies] @@ -1926,7 +1926,7 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" -pluggy = ">=0.12,<2.0" +pluggy = ">=1.3.0,<2.0" tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] @@ -1934,17 +1934,17 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no [[package]] name = "pytest-asyncio" -version = "0.23.4" +version = "0.23.5" description = "Pytest support for asyncio" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-asyncio-0.23.4.tar.gz", hash = "sha256:2143d9d9375bf372a73260e4114541485e84fca350b0b6b92674ca56ff5f7ea2"}, - {file = "pytest_asyncio-0.23.4-py3-none-any.whl", hash = "sha256:b0079dfac14b60cd1ce4691fbfb1748fe939db7d0234b5aba97197d10fbe0fef"}, + {file = "pytest-asyncio-0.23.5.tar.gz", hash = "sha256:3a048872a9c4ba14c3e90cc1aa20cbc2def7d01c7c8db3777ec281ba9c057675"}, + {file = "pytest_asyncio-0.23.5-py3-none-any.whl", hash = "sha256:4e7093259ba018d58ede7d5315131d21923a60f8a6e9ee266ce1589685c89eac"}, ] [package.dependencies] -pytest = ">=7.0.0,<8" +pytest = ">=7.0.0,<9" [package.extras] docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] @@ -2385,18 +2385,18 @@ files = [ [[package]] name = "setuptools" -version = "69.0.3" +version = "69.1.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, - {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, + {file = "setuptools-69.1.0-py3-none-any.whl", hash = "sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6"}, + {file = "setuptools-69.1.0.tar.gz", hash = "sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] @@ -2712,4 +2712,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "9e0468421485c45e3ce0e68578905dac1e50a1ed1cae8f8c6a19c91b67f36ca0" +content-hash = "531c4e91b09feb8097149a63a8cfde93152cd904df0f6616790d51ca8838dfe0" diff --git a/pyinjective/async_client.py b/pyinjective/async_client.py index e8da821b..dea12f12 100644 --- a/pyinjective/async_client.py +++ b/pyinjective/async_client.py @@ -12,6 +12,7 @@ from pyinjective.client.chain.grpc.chain_grpc_auth_api import ChainGrpcAuthApi from pyinjective.client.chain.grpc.chain_grpc_authz_api import ChainGrpcAuthZApi from pyinjective.client.chain.grpc.chain_grpc_bank_api import ChainGrpcBankApi +from pyinjective.client.chain.grpc.chain_grpc_distribution_api import ChainGrpcDistributionApi from pyinjective.client.chain.grpc.chain_grpc_token_factory_api import ChainGrpcTokenFactoryApi from pyinjective.client.chain.grpc.chain_grpc_wasm_api import ChainGrpcWasmApi from pyinjective.client.chain.grpc_stream.chain_grpc_chain_stream import ChainGrpcChainStream @@ -178,6 +179,12 @@ def __init__( metadata_query_provider=self._chain_cookie_metadata_requestor ), ) + self.distribution_api = ChainGrpcDistributionApi( + channel=self.chain_channel, + metadata_provider=lambda: self.network.chain_metadata( + metadata_query_provider=self._chain_cookie_metadata_requestor + ), + ) self.token_factory_api = ChainGrpcTokenFactoryApi( channel=self.chain_channel, metadata_provider=lambda: self.network.chain_metadata( @@ -572,6 +579,66 @@ async def fetch_send_enabled( ) -> Dict[str, Any]: return await self.bank_api.fetch_send_enabled(denoms=denoms, pagination=pagination) + async def fetch_validator_distribution_info(self, validator_address: str) -> Dict[str, Any]: + return await self.distribution_api.fetch_validator_distribution_info(validator_address=validator_address) + + async def fetch_validator_outstanding_rewards(self, validator_address: str) -> Dict[str, Any]: + return await self.distribution_api.fetch_validator_outstanding_rewards(validator_address=validator_address) + + async def fetch_validator_commission(self, validator_address: str) -> Dict[str, Any]: + return await self.distribution_api.fetch_validator_commission(validator_address=validator_address) + + async def fetch_validator_slashes( + self, + validator_address: str, + starting_height: Optional[int] = None, + ending_height: Optional[int] = None, + pagination: Optional[PaginationOption] = None, + ) -> Dict[str, Any]: + return await self.distribution_api.fetch_validator_slashes( + validator_address=validator_address, + starting_height=starting_height, + ending_height=ending_height, + pagination=pagination, + ) + + async def fetch_delegation_rewards( + self, + delegator_address: str, + validator_address: str, + ) -> Dict[str, Any]: + return await self.distribution_api.fetch_delegation_rewards( + delegator_address=delegator_address, + validator_address=validator_address, + ) + + async def fetch_delegation_total_rewards( + self, + delegator_address: str, + ) -> Dict[str, Any]: + return await self.distribution_api.fetch_delegation_total_rewards( + delegator_address=delegator_address, + ) + + async def fetch_delegator_validators( + self, + delegator_address: str, + ) -> Dict[str, Any]: + return await self.distribution_api.fetch_delegator_validators( + delegator_address=delegator_address, + ) + + async def fetch_delegator_withdraw_address( + self, + delegator_address: str, + ) -> Dict[str, Any]: + return await self.distribution_api.fetch_delegator_withdraw_address( + delegator_address=delegator_address, + ) + + async def fetch_community_pool(self) -> Dict[str, Any]: + return await self.distribution_api.fetch_community_pool() + # Injective Exchange client methods # Auction RPC diff --git a/pyinjective/client/chain/grpc/chain_grpc_distribution_api.py b/pyinjective/client/chain/grpc/chain_grpc_distribution_api.py new file mode 100644 index 00000000..e7da0966 --- /dev/null +++ b/pyinjective/client/chain/grpc/chain_grpc_distribution_api.py @@ -0,0 +1,109 @@ +from typing import Any, Callable, Dict, Optional + +from grpc.aio import Channel + +from pyinjective.client.model.pagination import PaginationOption +from pyinjective.proto.cosmos.distribution.v1beta1 import ( + query_pb2 as distribution_query_pb, + query_pb2_grpc as distribution_query_grpc, +) +from pyinjective.utils.grpc_api_request_assistant import GrpcApiRequestAssistant + + +class ChainGrpcDistributionApi: + def __init__(self, channel: Channel, metadata_provider: Callable): + self._stub = distribution_query_grpc.QueryStub(channel) + self._assistant = GrpcApiRequestAssistant(metadata_provider=metadata_provider) + + async def fetch_module_params(self) -> Dict[str, Any]: + request = distribution_query_pb.QueryParamsRequest() + response = await self._execute_call(call=self._stub.Params, request=request) + + return response + + async def fetch_validator_distribution_info(self, validator_address: str) -> Dict[str, Any]: + request = distribution_query_pb.QueryValidatorDistributionInfoRequest(validator_address=validator_address) + response = await self._execute_call(call=self._stub.ValidatorDistributionInfo, request=request) + + return response + + async def fetch_validator_outstanding_rewards(self, validator_address: str) -> Dict[str, Any]: + request = distribution_query_pb.QueryValidatorOutstandingRewardsRequest(validator_address=validator_address) + response = await self._execute_call(call=self._stub.ValidatorOutstandingRewards, request=request) + + return response + + async def fetch_validator_commission(self, validator_address: str) -> Dict[str, Any]: + request = distribution_query_pb.QueryValidatorCommissionRequest(validator_address=validator_address) + response = await self._execute_call(call=self._stub.ValidatorCommission, request=request) + + return response + + async def fetch_validator_slashes( + self, + validator_address: str, + starting_height: Optional[int] = None, + ending_height: Optional[int] = None, + pagination: Optional[PaginationOption] = None, + ) -> Dict[str, Any]: + pagination_request = None + if pagination is not None: + pagination_request = pagination.create_pagination_request() + request = distribution_query_pb.QueryValidatorSlashesRequest( + validator_address=validator_address, + starting_height=starting_height, + ending_height=ending_height, + pagination=pagination_request, + ) + response = await self._execute_call(call=self._stub.ValidatorSlashes, request=request) + + return response + + async def fetch_delegation_rewards( + self, + delegator_address: str, + validator_address: str, + ) -> Dict[str, Any]: + request = distribution_query_pb.QueryDelegationRewardsRequest( + delegator_address=delegator_address, + validator_address=validator_address, + ) + response = await self._execute_call(call=self._stub.DelegationRewards, request=request) + + return response + + async def fetch_delegation_total_rewards( + self, + delegator_address: str, + ) -> Dict[str, Any]: + request = distribution_query_pb.QueryDelegationTotalRewardsRequest( + delegator_address=delegator_address, + ) + response = await self._execute_call(call=self._stub.DelegationTotalRewards, request=request) + + return response + + async def fetch_delegator_validators(self, delegator_address: str) -> Dict[str, Any]: + request = distribution_query_pb.QueryDelegatorValidatorsRequest( + delegator_address=delegator_address, + ) + response = await self._execute_call(call=self._stub.DelegatorValidators, request=request) + + return response + + async def fetch_delegator_withdraw_address(self, delegator_address: str) -> Dict[str, Any]: + request = distribution_query_pb.QueryDelegatorWithdrawAddressRequest( + delegator_address=delegator_address, + ) + response = await self._execute_call(call=self._stub.DelegatorWithdrawAddress, request=request) + + return response + + async def fetch_community_pool(self) -> Dict[str, Any]: + request = distribution_query_pb.QueryCommunityPoolRequest() + response = await self._execute_call(call=self._stub.CommunityPool, request=request) + + return response + + async def _execute_call(self, call: Callable, request) -> Dict[str, Any]: + return await self._assistant.execute_call(call=call, request=request) diff --git a/pyinjective/composer.py b/pyinjective/composer.py index 720920d1..df353d6b 100644 --- a/pyinjective/composer.py +++ b/pyinjective/composer.py @@ -3,6 +3,7 @@ from decimal import Decimal from time import time from typing import Any, Dict, List, Optional +from warnings import warn from google.protobuf import any_pb2, json_format, timestamp_pb2 @@ -13,7 +14,10 @@ from pyinjective.proto.cosmos.authz.v1beta1 import authz_pb2 as cosmos_authz_pb, tx_pb2 as cosmos_authz_tx_pb from pyinjective.proto.cosmos.bank.v1beta1 import bank_pb2 as bank_pb, tx_pb2 as cosmos_bank_tx_pb from pyinjective.proto.cosmos.base.v1beta1 import coin_pb2 as cosmos_dot_base_dot_v1beta1_dot_coin__pb2 -from pyinjective.proto.cosmos.distribution.v1beta1 import tx_pb2 as cosmos_distribution_tx_pb +from pyinjective.proto.cosmos.distribution.v1beta1 import ( + distribution_pb2 as cosmos_distribution_pb2, + tx_pb2 as cosmos_distribution_tx_pb, +) from pyinjective.proto.cosmos.gov.v1beta1 import tx_pb2 as cosmos_gov_tx_pb from pyinjective.proto.cosmos.staking.v1beta1 import tx_pb2 as cosmos_staking_tx_pb from pyinjective.proto.cosmwasm.wasm.v1 import tx_pb2 as wasm_tx_pb @@ -129,8 +133,27 @@ def __init__( self.tokens = tokens def Coin(self, amount: int, denom: str): + """ + This method is deprecated and will be removed soon. Please use `coin` instead + """ + warn("This method is deprecated. Use coin instead", DeprecationWarning, stacklevel=2) return cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin(amount=str(amount), denom=denom) + def coin(self, amount: int, denom: str): + """ + This method create an instance of Coin gRPC type, considering the amount is already expressed in chain format + """ + formatted_amount_string = str(int(amount)) + return cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin(amount=formatted_amount_string, denom=denom) + + def create_coin_amount(self, amount: Decimal, token_name: str): + """ + This method create an instance of Coin gRPC type, considering the amount is already expressed in chain format + """ + token = self.tokens[token_name] + chain_amount = token.chain_formatted_value(human_readable_value=amount) + return self.coin(amount=int(chain_amount), denom=token.denom) + def get_order_mask(self, **kwargs): order_mask = 0 @@ -331,13 +354,12 @@ def BinaryOptionsOrder( ) def MsgSend(self, from_address: str, to_address: str, amount: float, denom: str): - token = self.tokens[denom] - be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(amount))) + coin = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) return cosmos_bank_tx_pb.MsgSend( from_address=from_address, to_address=to_address, - amount=[self.Coin(amount=int(be_amount), denom=token.denom)], + amount=[coin], ) def MsgExecuteContract(self, sender: str, contract: str, msg: str, **kwargs): @@ -350,13 +372,12 @@ def MsgExecuteContract(self, sender: str, contract: str, msg: str, **kwargs): ) def MsgDeposit(self, sender: str, subaccount_id: str, amount: float, denom: str): - token = self.tokens[denom] - be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(amount))) + coin = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) return injective_exchange_tx_pb.MsgDeposit( sender=sender, subaccount_id=subaccount_id, - amount=self.Coin(amount=int(be_amount), denom=token.denom), + amount=coin, ) def MsgCreateSpotLimitOrder( @@ -709,24 +730,22 @@ def MsgSubaccountTransfer( amount: int, denom: str, ): - token = self.tokens[denom] - be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(amount))) + be_amount = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) return injective_exchange_tx_pb.MsgSubaccountTransfer( sender=sender, source_subaccount_id=source_subaccount_id, destination_subaccount_id=destination_subaccount_id, - amount=self.Coin(amount=int(be_amount), denom=token.denom), + amount=be_amount, ) def MsgWithdraw(self, sender: str, subaccount_id: str, amount: float, denom: str): - token = self.tokens[denom] - be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(amount))) + be_amount = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) return injective_exchange_tx_pb.MsgWithdraw( sender=sender, subaccount_id=subaccount_id, - amount=self.Coin(amount=int(be_amount), denom=token.denom), + amount=be_amount, ) def MsgExternalTransfer( @@ -737,14 +756,13 @@ def MsgExternalTransfer( amount: int, denom: str, ): - token = self.tokens[denom] - be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(amount))) + coin = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) return injective_exchange_tx_pb.MsgExternalTransfer( sender=sender, source_subaccount_id=source_subaccount_id, destination_subaccount_id=destination_subaccount_id, - amount=self.Coin(amount=int(be_amount), denom=token.denom), + amount=coin, ) def MsgBid(self, sender: str, bid_amount: float, round: float): @@ -753,7 +771,7 @@ def MsgBid(self, sender: str, bid_amount: float, round: float): return injective_auction_tx_pb.MsgBid( sender=sender, round=round, - bid_amount=self.Coin(amount=int(be_amount), denom=INJ_DENOM), + bid_amount=self.coin(amount=int(be_amount), denom=INJ_DENOM), ) def MsgGrantGeneric(self, granter: str, grantee: str, msg_type: str, expire_in: int): @@ -851,15 +869,14 @@ def MsgRelayPriceFeedPrice(self, sender: list, base: list, quote: list, price: l return injective_oracle_tx_pb.MsgRelayPriceFeedPrice(sender=sender, base=base, quote=quote, price=price) def MsgSendToEth(self, denom: str, sender: str, eth_dest: str, amount: float, bridge_fee: float): - token = self.tokens[denom] - be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(amount))) - be_bridge_fee = token.chain_formatted_value(human_readable_value=Decimal(str(bridge_fee))) + be_amount = self.create_coin_amount(amount=Decimal(str(amount)), token_name=denom) + be_bridge_fee = self.create_coin_amount(amount=Decimal(str(bridge_fee)), token_name=denom) return injective_peggy_tx_pb.MsgSendToEth( sender=sender, eth_dest=eth_dest, - amount=self.Coin(amount=int(be_amount), denom=token.denom), - bridge_fee=self.Coin(amount=int(be_bridge_fee), denom=token.denom), + amount=be_amount, + bridge_fee=be_bridge_fee, ) def MsgDelegate(self, delegator_address: str, validator_address: str, amount: float): @@ -868,7 +885,7 @@ def MsgDelegate(self, delegator_address: str, validator_address: str, amount: fl return cosmos_staking_tx_pb.MsgDelegate( delegator_address=delegator_address, validator_address=validator_address, - amount=self.Coin(amount=int(be_amount), denom=INJ_DENOM), + amount=self.coin(amount=int(be_amount), denom=INJ_DENOM), ) def MsgCreateInsuranceFund( @@ -883,7 +900,7 @@ def MsgCreateInsuranceFund( initial_deposit: int, ): token = self.tokens[quote_denom] - be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(initial_deposit))) + deposit = self.create_coin_amount(Decimal(str(initial_deposit)), quote_denom) return injective_insurance_tx_pb.MsgCreateInsuranceFund( sender=sender, @@ -893,7 +910,7 @@ def MsgCreateInsuranceFund( oracle_quote=oracle_quote, oracle_type=oracle_type, expiry=expiry, - initial_deposit=self.Coin(amount=int(be_amount), denom=token.denom), + initial_deposit=deposit, ) def MsgUnderwrite( @@ -903,13 +920,12 @@ def MsgUnderwrite( quote_denom: str, amount: int, ): - token = self.tokens[quote_denom] - be_amount = token.chain_formatted_value(human_readable_value=Decimal(str(amount))) + be_amount = self.create_coin_amount(amount=Decimal(str(amount)), token_name=quote_denom) return injective_insurance_tx_pb.MsgUnderwrite( sender=sender, market_id=market_id, - deposit=self.Coin(amount=int(be_amount), denom=token.denom), + deposit=be_amount, ) def MsgRequestRedemption( @@ -922,17 +938,9 @@ def MsgRequestRedemption( return injective_insurance_tx_pb.MsgRequestRedemption( sender=sender, market_id=market_id, - amount=self.Coin(amount=amount, denom=share_denom), + amount=self.coin(amount=amount, denom=share_denom), ) - def MsgWithdrawDelegatorReward(self, delegator_address: str, validator_address: str): - return cosmos_distribution_tx_pb.MsgWithdrawDelegatorReward( - delegator_address=delegator_address, validator_address=validator_address - ) - - def MsgWithdrawValidatorCommission(self, validator_address: str): - return cosmos_distribution_tx_pb.MsgWithdrawValidatorCommission(validator_address=validator_address) - def MsgVote( self, proposal_id: str, @@ -1101,6 +1109,56 @@ def chain_stream_oracle_price_filter( symbols = symbols or ["*"] return chain_stream_query.OraclePriceFilter(symbol=symbols) + # ------------------------------------------------ + # Distribution module's messages + + def msg_set_withdraw_address(self, delegator_address: str, withdraw_address: str): + return cosmos_distribution_tx_pb.MsgSetWithdrawAddress( + delegator_address=delegator_address, withdraw_address=withdraw_address + ) + + # Deprecated + def MsgWithdrawDelegatorReward(self, delegator_address: str, validator_address: str): + """ + This method is deprecated and will be removed soon. Please use `msg_withdraw_delegator_reward` instead + """ + warn("This method is deprecated. Use msg_withdraw_delegator_reward instead", DeprecationWarning, stacklevel=2) + return cosmos_distribution_tx_pb.MsgWithdrawDelegatorReward( + delegator_address=delegator_address, validator_address=validator_address + ) + + def msg_withdraw_delegator_reward(self, delegator_address: str, validator_address: str): + return cosmos_distribution_tx_pb.MsgWithdrawDelegatorReward( + delegator_address=delegator_address, validator_address=validator_address + ) + + def MsgWithdrawValidatorCommission(self, validator_address: str): + """ + This method is deprecated and will be removed soon. Please use `msg_withdraw_validator_commission` instead + """ + warn( + "This method is deprecated. Use msg_withdraw_validator_commission instead", DeprecationWarning, stacklevel=2 + ) + return cosmos_distribution_tx_pb.MsgWithdrawValidatorCommission(validator_address=validator_address) + + def msg_withdraw_validator_commission(self, validator_address: str): + return cosmos_distribution_tx_pb.MsgWithdrawValidatorCommission(validator_address=validator_address) + + def msg_fund_community_pool(self, amounts: List[cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin], depositor: str): + return cosmos_distribution_tx_pb.MsgFundCommunityPool(amount=amounts, depositor=depositor) + + def msg_update_distribution_params(self, authority: str, community_tax: str, withdraw_address_enabled: bool): + params = cosmos_distribution_pb2.Params( + community_tax=community_tax, + withdraw_addr_enabled=withdraw_address_enabled, + ) + return cosmos_distribution_tx_pb.MsgUpdateParams(authority=authority, params=params) + + def msg_community_pool_spend( + self, authority: str, recipient: str, amount: List[cosmos_dot_base_dot_v1beta1_dot_coin__pb2.Coin] + ): + return cosmos_distribution_tx_pb.MsgCommunityPoolSpend(authority=authority, recipient=recipient, amount=amount) + # data field format: [request-msg-header][raw-byte-msg-response] # you need to figure out this magic prefix number to trim request-msg-header off the data # this method handles only exchange responses diff --git a/pyinjective/core/broadcaster.py b/pyinjective/core/broadcaster.py index 22df562b..f279baea 100644 --- a/pyinjective/core/broadcaster.py +++ b/pyinjective/core/broadcaster.py @@ -264,7 +264,7 @@ async def configure_gas_fee_for_transaction( gas_limit = math.ceil(Decimal(str(sim_res["gasInfo"]["gasUsed"])) * self._gas_limit_adjustment_multiplier) fee = [ - self._composer.Coin( + self._composer.coin( amount=self._gas_price * gas_limit, denom=self._client.network.fee_denom, ) @@ -292,7 +292,7 @@ async def configure_gas_fee_for_transaction( transaction_gas_limit = messages_gas_limit + self.TRANSACTION_GAS_LIMIT fee = [ - self._composer.Coin( + self._composer.coin( amount=math.ceil(self._gas_price * transaction_gas_limit), denom=self._client.network.fee_denom, ) diff --git a/pyproject.toml b/pyproject.toml index cfea69b1..c983dd07 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "injective-py" -version = "1.3.0-pre" +version = "1.4.0-pre" description = "Injective Python SDK, with Exchange API Client" authors = ["Injective Labs "] license = "Apache-2.0" @@ -40,13 +40,12 @@ websockets = "*" web3 = "^6.0" [tool.poetry.group.test.dependencies] -pytest = "<8" +pytest = "*" pytest-asyncio = "*" pytest-grpc = "*" requests-mock = "*" pytest-cov = "^4.1.0" - [tool.poetry.group.dev.dependencies] pre-commit = "^3.4.0" flakeheaven = "^3.3.0" diff --git a/tests/client/chain/grpc/configurable_autz_query_servicer.py b/tests/client/chain/grpc/configurable_authz_query_servicer.py similarity index 100% rename from tests/client/chain/grpc/configurable_autz_query_servicer.py rename to tests/client/chain/grpc/configurable_authz_query_servicer.py diff --git a/tests/client/chain/grpc/configurable_distribution_query_servicer.py b/tests/client/chain/grpc/configurable_distribution_query_servicer.py new file mode 100644 index 00000000..d2e1d7da --- /dev/null +++ b/tests/client/chain/grpc/configurable_distribution_query_servicer.py @@ -0,0 +1,69 @@ +from collections import deque + +from pyinjective.proto.cosmos.distribution.v1beta1 import ( + query_pb2 as distribution_query_pb, + query_pb2_grpc as distribution_query_grpc, +) + + +class ConfigurableDistributionQueryServicer(distribution_query_grpc.QueryServicer): + def __init__(self): + super().__init__() + self.distribution_params = deque() + self.validator_distribution_info_responses = deque() + self.validator_outstanding_rewards_responses = deque() + self.validator_commission_responses = deque() + self.validator_slashes_responses = deque() + self.delegation_rewards_responses = deque() + self.delegation_total_rewards_responses = deque() + self.delegator_validators_responses = deque() + self.delegator_withdraw_address_responses = deque() + self.community_pool_responses = deque() + + async def Params(self, request: distribution_query_pb.QueryParamsRequest, context=None, metadata=None): + return self.distribution_params.pop() + + async def ValidatorDistributionInfo( + self, request: distribution_query_pb.QueryValidatorDistributionInfoRequest, context=None, metadata=None + ): + return self.validator_distribution_info_responses.pop() + + async def ValidatorOutstandingRewards( + self, request: distribution_query_pb.QueryValidatorOutstandingRewardsRequest, context=None, metadata=None + ): + return self.validator_outstanding_rewards_responses.pop() + + async def ValidatorCommission( + self, request: distribution_query_pb.QueryValidatorCommissionRequest, context=None, metadata=None + ): + return self.validator_commission_responses.pop() + + async def ValidatorSlashes( + self, request: distribution_query_pb.QueryValidatorSlashesRequest, context=None, metadata=None + ): + return self.validator_slashes_responses.pop() + + async def DelegationRewards( + self, request: distribution_query_pb.QueryDelegationRewardsRequest, context=None, metadata=None + ): + return self.delegation_rewards_responses.pop() + + async def DelegationTotalRewards( + self, request: distribution_query_pb.QueryDelegationTotalRewardsRequest, context=None, metadata=None + ): + return self.delegation_total_rewards_responses.pop() + + async def DelegatorValidators( + self, request: distribution_query_pb.QueryDelegatorValidatorsRequest, context=None, metadata=None + ): + return self.delegator_validators_responses.pop() + + async def DelegatorWithdrawAddress( + self, request: distribution_query_pb.QueryDelegatorWithdrawAddressRequest, context=None, metadata=None + ): + return self.delegator_withdraw_address_responses.pop() + + async def CommunityPool( + self, request: distribution_query_pb.QueryCommunityPoolRequest, context=None, metadata=None + ): + return self.community_pool_responses.pop() diff --git a/tests/client/chain/grpc/test_chain_grpc_authz_api.py b/tests/client/chain/grpc/test_chain_grpc_authz_api.py index e097ff66..9d1d5586 100644 --- a/tests/client/chain/grpc/test_chain_grpc_authz_api.py +++ b/tests/client/chain/grpc/test_chain_grpc_authz_api.py @@ -7,7 +7,7 @@ from pyinjective.core.network import Network from pyinjective.proto.cosmos.authz.v1beta1 import authz_pb2, query_pb2 as authz_query from pyinjective.proto.cosmos.base.query.v1beta1 import pagination_pb2 as pagination_pb -from tests.client.chain.grpc.configurable_autz_query_servicer import ConfigurableAuthZQueryServicer +from tests.client.chain.grpc.configurable_authz_query_servicer import ConfigurableAuthZQueryServicer @pytest.fixture diff --git a/tests/client/chain/grpc/test_chain_grpc_distribution_api.py b/tests/client/chain/grpc/test_chain_grpc_distribution_api.py new file mode 100644 index 00000000..9f8ee9a6 --- /dev/null +++ b/tests/client/chain/grpc/test_chain_grpc_distribution_api.py @@ -0,0 +1,338 @@ +import base64 + +import grpc +import pytest + +from pyinjective.client.chain.grpc.chain_grpc_distribution_api import ChainGrpcDistributionApi +from pyinjective.client.model.pagination import PaginationOption +from pyinjective.core.network import Network +from pyinjective.proto.cosmos.base.query.v1beta1 import pagination_pb2 as pagination_pb +from pyinjective.proto.cosmos.base.v1beta1 import coin_pb2 as coin_pb +from pyinjective.proto.cosmos.distribution.v1beta1 import ( + distribution_pb2 as distribution_pb, + query_pb2 as distribution_query_pb, +) +from tests.client.chain.grpc.configurable_distribution_query_servicer import ConfigurableDistributionQueryServicer + + +@pytest.fixture +def distribution_servicer(): + return ConfigurableDistributionQueryServicer() + + +class TestChainGrpcAuthApi: + @pytest.mark.asyncio + async def test_fetch_module_params( + self, + distribution_servicer, + ): + params = distribution_pb.Params( + community_tax="0.050000000000000000", + base_proposer_reward="0.060000000000000000", + bonus_proposer_reward="0.070000000000000000", + withdraw_addr_enabled=True, + ) + + distribution_servicer.distribution_params.append(distribution_query_pb.QueryParamsResponse(params=params)) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcDistributionApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = distribution_servicer + + module_params = await api.fetch_module_params() + expected_params = { + "params": { + "communityTax": params.community_tax, + "baseProposerReward": params.base_proposer_reward, + "bonusProposerReward": params.bonus_proposer_reward, + "withdrawAddrEnabled": params.withdraw_addr_enabled, + } + } + + assert expected_params == module_params + + @pytest.mark.asyncio + async def test_fetch_validator_distribution_info( + self, + distribution_servicer, + ): + operator = "inj1zpy3qf7us3m0pxpqkp72gzjv55t70huyxh7slz" + reward = coin_pb.DecCoin(denom="inj", amount="1000000000") + commission = coin_pb.DecCoin(denom="peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", amount="54497408") + + distribution_servicer.validator_distribution_info_responses.append( + distribution_query_pb.QueryValidatorDistributionInfoResponse( + operator_address=operator, self_bond_rewards=[reward], commission=[commission] + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcDistributionApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = distribution_servicer + + validator_info = await api.fetch_validator_distribution_info(validator_address=operator) + expected_info = { + "operatorAddress": operator, + "selfBondRewards": [{"denom": reward.denom, "amount": reward.amount}], + "commission": [{"denom": commission.denom, "amount": commission.amount}], + } + + assert expected_info == validator_info + + @pytest.mark.asyncio + async def test_fetch_validator_outstanding_rewards( + self, + distribution_servicer, + ): + operator = "inj1zpy3qf7us3m0pxpqkp72gzjv55t70huyxh7slz" + reward = coin_pb.DecCoin(denom="inj", amount="1000000000") + rewards = distribution_pb.ValidatorOutstandingRewards(rewards=[reward]) + + distribution_servicer.validator_outstanding_rewards_responses.append( + distribution_query_pb.QueryValidatorOutstandingRewardsResponse( + rewards=rewards, + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcDistributionApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = distribution_servicer + + validator_rewards = await api.fetch_validator_outstanding_rewards(validator_address=operator) + expected_rewards = {"rewards": {"rewards": [{"denom": reward.denom, "amount": reward.amount}]}} + + assert expected_rewards == validator_rewards + + @pytest.mark.asyncio + async def test_fetch_validator_commission( + self, + distribution_servicer, + ): + operator = "inj1zpy3qf7us3m0pxpqkp72gzjv55t70huyxh7slz" + first_commission = coin_pb.DecCoin(denom="inj", amount="1000000000") + commission = distribution_pb.ValidatorAccumulatedCommission(commission=[first_commission]) + + distribution_servicer.validator_commission_responses.append( + distribution_query_pb.QueryValidatorCommissionResponse( + commission=commission, + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcDistributionApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = distribution_servicer + + commission = await api.fetch_validator_commission(validator_address=operator) + expected_commission = { + "commission": {"commission": [{"denom": first_commission.denom, "amount": first_commission.amount}]} + } + + assert expected_commission == commission + + @pytest.mark.asyncio + async def test_fetch_validator_slashes( + self, + distribution_servicer, + ): + operator = "inj1zpy3qf7us3m0pxpqkp72gzjv55t70huyxh7slz" + slash = distribution_pb.ValidatorSlashEvent( + validator_period=1, + fraction="4", + ) + pagination = pagination_pb.PageResponse(total=2) + + distribution_servicer.validator_slashes_responses.append( + distribution_query_pb.QueryValidatorSlashesResponse( + slashes=[slash], + pagination=pagination, + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcDistributionApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = distribution_servicer + + slashes = await api.fetch_validator_slashes( + validator_address=operator, + starting_height=20, + ending_height=100, + pagination=PaginationOption( + skip=0, + limit=100, + ), + ) + expected_slashes = { + "slashes": [ + { + "validatorPeriod": str(slash.validator_period), + "fraction": slash.fraction, + } + ], + "pagination": {"nextKey": base64.b64encode(pagination.next_key).decode(), "total": str(pagination.total)}, + } + + assert slashes == expected_slashes + + @pytest.mark.asyncio + async def test_fetch_delegation_rewards( + self, + distribution_servicer, + ): + delegator = "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r" + validator = "injvaloper16gdnrnl224ylje5z9vd0vn0msym7p58f00qauj" + reward = coin_pb.DecCoin(denom="inj", amount="1000000000") + + distribution_servicer.delegation_rewards_responses.append( + distribution_query_pb.QueryDelegationRewardsResponse( + rewards=[reward], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcDistributionApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = distribution_servicer + + rewards = await api.fetch_delegation_rewards( + delegator_address=delegator, + validator_address=validator, + ) + expected_rewards = {"rewards": [{"denom": reward.denom, "amount": reward.amount}]} + + assert rewards == expected_rewards + + @pytest.mark.asyncio + async def test_fetch_delegation_total_rewards( + self, + distribution_servicer, + ): + delegator = "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r" + validator = "injvaloper16gdnrnl224ylje5z9vd0vn0msym7p58f00qauj" + reward = coin_pb.DecCoin(denom="inj", amount="1000000000") + delegation_delegator_reward = distribution_pb.DelegationDelegatorReward( + validator_address=validator, + reward=[reward], + ) + total = coin_pb.DecCoin(denom="inj", amount="2000000000") + + distribution_servicer.delegation_total_rewards_responses.append( + distribution_query_pb.QueryDelegationTotalRewardsResponse( + rewards=[delegation_delegator_reward], + total=[total], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcDistributionApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = distribution_servicer + + rewards = await api.fetch_delegation_total_rewards( + delegator_address=delegator, + ) + expected_rewards = { + "rewards": [ + { + "validatorAddress": validator, + "reward": [{"denom": reward.denom, "amount": reward.amount}], + } + ], + "total": [{"denom": total.denom, "amount": total.amount}], + } + + assert rewards == expected_rewards + + @pytest.mark.asyncio + async def test_fetch_delegator_validators( + self, + distribution_servicer, + ): + delegator = "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r" + validator = "injvaloper16gdnrnl224ylje5z9vd0vn0msym7p58f00qauj" + + distribution_servicer.delegator_validators_responses.append( + distribution_query_pb.QueryDelegatorValidatorsResponse( + validators=[validator], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcDistributionApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = distribution_servicer + + validators = await api.fetch_delegator_validators( + delegator_address=delegator, + ) + expected_validators = { + "validators": [validator], + } + + assert validators == expected_validators + + @pytest.mark.asyncio + async def test_fetch_delegator_withdraw_address( + self, + distribution_servicer, + ): + delegator = "inj1cml96vmptgw99syqrrz8az79xer2pcgp0a885r" + + distribution_servicer.delegator_withdraw_address_responses.append( + distribution_query_pb.QueryDelegatorWithdrawAddressResponse( + withdraw_address=delegator, + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcDistributionApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = distribution_servicer + + withdraw_address = await api.fetch_delegator_withdraw_address( + delegator_address=delegator, + ) + expected_withdraw_address = { + "withdrawAddress": delegator, + } + + assert withdraw_address == expected_withdraw_address + + @pytest.mark.asyncio + async def test_fetch_community_pool( + self, + distribution_servicer, + ): + coin = coin_pb.DecCoin(denom="inj", amount="1000000000") + distribution_servicer.community_pool_responses.append( + distribution_query_pb.QueryCommunityPoolResponse( + pool=[coin], + ) + ) + + network = Network.devnet() + channel = grpc.aio.insecure_channel(network.grpc_endpoint) + + api = ChainGrpcDistributionApi(channel=channel, metadata_provider=lambda: self._dummy_metadata_provider()) + api._stub = distribution_servicer + + community_pool = await api.fetch_community_pool() + expected_community_pool = {"pool": [{"denom": coin.denom, "amount": coin.amount}]} + + assert community_pool == expected_community_pool + + async def _dummy_metadata_provider(self): + return None diff --git a/tests/test_async_client_deprecation_warnings.py b/tests/test_async_client_deprecation_warnings.py index dae2d807..1df77fe8 100644 --- a/tests/test_async_client_deprecation_warnings.py +++ b/tests/test_async_client_deprecation_warnings.py @@ -21,7 +21,7 @@ from pyinjective.proto.injective.stream.v1beta1 import query_pb2 as chain_stream_pb from pyinjective.proto.injective.types.v1beta1 import account_pb2 as account_pb from tests.client.chain.grpc.configurable_auth_query_servicer import ConfigurableAuthQueryServicer -from tests.client.chain.grpc.configurable_autz_query_servicer import ConfigurableAuthZQueryServicer +from tests.client.chain.grpc.configurable_authz_query_servicer import ConfigurableAuthZQueryServicer from tests.client.chain.grpc.configurable_bank_query_servicer import ConfigurableBankQueryServicer from tests.client.chain.stream_grpc.configurable_chain_stream_query_servicer import ConfigurableChainStreamQueryServicer from tests.client.indexer.configurable_account_query_servicer import ConfigurableAccountQueryServicer diff --git a/tests/test_composer.py b/tests/test_composer.py index 4f756c79..a0cca2ab 100644 --- a/tests/test_composer.py +++ b/tests/test_composer.py @@ -282,7 +282,7 @@ def test_msg_create_denom(self, basic_composer: Composer): def test_msg_mint(self, basic_composer: Composer): sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" - amount = basic_composer.Coin( + amount = basic_composer.coin( amount=1_000_000, denom="factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test", ) @@ -297,7 +297,7 @@ def test_msg_mint(self, basic_composer: Composer): def test_msg_burn(self, basic_composer: Composer): sender = "inj1apmvarl2xyv6kecx2ukkeymddw3we4zkygjyc0" - amount = basic_composer.Coin( + amount = basic_composer.coin( amount=100, denom="factory/inj1hkhdaj2a2clmq5jq6mspsggqs32vynpk228q3r/inj_test", )