57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76 | def load_account_data(self, account: Account):
"""
Load the ``next_sequence`` and ``account_number`` into the account object.
@@ -1184,6 +1477,139 @@
+
+
+
+
+wait_for_tx(*, tx_hash, timeout=60, poll_period=10)
+
+
+
+
+
+
+ Waits for a transaction hash to hit the chain.
+
+
+ Note
+ Takes only positional arguments
+
+ Parameters:
+
+
+
+ Name |
+ Type |
+ Description |
+ Default |
+
+
+
+
+ tx_hash |
+
+ Transaction
+ |
+ The transaction hash |
+
+ required
+ |
+
+
+ timeout |
+
+ bool
+ |
+ Time to wait before throwing a TransactionTimeout. Defaults to 60 |
+
+ 60
+ |
+
+
+ poll_period |
+
+ float
+ |
+ Time to wait between each check. Defaults to 10 |
+
+ 10
+ |
+
+
+
+
+ Returns:
+
+
+
+Name | Type |
+ Description |
+
+
+
+
+transaction |
+ dict
+ |
+ Transaction dict as returned by the chain |
+
+
+
+
+
+ Source code in mospy/clients/HTTPClient.py
+ 169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191 | def wait_for_tx(self, *, tx_hash: str, timeout: float = 60, poll_period: float = 10):
+ """
+ Waits for a transaction hash to hit the chain.
+
+ Note:
+ Takes only positional arguments
+
+ Args:
+ tx_hash (Transaction): The transaction hash
+ timeout (bool): Time to wait before throwing a TransactionTimeout. Defaults to 60
+ poll_period (float): Time to wait between each check. Defaults to 10
+
+ Returns:
+ transaction (dict): Transaction dict as returned by the chain
+ """
+ start = time.time()
+ while time.time() < (start + timeout):
+ try:
+ return self.get_tx(tx_hash=tx_hash)
+ except TransactionNotFound:
+ time.sleep(poll_period)
+
+ raise TransactionTimeout(f"The transaction {tx_hash} couldn't be found on chain within {timeout} seconds.")
+
|
+
+
+
+
+
diff --git a/objects.inv b/objects.inv
index 0e1bec0..f636f41 100644
Binary files a/objects.inv and b/objects.inv differ
diff --git a/search/search_index.json b/search/search_index.json
index 56e4d5d..4115f3c 100644
--- a/search/search_index.json
+++ b/search/search_index.json
@@ -1 +1 @@
-{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"MosPy","text":"MosPy is a cosmospy fork and aims to be a versatile transaction signing library for the whole cosmos ecosystem. "},{"location":"#installation","title":"Installation","text":"Mospy is available on pypi: python -m pip install mospy-wallet Note: Even though the name is mospy-wallet on pypi the library itself is called mospy "},{"location":"#dependencies","title":"Dependencies","text":"By default mospy will import the protobuf files from cosmospy-protobuf and therefore work with the Cosmos chain. If you want to use it on another chain I highly recommend to use thee according protobufs to avoid version conflicts. The Account and Transaction class both take a protobuf argument to specify the protobufs. Note: You have to install them manually as mospy ships woth cosmospy_protobuf. You can use: evmos for evmos-protobuf osmosis for osmosis-protobuf cosmos for cosmospy-protobuf (default) <your module here> for your own protobuf module following the cosmos name schema "},{"location":"#get-started","title":"Get started","text":"import httpx # optional\nfrom mospy import Account, Transaction\n\naccount = Account(\n seed_phrase=\"law grab theory better athlete submit awkward hawk state wedding wave monkey audit blame fury wood tag rent furnace exotic jeans drift destroy style\",\n address_index=12\n)\n\ntx = Transaction(\n account=account,\n gas=1000,\n)\ntx.set_fee(\n amount=100,\n denom=\"uatom\"\n)\n# Add a transfer message to the transaction (multiple messages can be added)\ntx.add_msg(\n tx_type='transfer',\n sender=account,\n receipient=\"cosmos1tkv9rquxr88r7snrg42kxdj9gsnfxxg028kuh9\",\n amount=1000,\n denom=\"uatom\"\n)\n\n# Sign and encode transaction to submit it to the network manually\n\n# REST endpoint (RPC or API)\ntx_bytes = tx.get_tx_bytes_as_string()\n\n# Submit the transaction through the Tendermint RPC\nrpc_url = \"https://rpc.cosmos.network/\"\npushable_tx = json.dumps(\n {\n \"jsonrpc\": \"2.0\",\n \"id\": 1,\n \"method\": \"broadcast_tx_sync\", # Available methods: broadcast_tx_sync, broadcast_tx_async, broadcast_tx_commit\n \"params\": {\n \"tx\": tx_bytes\n }\n }\n )\nr = httpx.post(rpc_url, data=pushable_tx)\n\n# Submit the transaction through the Cosmos REST API\nrpc_api = \"https://api.cosmos.network/cosmos/tx/v1beta1/txs\"\npushable_tx = json.dumps(\n {\n \"tx_bytes\": tx_bytes,\n \"mode\": \"BROADCAST_MODE_SYNC\" # Available modes: BROADCAST_MODE_SYNC, BROADCAST_MODE_ASYNC, BROADCAST_MODE_BLOCK\n }\n )\nr = httpx.post(rpc_api, data=pushable_tx)\n "},{"location":"#support","title":"Support","text":"When facing issues feel free to open a github issue or reach out to the creators on the Osmosis Discord. "},{"location":"account/","title":"Account","text":"The account class can be instantiated through a seed or a private key. If nothing is provided it will create a new keyring and the params to work with the cosmos chain Note - You can't provide a
seed_phrase and aprivate_key - A
readble method behaves is the getter for a Attribute (Example: hrp = account.hrp ) - A
writable method is the setter for the Attribute (Example: account.hrp = \"cosmos\" ) - A method can be setter and getter at the same time. The Parameters description always refers to the setter while the Returns section belongs to the getter
Parameters: Name Type Description Default seed_phrase str Seed phrase to derive private keys from None private_key str Private key to instantiate the Account None next_sequence int Sequence which will be used for transactions signed with this Account None account_number int On-chain account number None slip44 int Slip44 value 118 hrp str Address Prefix 'cosmos' address_index int Address index to get sub accounts for seed phrases (doesn't work when using a private key) 0 protobuf str Define which protobuf files to use. Cosmos, Evmos and Osmosis are built in and otherwise pass the raw package name (cosmospy-protobuf) 'cosmos' eth bool Etermint compatibility mpde. If set to true the addresses and signatures will match the ethereum standard. Defaults to false to match the Cosmos standard. False Source code in mospy/Account.py class Account:\n\"\"\"\n The account class can be instantiated through a seed or a private key. If nothing is provided it will create a new keyring and the params to work with the cosmos chain\n\n Note:\n * You can't provide a ``seed_phrase`` and a``private_key``\n * A ``readble`` method behaves is the getter for a Attribute (Example: ``hrp = account.hrp``)\n * A ``writable`` method is the setter for the Attribute (Example: ``account.hrp = \"cosmos\"``)\n * A method can be setter and getter at the same time. The Parameters description always refers to the setter while the Returns section belongs to the getter\n\n\n Args:\n seed_phrase (str): Seed phrase to derive private keys from\n private_key (str): Private key to instantiate the Account\n next_sequence (int): Sequence which will be used for transactions signed with this Account\n account_number (int): On-chain account number\n slip44 (int): Slip44 value\n hrp (str): Address Prefix\n address_index (int): Address index to get sub accounts for seed phrases (doesn't work when using a private key)\n protobuf (str): Define which protobuf files to use. Cosmos, Evmos and Osmosis are built in and otherwise pass the raw package name (cosmospy-protobuf)\n eth (bool): Etermint compatibility mpde. If set to true the addresses and signatures will match the ethereum standard. Defaults to false to match the Cosmos standard.\n \"\"\"\n\n address: str\n\"\"\"the address of the account derived by using the slip44 param, the hrp and the address_index\"\"\"\n\n _RAW_DERIVATION_PATH = \"m/44'/{slip44}'/0'/0/{address_index}\"\n\n def __init__(\n self,\n seed_phrase: str = None,\n private_key: str = None,\n next_sequence: int = None,\n account_number: int = None,\n slip44: int = 118,\n hrp: str = \"cosmos\",\n address_index: int = 0,\n protobuf: str = \"cosmos\",\n eth: bool = False\n ):\n _protobuf_packages = {\n \"cosmos\": \"cosmospy_protobuf\",\n \"osmosis\": \"osmosis_protobuf\",\n \"evmos\": \"evmos_protobuf\",\n }\n _protobuf_package = (_protobuf_packages[protobuf.lower()]\n if protobuf.lower() in _protobuf_packages.keys()\n else protobuf)\n\n\n try:\n self.keys_pb2 = importlib.import_module(\n _protobuf_package + \".cosmos.crypto.secp256k1.keys_pb2\")\n except AttributeError:\n raise ImportError(\n \"It seems that you are importing conflicting protobuf files. Have sou set the protobuf attribute to specify your coin? Check out the documentation for more information.\"\n )\n except:\n raise ImportError(\n f\"Couldn't import from {_protobuf_package}. Is the package installed? \"\n )\n\n self._eth = eth\n self._slip44 = slip44\n self._hrp = hrp\n self._address_index = address_index\n self._next_sequence = next_sequence\n self._account_number = account_number\n\n if not seed_phrase and not private_key:\n self._seed_phrase = Mnemonic(language=\"english\").generate(\n strength=256)\n self._private_key = seed_to_private_key(self._seed_phrase,\n self._derivation_path())\n\n elif seed_phrase and not private_key:\n self._seed_phrase = seed_phrase\n self._private_key = seed_to_private_key(seed_phrase,\n self._derivation_path())\n\n elif private_key and not seed_phrase:\n self._seed_phrase = None\n self._private_key = bytes.fromhex(private_key)\n\n else:\n raise AttributeError(\n \"Please set only a private key or a seed phrase. Not both!\")\n\n def _derivation_path(self, address_index: int = None):\n adr_id = self._address_index if not address_index else address_index\n params = {\"slip44\": self._slip44, \"address_index\": adr_id}\n return self._RAW_DERIVATION_PATH.format(**params)\n\n @property\n def address(self) -> str:\n\"\"\"\n Current address which depends on the hrp and the private key.\n\n Returns:\n Address\n \"\"\"\n if not self._seed_phrase:\n address = privkey_to_address(self._private_key, hrp=self._hrp) if not self._eth else privkey_to_eth_address(self._private_key, hrp=self._hrp)\n else:\n sub_private_key = seed_to_private_key(\n self._seed_phrase,\n self._derivation_path(address_index=self._address_index),\n )\n address = privkey_to_address(sub_private_key, hrp=self._hrp) if not self._eth else privkey_to_eth_address(sub_private_key, hrp=self._hrp)\n\n return address\n\n @property\n def eth_address(self) -> str:\n\"\"\"\n Ethereum compatible address starting with 0x. Only available if Account is initialised with eth set to True.\n\n Returns:\n Address\n \"\"\"\n if not self._eth:\n raise TypeError(\"Account hasn't been initialised with the eth mode set to true.\")\n if not self._seed_phrase:\n address = privkey_to_eth_address(self._private_key)\n else:\n sub_private_key = seed_to_private_key(\n self._seed_phrase,\n self._derivation_path(address_index=self._address_index),\n )\n address = privkey_to_eth_address(sub_private_key)\n\n return address\n\n @property\n def seed_phrase(self) -> str:\n\"\"\"\n Current Seed Phrase\n\n Returns:\n Seed Phrase\n \"\"\"\n return self._seed_phrase\n\n @property\n def private_key(self) -> bytes:\n\"\"\"\n Current private key which depends on the slip 44 param and the address index if the account is instantiated through a seed.\n\n Returns:\n Private Key\n \"\"\"\n if self._seed_phrase:\n private_key = seed_to_private_key(\n self._seed_phrase,\n self._derivation_path(address_index=self._address_index),\n )\n return private_key\n else:\n return self._private_key\n\n @property\n def public_key(self) -> str:\n\"\"\"\n Current public key which depends on the slip 44 param and the address index if the account is instantiated through a seed.\n\n Returns:\n Public Key\n \"\"\"\n pubkey_bytes = privkey_to_pubkey(self.private_key)\n _pubkey = self.keys_pb2.PubKey()\n _pubkey.key = pubkey_bytes\n return _pubkey\n\n @property\n def account_number(self) -> int:\n\"\"\"\n On-chain account number which will be assigned when the address receives coins for the first time.\n\n Args:\n account_number (int): Account Number\n Returns:\n Account number\n \"\"\"\n return self._account_number\n\n @account_number.setter\n def account_number(self, account_number: int):\n self._account_number = account_number\n\n @property\n def next_sequence(self) -> int:\n\"\"\"\n Sequence which will be used for transactions signed with this Account.\n\n Args:\n next_sequence (int): Next sequence (only when used as setter)\n\n Returns:\n Next Sequence\n \"\"\"\n return self._next_sequence\n\n @next_sequence.setter\n def next_sequence(self, next_sequence):\n self._next_sequence = next_sequence\n\n def increase_sequence(self, change: int = 1) -> None:\n\"\"\"\n Increase the sequence by ``change``\n\n Args:\n change (int): Value to increase the sequence\n \"\"\"\n self._next_sequence += change\n\n @property\n def address_index(self):\n\"\"\"\n Change the address index to use a sub account. This works only if a seed has been used to instantiate the Account.\n\n Args:\n address_index (int): New address index\n\n Returns:\n Address Index\n \"\"\"\n return self._address_index\n\n @address_index.setter\n def address_index(self, address_index: int) -> None:\n\n if self._seed_phrase:\n self._DEFAULT_ADDRESS_INDEX = address_index\n else:\n raise ValueError(\n \"Can't the change the address index without provided seed\")\n\n @property\n def hrp(self) -> str:\n\"\"\"\n Current address prefix used by the Account.\n\n Args:\n hrp (str): New address prefix\n\n\n Returns:\n Address Prefix (hrp)\n \"\"\"\n return self._hrp\n\n @hrp.setter\n def hrp(self, hrp: str) -> None:\n self._hrp = hrp\n\n @property\n def slip44(self) -> int:\n\"\"\"\"\n Set the Slip44 value. Cosmos defaults to 118\n\n Args:\n slip44 (int): New slip44 value as defined in the [slip44 registry](https://github.com/satoshilabs/slips/blob/master/slip-0044.md)\n\n Returns:\n Slip44\n\n \"\"\"\n return self._slip44\n\n @slip44.setter\n def slip44(self, slip44: int) -> None:\n self._slip44 = slip44\n\n @property\n def eth(self) -> bool:\n\"\"\"\n Change the eth compatibility mode. If you want to use Evmos you will need to set eth to true. Otherwise it defaults to False\n\n Args:\n eth (bool): ETH compatibility mode\n\n Returns:\n eth\n \"\"\"\n return self._eth\n\n @eth.setter\n def eth(self, eth: bool):\n\n self._eth = eth\n "},{"location":"account/#mospy.Account.Account.account_number","title":"account_number: int property writable ","text":"On-chain account number which will be assigned when the address receives coins for the first time. Parameters: Name Type Description Default account_number int Account Number required Returns: Type Description int Account number "},{"location":"account/#mospy.Account.Account.address","title":"address: str property ","text":"Current address which depends on the hrp and the private key. Returns: Type Description str Address "},{"location":"account/#mospy.Account.Account.address_index","title":"address_index property writable ","text":"Change the address index to use a sub account. This works only if a seed has been used to instantiate the Account. Parameters: Name Type Description Default address_index int New address index required Returns: Type Description Address Index "},{"location":"account/#mospy.Account.Account.eth","title":"eth: bool property writable ","text":"Change the eth compatibility mode. If you want to use Evmos you will need to set eth to true. Otherwise it defaults to False Parameters: Name Type Description Default eth bool ETH compatibility mode required Returns: Type Description bool eth "},{"location":"account/#mospy.Account.Account.eth_address","title":"eth_address: str property ","text":"Ethereum compatible address starting with 0x. Only available if Account is initialised with eth set to True. Returns: Type Description str Address "},{"location":"account/#mospy.Account.Account.hrp","title":"hrp: str property writable ","text":"Current address prefix used by the Account. Parameters: Name Type Description Default hrp str New address prefix required Returns: Type Description str Address Prefix (hrp) "},{"location":"account/#mospy.Account.Account.next_sequence","title":"next_sequence: int property writable ","text":"Sequence which will be used for transactions signed with this Account. Parameters: Name Type Description Default next_sequence int Next sequence (only when used as setter) required Returns: Type Description int Next Sequence "},{"location":"account/#mospy.Account.Account.private_key","title":"private_key: bytes property ","text":"Current private key which depends on the slip 44 param and the address index if the account is instantiated through a seed. Returns: Type Description bytes Private Key "},{"location":"account/#mospy.Account.Account.public_key","title":"public_key: str property ","text":"Current public key which depends on the slip 44 param and the address index if the account is instantiated through a seed. Returns: Type Description str Public Key "},{"location":"account/#mospy.Account.Account.seed_phrase","title":"seed_phrase: str property ","text":"Current Seed Phrase Returns: Type Description str Seed Phrase "},{"location":"account/#mospy.Account.Account.slip44","title":"slip44: int property writable ","text":"\" Set the Slip44 value. Cosmos defaults to 118 Parameters: Name Type Description Default slip44 int New slip44 value as defined in the slip44 registry required Returns: Type Description int Slip44 "},{"location":"account/#mospy.Account.Account.increase_sequence","title":"increase_sequence(change=1) ","text":"Increase the sequence by change Parameters: Name Type Description Default change int Value to increase the sequence 1 Source code in mospy/Account.py def increase_sequence(self, change: int = 1) -> None:\n\"\"\"\n Increase the sequence by ``change``\n\n Args:\n change (int): Value to increase the sequence\n \"\"\"\n self._next_sequence += change\n "},{"location":"examples/","title":"Examples","text":"Here you'll find some useful code snippets to get started with MosPy "},{"location":"examples/#account","title":"Account","text":"Examples showing the use of the account class "},{"location":"examples/#account-creation","title":"Account creation","text":"\nfrom mospy import Account\n\n# Generate a new Account with a new seed phrase\naccount1 = Account()\n\n# Create an account object through a seed phrase and \n# get a sub-account of that seed by passing the address index (optional)\n\naccount2 = Account(\n seed_phrase=\"law grab theory better athlete submit awkward hawk state wedding wave monkey audit blame fury wood tag rent furnace exotic jeans drift destroy style\",\n address_index=12\n)\n\n# Instantiate the Account by using a private key and\n# set a different address prefix to use another cosmos based chain as well as\n# the nex account sequence and account number (example values)\n\naccount3 = Account(\n private_key=\"8c2ae3f9c216f714c0a877e7a4952ec03462496e01452bd5ee79ef79d707ff6c\",\n hrp=\"osmo\",\n next_sequence=1,\n account_number=187486\n)\n\n\n "},{"location":"examples/#transaction","title":"Transaction","text":"Showcase how to create use the Transaction class from mospy import Transaction\nfrom cosmospy_protobuf.cosmos.base.v1beta1.coin_pb2 import Coin # Optional\n\n# Create the fee object from the protobufs and pass it when instantiating the Transaction\n# or add it later through the set_fee function\nfee = Coin(\n denom=\"uatom\",\n amount=\"1000\"\n)\n\n# Create the transaction object by passing the account object from the step above\ntx = Transaction(\n account=account3,\n fee=fee,\n gas=1000,\n)\n\n# Add a transfer message to the transaction (multiple messages can be added)\ntx.add_msg(\n tx_type='transfer',\n sender=account3,\n receipient=\"cosmos1tkv9rquxr88r7snrg42kxdj9gsnfxxg028kuh9\",\n amount=1000,\n denom=\"uatom\"\n)\n\n# Sign and encode transaction to submit it to the network manually\n\n# REST endpoint (RPC or API)\ntx_bytes = tx.get_tx_bytes_as_string()\n\n# GRPC\ntx_bytes = tx.get_tx_bytes()\n "},{"location":"examples/#custom-transaction-message","title":"Custom Transaction Message","text":"You can easily use every other tx type too. The type_url usually matches the import path. # References the tx class from above before signing\n\nfrom cosmospy_protobuf.cosmos.distribution.v1beta1.tx_pb2 import MsgSetWithdrawAddress\n\nwmsg = MsgSetWithdrawAddress(\n delegator_address=account.address,\n withdraw_address=\"newaddresshere\"\n\n)\ntx.add_raw_msg(wmsg, type_url=\"/cosmos.distribution.v1beta1.MsgSetWithdrawAddress\")\n\n "},{"location":"examples/#client","title":"Client","text":"Examples howing the usage of the included clients from mospy.clients import HTTPClient\n\n# Instantiate a HTTPClient object by passing a custom API endpoint.\n# https://api.cosmos.network is chosen if no api provider is provided\nclient = HTTPClient(\n api=\"https://api.cosmos.interbloc.org\"\n)\n\n# Update the account object to set the current on chain sequence and account_number\nclient.load_account_data(account=account)\n\n# Broadcast a transaction\n# Note: Do not call 'get_tx_bytes' on the transaction object before \n# as it will be signed twice then\nhash, code, log = client.broadcast_transaction(transaction=tx)\n "},{"location":"examples/#ethereumethermint-transaction","title":"Ethereum/Ethermint Transaction","text":"Make a transaction on chains using Ethermint like Evmos from mospy import Transaction\nfrom mospy.clients import HTTPClient\n\nfrom src.mospy import Account\n\n# As the account query returns a different json than the standard cosmos one evmos won't be compatible with the \n# client.load_account() function \naccount = Account(\n seed_phrase=\"law grab theory better athlete submit awkward hawk state wedding wave monkey audit blame fury wood tag rent furnace exotic jeans drift destroy style\",\n hrp=\"evmos\",\n slip44=60,\n eth=True,\n next_sequence=1,\n account_number=2154050,\n )\n\ntx = Transaction(\n account=account,\n gas=2000000,\n memo=\"The first mospy evmos transaction!\",\n chain_id=\"evmos_9001-2\",\n)\n\ntx.set_fee(\n denom=\"aevmos\",\n amount=40000000000000000\n)\ntx.add_msg(\n tx_type=\"transfer\",\n sender=account,\n receipient=account.address,\n amount=3500000000000000,\n denom=\"aevmos\",\n)\n\nclient = HTTPClient(api=\"https://api.evmos.interbloc.org\")\ntx_response = client.broadcast_transaction(transaction=tx)\n "},{"location":"transaction/","title":"Transaction","text":"Class to create and sign a transaction Parameters: Name Type Description Default account Account Account object to sign this transaction required gas int Gas unit for this transaction required fee coin The fee to pay for this transaction (This can also be added later through the set_fee method) None memo str Memo '' chain_id str Chain-Id \"cosmoshub-4\", 'cosmoshub-4' protobuf str Define which protobuf files to use. Cosmos, Evmos and Osmosis are built in and otherwise pass the raw package name (cosmospy-protobuf) 'cosmos' Source code in mospy/Transaction.py class Transaction:\n\"\"\"Class to create and sign a transaction\n Args:\n account (Account): Account object to sign this transaction\n gas (int): Gas unit for this transaction\n fee (coin): The fee to pay for this transaction (This can also be added later through the ``set_fee`` method)\n memo (str): Memo\n chain_id (str): Chain-Id \"cosmoshub-4\",\n protobuf (str): Define which protobuf files to use. Cosmos, Evmos and Osmosis are built in and otherwise pass the raw package name (cosmospy-protobuf)\n\n\n \"\"\"\n\n def __init__(\n self,\n *,\n account: Account,\n gas: int,\n fee: object = None,\n memo: str = \"\",\n chain_id: str = \"cosmoshub-4\",\n protobuf: str = \"cosmos\",\n feegrant: str = \"\"\n ) -> None:\n\n _protobuf_packages = {\n \"cosmos\": \"cosmospy_protobuf\",\n \"osmosis\": \"osmosis_protobuf\",\n \"evmos\": \"evmos_protobuf\",\n }\n self._protobuf_package = (_protobuf_packages[protobuf.lower()]\n if protobuf.lower()\n in _protobuf_packages.keys() else protobuf)\n try:\n self.coin_pb2 = importlib.import_module(\n self._protobuf_package + \".cosmos.base.v1beta1.coin_pb2\")\n self.tx_pb2 = importlib.import_module(self._protobuf_package +\n \".cosmos.tx.v1beta1.tx_pb2\")\n except:\n raise ImportError(\n f\"Couldn't import from {self._protobuf_package}. Is the package installed?\"\n )\n\n if fee and not isinstance(fee, (self.coin_pb2.Coin)):\n raise ValueError(\"The fee is not a valid.\")\n\n self._account = account\n self._fee = fee\n self._gas = gas\n self._chain_id = chain_id\n self._tx_body = self.tx_pb2.TxBody()\n self._tx_body.memo = memo\n self._tx_raw = self.tx_pb2.TxRaw()\n self._feegrant = feegrant\n\n def add_msg(self, tx_type: str, **kwargs) -> None:\n\"\"\"\n Add a pre-defined message to the tx body.\n\n Args:\n tx_type (str): Transaction type to match the transaction with the pre-defined ones\n **kwargs: Depending on the transaction type\n \"\"\"\n msg_data = built_in_transactions[tx_type](\n protobuf_package=self._protobuf_package, **kwargs).format()\n self.add_raw_msg(msg_data[1], type_url=msg_data[0])\n\n def add_raw_msg(self, unpacked_msg, type_url: str) -> None:\n\"\"\"\n Add a message to the tx body manually.\n\n Args:\n unpacked_msg: Transaction data\n type_url: Type url for the transaction\n \"\"\"\n msg_any = any.Any()\n msg_any.Pack(unpacked_msg)\n msg_any.type_url = type_url\n self._tx_body.messages.append(msg_any)\n\n def set_fee(self, amount: int, denom: str = \"uatom\"):\n\"\"\"\n Set the fee manually\n\n Args:\n amount: Amount\n denom: Denom\n \"\"\"\n self._fee = self.coin_pb2.Coin(amount=str(amount), denom=denom)\n\n def set_gas(self, gas: int):\n\"\"\"\n Update the wanted gas for the transaction\n\n Args:\n gas: Gas\n \"\"\"\n self._gas = gas\n\n def get_tx_bytes(self) -> bytes:\n\"\"\"Sign the transaction and get the tx bytes which can be used to broadcast the transaction to the network.\n\n To broadcast the transaction through the REST endpoint use the ``get_tx_bytes_as_string()`` method instead\n\n Returns:\n tx_bytes (bytes): Transaction bytes\n \"\"\"\n self._tx_raw = self.tx_pb2.TxRaw()\n self._tx_raw.body_bytes = self._tx_body.SerializeToString()\n self._tx_raw.auth_info_bytes = self._get_auth_info().SerializeToString(\n )\n self._tx_raw.signatures.append(self._get_signatures())\n raw_tx = self._tx_raw.SerializeToString()\n tx_bytes = bytes(raw_tx)\n return tx_bytes\n\n def get_tx_bytes_as_string(self) -> str:\n\"\"\"Sign the transaction and get the base64 encoded tx bytes which can be used to broadcast the transaction to the network.\n\n Returns:\n tx_bytes (str): Transaction bytes\n \"\"\"\n tx_bytes = self.get_tx_bytes()\n tx_b64 = base64.b64encode(tx_bytes).decode(\"utf-8\")\n return tx_b64\n\n def _get_signatures(self):\n privkey = ecdsa.SigningKey.from_string(self._account.private_key,\n curve=ecdsa.SECP256k1)\n\n # Cosmos uses sha256 as main hashing function while ethereum uses keccak256\n hashfunc = hashlib.sha256 if not self._account.eth else keccak_256\n\n signature_compact = privkey.sign_deterministic(\n self._get_sign_doc().SerializeToString(),\n hashfunc=hashfunc,\n sigencode=ecdsa.util.sigencode_string_canonize,\n )\n return signature_compact\n\n def _get_sign_doc(self):\n sign_doc = self.tx_pb2.SignDoc()\n sign_doc.body_bytes = self._tx_body.SerializeToString()\n sign_doc.auth_info_bytes = self._get_auth_info().SerializeToString()\n sign_doc.chain_id = self._chain_id\n sign_doc.account_number = self._account.account_number\n return sign_doc\n\n def _get_auth_info(self):\n _auth_info = self.tx_pb2.AuthInfo()\n _auth_info.signer_infos.append(self._get_signer_infos())\n _auth_info.fee.gas_limit = self._gas\n _auth_info.fee.amount.append(self._fee)\n if self._feegrant:\n _auth_info.fee.granter = self._feegrant\n return _auth_info\n\n def _get_signer_infos(self):\n signer_infos = self.tx_pb2.SignerInfo()\n signer_infos.sequence = self._account.next_sequence\n signer_infos.public_key.Pack(self._account.public_key)\n if self._account.eth:\n signer_infos.public_key.type_url = \"/ethermint.crypto.v1.ethsecp256k1.PubKey\"\n else:\n signer_infos.public_key.type_url = \"/cosmos.crypto.secp256k1.PubKey\"\n signer_infos.mode_info.single.mode = 1\n return signer_infos\n "},{"location":"transaction/#mospy.Transaction.Transaction.add_msg","title":"add_msg(tx_type, **kwargs) ","text":"Add a pre-defined message to the tx body. Parameters: Name Type Description Default tx_type str Transaction type to match the transaction with the pre-defined ones required **kwargs Depending on the transaction type {} Source code in mospy/Transaction.py def add_msg(self, tx_type: str, **kwargs) -> None:\n\"\"\"\n Add a pre-defined message to the tx body.\n\n Args:\n tx_type (str): Transaction type to match the transaction with the pre-defined ones\n **kwargs: Depending on the transaction type\n \"\"\"\n msg_data = built_in_transactions[tx_type](\n protobuf_package=self._protobuf_package, **kwargs).format()\n self.add_raw_msg(msg_data[1], type_url=msg_data[0])\n "},{"location":"transaction/#mospy.Transaction.Transaction.add_raw_msg","title":"add_raw_msg(unpacked_msg, type_url) ","text":"Add a message to the tx body manually. Parameters: Name Type Description Default unpacked_msg Transaction data required type_url str Type url for the transaction required Source code in mospy/Transaction.py def add_raw_msg(self, unpacked_msg, type_url: str) -> None:\n\"\"\"\n Add a message to the tx body manually.\n\n Args:\n unpacked_msg: Transaction data\n type_url: Type url for the transaction\n \"\"\"\n msg_any = any.Any()\n msg_any.Pack(unpacked_msg)\n msg_any.type_url = type_url\n self._tx_body.messages.append(msg_any)\n "},{"location":"transaction/#mospy.Transaction.Transaction.get_tx_bytes","title":"get_tx_bytes() ","text":"Sign the transaction and get the tx bytes which can be used to broadcast the transaction to the network. To broadcast the transaction through the REST endpoint use the get_tx_bytes_as_string() method instead Returns: Name Type Description tx_bytes bytes Transaction bytes Source code in mospy/Transaction.py def get_tx_bytes(self) -> bytes:\n\"\"\"Sign the transaction and get the tx bytes which can be used to broadcast the transaction to the network.\n\n To broadcast the transaction through the REST endpoint use the ``get_tx_bytes_as_string()`` method instead\n\n Returns:\n tx_bytes (bytes): Transaction bytes\n \"\"\"\n self._tx_raw = self.tx_pb2.TxRaw()\n self._tx_raw.body_bytes = self._tx_body.SerializeToString()\n self._tx_raw.auth_info_bytes = self._get_auth_info().SerializeToString(\n )\n self._tx_raw.signatures.append(self._get_signatures())\n raw_tx = self._tx_raw.SerializeToString()\n tx_bytes = bytes(raw_tx)\n return tx_bytes\n "},{"location":"transaction/#mospy.Transaction.Transaction.get_tx_bytes_as_string","title":"get_tx_bytes_as_string() ","text":"Sign the transaction and get the base64 encoded tx bytes which can be used to broadcast the transaction to the network. Returns: Name Type Description tx_bytes str Transaction bytes Source code in mospy/Transaction.py def get_tx_bytes_as_string(self) -> str:\n\"\"\"Sign the transaction and get the base64 encoded tx bytes which can be used to broadcast the transaction to the network.\n\n Returns:\n tx_bytes (str): Transaction bytes\n \"\"\"\n tx_bytes = self.get_tx_bytes()\n tx_b64 = base64.b64encode(tx_bytes).decode(\"utf-8\")\n return tx_b64\n "},{"location":"transaction/#mospy.Transaction.Transaction.set_fee","title":"set_fee(amount, denom='uatom') ","text":"Set the fee manually Parameters: Name Type Description Default amount int Amount required denom str Denom 'uatom' Source code in mospy/Transaction.py def set_fee(self, amount: int, denom: str = \"uatom\"):\n\"\"\"\n Set the fee manually\n\n Args:\n amount: Amount\n denom: Denom\n \"\"\"\n self._fee = self.coin_pb2.Coin(amount=str(amount), denom=denom)\n "},{"location":"transaction/#mospy.Transaction.Transaction.set_gas","title":"set_gas(gas) ","text":"Update the wanted gas for the transaction Parameters: Name Type Description Default gas int Gas required Source code in mospy/Transaction.py def set_gas(self, gas: int):\n\"\"\"\n Update the wanted gas for the transaction\n\n Args:\n gas: Gas\n \"\"\"\n self._gas = gas\n "},{"location":"clients/","title":"Clients","text":"The client classes contain helper functions supporting you while interacting with the chain. "},{"location":"clients/#supported-endpoints","title":"Supported Endpoints","text":" - API:
HTTPClient - GRPC:
GRPCClient "},{"location":"clients/grpcclient/","title":"HTTPClient","text":"Wrapper class to interact with a cosmos chain through their grpc endpoint Parameters: Name Type Description Default host str URL to a Cosmos api node 'cosmoshub.strange.love' port int Port to connect to 9090 ssl bool Whether a ssl encrypted endpoint should be used False protobuf str Define which protobuf files to use. Cosmos, Evmos and Osmosis are built in and otherwise pass the raw package name (cosmospy-protobuf) 'cosmos' Source code in mospy/clients/GRPCClient.py class GRPCClient:\n\"\"\"\n Wrapper class to interact with a cosmos chain through their grpc endpoint\n\n Args:\n host (str): URL to a Cosmos api node\n port (int): Port to connect to\n ssl (bool): Whether a ssl encrypted endpoint should be used\n protobuf (str): Define which protobuf files to use. Cosmos, Evmos and Osmosis are built in and otherwise pass the raw package name (cosmospy-protobuf)\n\n \"\"\"\n\n def __init__(\n self,\n *,\n host: str = \"cosmoshub.strange.love\",\n port: int = 9090,\n ssl: bool = False,\n protobuf=\"cosmos\",\n ):\n\n _protobuf_packages = {\n \"cosmos\": \"cosmospy_protobuf\",\n \"osmosis\": \"osmosis_protobuf\",\n \"evmos\": \"evmos_protobuf\",\n }\n _protobuf_package = (_protobuf_packages[protobuf.lower()]\n if protobuf.lower() in _protobuf_packages.keys()\n else protobuf)\n try:\n self._cosmos_tx_service_pb2 = importlib.import_module(\n _protobuf_package +\n \".cosmos.tx.v1beta1.service_pb2\")\n self._cosmos_auth_query_pb2 = importlib.import_module(\n _protobuf_package + \".cosmos.auth.v1beta1.query_pb2\")\n self._cosmos_auth_query_pb2_grpc = importlib.import_module(\n _protobuf_package + \".cosmos.auth.v1beta1.query_pb2_grpc\")\n self._cosmos_tx_service_pb2_grpc = importlib.import_module(\n _protobuf_package + \".cosmos.tx.v1beta1.service_pb2_grpc\")\n\n self._BroadcastTxRequest = self._cosmos_tx_service_pb2.BroadcastTxRequest\n self._SimulateTxRequest = self._cosmos_tx_service_pb2.SimulateRequest\n\n except AttributeError:\n raise ImportError(\n \"It seems that you are importing conflicting protobuf files. Have sou set the protobuf attribute to specify your coin? Check out the documentation for more information.\"\n )\n except:\n raise ImportError(\n f\"Couldn't import from {_protobuf_package}. Is the package installed? \"\n )\n\n self._host = host\n self._port = port\n self._ssl = ssl\n\n def _connect(self):\n if self._ssl:\n con = grpc.secure_channel(\n f\"{self._host}:{self._port}\",\n credentials=grpc.ssl_channel_credentials())\n else:\n con = grpc.insecure_channel(f\"{self._host}:{self._port}\")\n return con\n\n def load_account_data(self, account: Account):\n\"\"\"\n Load the ``next_sequence`` and ``account_number`` into the account object.\n\n Args:\n account (Account): Account\n \"\"\"\n con = self._connect()\n address = account.address\n\n query_stub = self._cosmos_auth_query_pb2_grpc.QueryStub(con)\n account_request = self._cosmos_auth_query_pb2.QueryAccountRequest(address=address)\n\n req = query_stub.Account(account_request)\n data = dict(MessageToDict(req.account))\n\n sequence = 0 if not \"sequence\" in data else int(data[\"sequence\"])\n account_number = int(data[\"accountNumber\"])\n\n account.next_sequence = sequence\n account.account_number = account_number\n con.close()\n\n def broadcast_transaction(self,\n *,\n transaction: Transaction,\n timeout: int = 10) -> [str, int, str]:\n\"\"\"\n Sign and broadcast a transaction.\n\n Note:\n Takes only positional arguments\n\n Args:\n transaction (Transaction): The transaction object\n\n Returns:\n hash: Transaction hash\n code: Result code\n log: Log (None if transaction successful)\n \"\"\"\n con = self._connect()\n tx_bytes = transaction.get_tx_bytes()\n\n tx_request = self._BroadcastTxRequest(\n tx_bytes=tx_bytes,\n mode=2 # BROADCAST_MODE_SYNC\n )\n\n tx_stub = self._cosmos_tx_service_pb2_grpc.ServiceStub(con)\n tx_data = tx_stub.BroadcastTx(tx_request)\n\n hash = tx_data.tx_response.txhash\n code = tx_data.tx_response.code\n log = None if code == 0 else tx_data.tx_response.raw_log\n\n return {\"hash\": hash, \"code\": code, \"log\": log}\n\n def estimate_gas(self,\n *,\n transaction: Transaction,\n update: bool = True,\n multiplier: float = 1.2\n ) ->int:\n\"\"\"\n Simulate a transaction to get the estimated gas usage.\n\n Note:\n Takes only positional arguments\n\n Args:\n transaction (Transaction): The transaction object\n update (bool): Update the transaction with the estimated gas amount\n multiplier (float): Multiplier for the estimated gas when updating the transaction. Defaults to 1.2\n\n Returns:\n expedted_gas: Expected gas\n \"\"\"\n con = self._connect()\n tx_bytes = transaction.get_tx_bytes()\n\n simulate_request = self._SimulateTxRequest(\n tx_bytes=tx_bytes,\n )\n\n tx_stub = self._cosmos_tx_service_pb2_grpc.ServiceStub(con)\n tx_data = tx_stub.Simulate(simulate_request)\n\n gas_used = tx_data.gas_info.gas_used\n\n if update:\n transaction.set_gas(int(gas_used * multiplier))\n\n return gas_used\n "},{"location":"clients/grpcclient/#mospy.clients.GRPCClient.GRPCClient.broadcast_transaction","title":"broadcast_transaction(*, transaction, timeout=10) ","text":"Sign and broadcast a transaction. Note Takes only positional arguments Parameters: Name Type Description Default transaction Transaction The transaction object required Returns: Name Type Description hash [str, int, str] Transaction hash code [str, int, str] Result code log [str, int, str] Log (None if transaction successful) Source code in mospy/clients/GRPCClient.py def broadcast_transaction(self,\n *,\n transaction: Transaction,\n timeout: int = 10) -> [str, int, str]:\n\"\"\"\n Sign and broadcast a transaction.\n\n Note:\n Takes only positional arguments\n\n Args:\n transaction (Transaction): The transaction object\n\n Returns:\n hash: Transaction hash\n code: Result code\n log: Log (None if transaction successful)\n \"\"\"\n con = self._connect()\n tx_bytes = transaction.get_tx_bytes()\n\n tx_request = self._BroadcastTxRequest(\n tx_bytes=tx_bytes,\n mode=2 # BROADCAST_MODE_SYNC\n )\n\n tx_stub = self._cosmos_tx_service_pb2_grpc.ServiceStub(con)\n tx_data = tx_stub.BroadcastTx(tx_request)\n\n hash = tx_data.tx_response.txhash\n code = tx_data.tx_response.code\n log = None if code == 0 else tx_data.tx_response.raw_log\n\n return {\"hash\": hash, \"code\": code, \"log\": log}\n "},{"location":"clients/grpcclient/#mospy.clients.GRPCClient.GRPCClient.estimate_gas","title":"estimate_gas(*, transaction, update=True, multiplier=1.2) ","text":"Simulate a transaction to get the estimated gas usage. Note Takes only positional arguments Parameters: Name Type Description Default transaction Transaction The transaction object required update bool Update the transaction with the estimated gas amount True multiplier float Multiplier for the estimated gas when updating the transaction. Defaults to 1.2 1.2 Returns: Name Type Description expedted_gas int Expected gas Source code in mospy/clients/GRPCClient.py def estimate_gas(self,\n *,\n transaction: Transaction,\n update: bool = True,\n multiplier: float = 1.2\n ) ->int:\n\"\"\"\n Simulate a transaction to get the estimated gas usage.\n\n Note:\n Takes only positional arguments\n\n Args:\n transaction (Transaction): The transaction object\n update (bool): Update the transaction with the estimated gas amount\n multiplier (float): Multiplier for the estimated gas when updating the transaction. Defaults to 1.2\n\n Returns:\n expedted_gas: Expected gas\n \"\"\"\n con = self._connect()\n tx_bytes = transaction.get_tx_bytes()\n\n simulate_request = self._SimulateTxRequest(\n tx_bytes=tx_bytes,\n )\n\n tx_stub = self._cosmos_tx_service_pb2_grpc.ServiceStub(con)\n tx_data = tx_stub.Simulate(simulate_request)\n\n gas_used = tx_data.gas_info.gas_used\n\n if update:\n transaction.set_gas(int(gas_used * multiplier))\n\n return gas_used\n "},{"location":"clients/grpcclient/#mospy.clients.GRPCClient.GRPCClient.load_account_data","title":"load_account_data(account) ","text":"Load the next_sequence and account_number into the account object. Parameters: Name Type Description Default account Account Account required Source code in mospy/clients/GRPCClient.py def load_account_data(self, account: Account):\n\"\"\"\n Load the ``next_sequence`` and ``account_number`` into the account object.\n\n Args:\n account (Account): Account\n \"\"\"\n con = self._connect()\n address = account.address\n\n query_stub = self._cosmos_auth_query_pb2_grpc.QueryStub(con)\n account_request = self._cosmos_auth_query_pb2.QueryAccountRequest(address=address)\n\n req = query_stub.Account(account_request)\n data = dict(MessageToDict(req.account))\n\n sequence = 0 if not \"sequence\" in data else int(data[\"sequence\"])\n account_number = int(data[\"accountNumber\"])\n\n account.next_sequence = sequence\n account.account_number = account_number\n con.close()\n "},{"location":"clients/httpclient/","title":"HTTPClient","text":"Wrapper class to interact with a cosmos chain through their API endpoint Parameters: Name Type Description Default api str URL to a Api node 'https://api.cosmos.interbloc.org' Source code in mospy/clients/HTTPClient.py class HTTPClient:\n\"\"\"\n Wrapper class to interact with a cosmos chain through their API endpoint\n\n Args:\n api (str): URL to a Api node\n \"\"\"\n\n def __init__(self, *, api: str = \"https://api.cosmos.interbloc.org\"):\n self._api = api\n\n def _make_post_request(self, path, payload, timeout):\n req = httpx.post(self._api + path, json=payload, timeout=timeout)\n\n if req.status_code != 200:\n try:\n data = req.json()\n message = f\"({data['message']}\"\n except:\n message = \"\"\n raise NodeException(f\"Error while doing request to api endpoint {message}\")\n\n data = req.json()\n return data\n\n def load_account_data(self, account: Account):\n\"\"\"\n Load the ``next_sequence`` and ``account_number`` into the account object.\n\n Args:\n account (Account): Account\n \"\"\"\n\n address = account.address\n url = self._api + \"/cosmos/auth/v1beta1/accounts/\" + address\n req = httpx.get(url=url)\n if req.status_code != 200:\n raise NodeException(\"Error while doing request to api endpoint\")\n\n data = req.json()\n sequence = int(data[\"account\"][\"sequence\"])\n account_number = int(data[\"account\"][\"account_number\"])\n\n account.next_sequence = sequence\n account.account_number = account_number\n\n def broadcast_transaction(self,\n *,\n transaction: Transaction,\n timeout: int = 10) -> [str, int, str]:\n\"\"\"\n Sign and broadcast a transaction.\n\n Note:\n Takes only positional arguments\n\n Args:\n transaction (Transaction): The transaction object\n timeout (int): Timeout\n\n Returns:\n hash: Transaction hash\n code: Result code\n log: Log (None if transaction successful)\n \"\"\"\n path = \"/cosmos/tx/v1beta1/txs\"\n tx_bytes = transaction.get_tx_bytes_as_string()\n payload = {\"tx_bytes\": tx_bytes, \"mode\": \"BROADCAST_MODE_SYNC\"}\n\n data = self._make_post_request(path, payload, timeout)\n\n hash = data[\"tx_response\"][\"txhash\"]\n code = data[\"tx_response\"][\"code\"]\n log = None if code == 0 else data[\"tx_response\"][\"raw_log\"]\n\n return {\"hash\": hash, \"code\": code, \"log\": log}\n\n def estimate_gas(self,\n *,\n transaction: Transaction,\n update: bool = True,\n multiplier: float = 1.2,\n timeout: int = 10) ->int:\n\"\"\"\n Simulate a transaction to get the estimated gas usage.\n\n Note:\n Takes only positional arguments\n\n Args:\n transaction (Transaction): The transaction object\n update (bool): Update the transaction with the estimated gas amount\n multiplier (float): Multiplier for the estimated gas when updating the transaction. Defaults to 1.2\n timeout (int): Timeout\n\n Returns:\n expedted_gas: Expected gas\n \"\"\"\n path = \"/cosmos/tx/v1beta1/simulate\"\n tx_bytes = transaction.get_tx_bytes_as_string()\n payload = {\"tx_bytes\": tx_bytes}\n\n data = self._make_post_request(path, payload, timeout)\n\n gas_used = int(data[\"gas_info\"][\"gas_used\"])\n\n if update:\n transaction.set_gas(int(gas_used * multiplier))\n\n return gas_used\n "},{"location":"clients/httpclient/#mospy.clients.HTTPClient.HTTPClient.broadcast_transaction","title":"broadcast_transaction(*, transaction, timeout=10) ","text":"Sign and broadcast a transaction. Note Takes only positional arguments Parameters: Name Type Description Default transaction Transaction The transaction object required timeout int Timeout 10 Returns: Name Type Description hash [str, int, str] Transaction hash code [str, int, str] Result code log [str, int, str] Log (None if transaction successful) Source code in mospy/clients/HTTPClient.py def broadcast_transaction(self,\n *,\n transaction: Transaction,\n timeout: int = 10) -> [str, int, str]:\n\"\"\"\n Sign and broadcast a transaction.\n\n Note:\n Takes only positional arguments\n\n Args:\n transaction (Transaction): The transaction object\n timeout (int): Timeout\n\n Returns:\n hash: Transaction hash\n code: Result code\n log: Log (None if transaction successful)\n \"\"\"\n path = \"/cosmos/tx/v1beta1/txs\"\n tx_bytes = transaction.get_tx_bytes_as_string()\n payload = {\"tx_bytes\": tx_bytes, \"mode\": \"BROADCAST_MODE_SYNC\"}\n\n data = self._make_post_request(path, payload, timeout)\n\n hash = data[\"tx_response\"][\"txhash\"]\n code = data[\"tx_response\"][\"code\"]\n log = None if code == 0 else data[\"tx_response\"][\"raw_log\"]\n\n return {\"hash\": hash, \"code\": code, \"log\": log}\n "},{"location":"clients/httpclient/#mospy.clients.HTTPClient.HTTPClient.estimate_gas","title":"estimate_gas(*, transaction, update=True, multiplier=1.2, timeout=10) ","text":"Simulate a transaction to get the estimated gas usage. Note Takes only positional arguments Parameters: Name Type Description Default transaction Transaction The transaction object required update bool Update the transaction with the estimated gas amount True multiplier float Multiplier for the estimated gas when updating the transaction. Defaults to 1.2 1.2 timeout int Timeout 10 Returns: Name Type Description expedted_gas int Expected gas Source code in mospy/clients/HTTPClient.py def estimate_gas(self,\n *,\n transaction: Transaction,\n update: bool = True,\n multiplier: float = 1.2,\n timeout: int = 10) ->int:\n\"\"\"\n Simulate a transaction to get the estimated gas usage.\n\n Note:\n Takes only positional arguments\n\n Args:\n transaction (Transaction): The transaction object\n update (bool): Update the transaction with the estimated gas amount\n multiplier (float): Multiplier for the estimated gas when updating the transaction. Defaults to 1.2\n timeout (int): Timeout\n\n Returns:\n expedted_gas: Expected gas\n \"\"\"\n path = \"/cosmos/tx/v1beta1/simulate\"\n tx_bytes = transaction.get_tx_bytes_as_string()\n payload = {\"tx_bytes\": tx_bytes}\n\n data = self._make_post_request(path, payload, timeout)\n\n gas_used = int(data[\"gas_info\"][\"gas_used\"])\n\n if update:\n transaction.set_gas(int(gas_used * multiplier))\n\n return gas_used\n "},{"location":"clients/httpclient/#mospy.clients.HTTPClient.HTTPClient.load_account_data","title":"load_account_data(account) ","text":"Load the next_sequence and account_number into the account object. Parameters: Name Type Description Default account Account Account required Source code in mospy/clients/HTTPClient.py def load_account_data(self, account: Account):\n\"\"\"\n Load the ``next_sequence`` and ``account_number`` into the account object.\n\n Args:\n account (Account): Account\n \"\"\"\n\n address = account.address\n url = self._api + \"/cosmos/auth/v1beta1/accounts/\" + address\n req = httpx.get(url=url)\n if req.status_code != 200:\n raise NodeException(\"Error while doing request to api endpoint\")\n\n data = req.json()\n sequence = int(data[\"account\"][\"sequence\"])\n account_number = int(data[\"account\"][\"account_number\"])\n\n account.next_sequence = sequence\n account.account_number = account_number\n "},{"location":"transaction/types/","title":"Transaction Types","text":"Nearly every cosmos chain has its transaction types usually on top of the standard cosmos ones. Mospy supports some standard transaction types that should be the same on every chain. However, every chain can modify these and you would then need to implement that change by yourself. But this will be explained here. "},{"location":"transaction/types/#data-structures","title":"Data structures","text":"In general, the cosmos sdk uses the protobuf data format to define data structures. These protobuf files serve as documentation and help to serialize the data directly in your code. To make protobufs more accessible for python I am maintaining the cosmospy-protobuf library which contains all cosmos protobuf files compiled for python. Mospy is using cosmospy-protobuf. The naming scheme is following the official cosmos naming scheme. This is especially useful when working with different transaction types. "},{"location":"transaction/types/#included-transaction-types","title":"Included transaction types","text":"Mospy ships some standard transaction types for easier implementation. Currently, following transaction types are supported: * MsgSend * MsgDelegate * MsgUndelegate * MsgWithdrawDelegatorReward Each transaction type takes different keyword arguments. You can check out the examples to see how to use each type. The following example will use the MsgSend type as it is the most common one: from mospy import Transaction, Account\n\naccount = Account(...)\ntx = Transaction(...)\n\ntx.add_msg(\n tx_type='transfer',\n sender=account,\n receipient=\"cosmos1tkv9rquxr88r7snrg42kxdj9gsnfxxg028kuh9\",\n amount=1000,\n denom=\"uatom\"\n)\n\n# Sign and broadcast\n The first argument always defines the transaction type. The following required arguments are then defined by each adapter. You have to use keyword arguments. "},{"location":"transaction/types/#custom-transaction-types","title":"Custom transaction types","text":"Transaction types that aren't integrated can be added to the transaction class through the add_raw_msg method. This function takes two arguments. The method takes two arguments. The first one is the msg data in the protobuf format and the second one is the type url. For instance, if you want to make a transaction that changes the reward withdraw address you will need to implement the transaction with the type /cosmos.distribution.v1beta1.MsgSetWithdrawAddress . The compiled protobuf files are available at cosmospy_protobuf.cosmos.distribution.v1beta1.tx_pb2 . To see what data you need to pass you can check out the according protobuf file in the cosmospy-protobuf repository: https://github.com/ctrl-Felix/cosmospy-protobuf/blob/main/src/cosmospy_protobuf/cosmos/distribution/v1beta1/tx.proto#L31 The full example will look like this: from mospy import Transaction\nfrom cosmospy_protobuf.cosmos.distribution.v1beta1.tx_pb2 import MsgSetWithdrawAddress\n\ntx = Transaction(...)\n\nwmsg = MsgSetWithdrawAddress(\n delegator_address=\"cosmos1...\",\n withdraw_address=\"cosmos1...\"\n\n)\ntx.add_raw_msg(wmsg, type_url=\"/cosmos.distribution.v1beta1.MsgSetWithdrawAddress\")\n\n# Sign and broadcast\n\n You see! It's not complicated at all. "},{"location":"transaction/types/#transaction-body","title":"Transaction body","text":"A transaction can have many messages with different transaction types. You can save a lot of fees by aggregating your messages into one big transaction. But keep in mind. If one message fails the whole transaction and all messages fail. "}]}
\ No newline at end of file
+{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"MosPy","text":"MosPy is a cosmospy fork and aims to be a versatile transaction signing library for the whole cosmos ecosystem. "},{"location":"#installation","title":"Installation","text":"Mospy is available on pypi: python -m pip install mospy-wallet Note: Even though the name is mospy-wallet on pypi the library itself is called mospy "},{"location":"#dependencies","title":"Dependencies","text":"By default mospy will import the protobuf files from cosmospy-protobuf and therefore work with the Cosmos chain. If you want to use it on another chain I highly recommend to use thee according protobufs to avoid version conflicts. The Account and Transaction class both take a protobuf argument to specify the protobufs. Note: You have to install them manually as mospy ships woth cosmospy_protobuf. You can use: evmos for evmos-protobuf osmosis for osmosis-protobuf cosmos for cosmospy-protobuf (default) <your module here> for your own protobuf module following the cosmos name schema "},{"location":"#get-started","title":"Get started","text":"import httpx # optional\nfrom mospy import Account, Transaction\n\naccount = Account(\n seed_phrase=\"law grab theory better athlete submit awkward hawk state wedding wave monkey audit blame fury wood tag rent furnace exotic jeans drift destroy style\",\n address_index=12\n)\n\ntx = Transaction(\n account=account,\n gas=1000,\n)\ntx.set_fee(\n amount=100,\n denom=\"uatom\"\n)\n# Add a transfer message to the transaction (multiple messages can be added)\ntx.add_msg(\n tx_type='transfer',\n sender=account,\n receipient=\"cosmos1tkv9rquxr88r7snrg42kxdj9gsnfxxg028kuh9\",\n amount=1000,\n denom=\"uatom\"\n)\n\n# Sign and encode transaction to submit it to the network manually\n\n# REST endpoint (RPC or API)\ntx_bytes = tx.get_tx_bytes_as_string()\n\n# Submit the transaction through the Tendermint RPC\nrpc_url = \"https://rpc.cosmos.network/\"\npushable_tx = json.dumps(\n {\n \"jsonrpc\": \"2.0\",\n \"id\": 1,\n \"method\": \"broadcast_tx_sync\", # Available methods: broadcast_tx_sync, broadcast_tx_async, broadcast_tx_commit\n \"params\": {\n \"tx\": tx_bytes\n }\n }\n )\nr = httpx.post(rpc_url, data=pushable_tx)\n\n# Submit the transaction through the Cosmos REST API\nrpc_api = \"https://api.cosmos.network/cosmos/tx/v1beta1/txs\"\npushable_tx = json.dumps(\n {\n \"tx_bytes\": tx_bytes,\n \"mode\": \"BROADCAST_MODE_SYNC\" # Available modes: BROADCAST_MODE_SYNC, BROADCAST_MODE_ASYNC, BROADCAST_MODE_BLOCK\n }\n )\nr = httpx.post(rpc_api, data=pushable_tx)\n "},{"location":"#support","title":"Support","text":"When facing issues feel free to open a github issue or reach out to the creators on the Osmosis Discord. "},{"location":"account/","title":"Account","text":"The account class can be instantiated through a seed or a private key. If nothing is provided it will create a new keyring and the params to work with the cosmos chain Note - You can't provide a
seed_phrase and aprivate_key - A
readble method behaves is the getter for a Attribute (Example: hrp = account.hrp ) - A
writable method is the setter for the Attribute (Example: account.hrp = \"cosmos\" ) - A method can be setter and getter at the same time. The Parameters description always refers to the setter while the Returns section belongs to the getter
Parameters: Name Type Description Default seed_phrase str Seed phrase to derive private keys from None private_key str Private key to instantiate the Account None next_sequence int Sequence which will be used for transactions signed with this Account None account_number int On-chain account number None slip44 int Slip44 value 118 hrp str Address Prefix 'cosmos' address_index int Address index to get sub accounts for seed phrases (doesn't work when using a private key) 0 protobuf str Define which protobuf files to use. Cosmos, Evmos and Osmosis are built in and otherwise pass the raw package name (cosmospy-protobuf) 'cosmos' eth bool Etermint compatibility mpde. If set to true the addresses and signatures will match the ethereum standard. Defaults to false to match the Cosmos standard. False Source code in mospy/Account.py class Account:\n\"\"\"\n The account class can be instantiated through a seed or a private key. If nothing is provided it will create a new keyring and the params to work with the cosmos chain\n\n Note:\n * You can't provide a ``seed_phrase`` and a``private_key``\n * A ``readble`` method behaves is the getter for a Attribute (Example: ``hrp = account.hrp``)\n * A ``writable`` method is the setter for the Attribute (Example: ``account.hrp = \"cosmos\"``)\n * A method can be setter and getter at the same time. The Parameters description always refers to the setter while the Returns section belongs to the getter\n\n\n Args:\n seed_phrase (str): Seed phrase to derive private keys from\n private_key (str): Private key to instantiate the Account\n next_sequence (int): Sequence which will be used for transactions signed with this Account\n account_number (int): On-chain account number\n slip44 (int): Slip44 value\n hrp (str): Address Prefix\n address_index (int): Address index to get sub accounts for seed phrases (doesn't work when using a private key)\n protobuf (str): Define which protobuf files to use. Cosmos, Evmos and Osmosis are built in and otherwise pass the raw package name (cosmospy-protobuf)\n eth (bool): Etermint compatibility mpde. If set to true the addresses and signatures will match the ethereum standard. Defaults to false to match the Cosmos standard.\n \"\"\"\n\n address: str\n\"\"\"the address of the account derived by using the slip44 param, the hrp and the address_index\"\"\"\n\n _RAW_DERIVATION_PATH = \"m/44'/{slip44}'/0'/0/{address_index}\"\n\n def __init__(\n self,\n seed_phrase: str = None,\n private_key: str = None,\n next_sequence: int = None,\n account_number: int = None,\n slip44: int = 118,\n hrp: str = \"cosmos\",\n address_index: int = 0,\n protobuf: str = \"cosmos\",\n eth: bool = False,\n public_key_type: str = None\n ):\n _protobuf_packages = {\n \"cosmos\": \"cosmospy_protobuf\",\n \"osmosis\": \"osmosis_protobuf\",\n \"evmos\": \"evmos_protobuf\",\n \"sentinel\": \"sentinel_protobuf\",\n }\n _protobuf_package = (_protobuf_packages[protobuf.lower()]\n if protobuf.lower() in _protobuf_packages.keys()\n else protobuf)\n\n\n try:\n self.keys_pb2 = importlib.import_module(\n _protobuf_package + \".cosmos.crypto.secp256k1.keys_pb2\")\n except AttributeError:\n raise ImportError(\n \"It seems that you are importing conflicting protobuf files. Have sou set the protobuf attribute to specify your coin? Check out the documentation for more information.\"\n )\n except:\n raise ImportError(\n f\"Couldn't import from {_protobuf_package}. Is the package installed? \"\n )\n\n self._eth = eth\n self._slip44 = slip44\n self._hrp = hrp\n self._address_index = address_index\n self._next_sequence = next_sequence\n self._account_number = account_number\n\n # Set the public key type\n if public_key_type:\n self._public_key_type = public_key_type\n else:\n if eth:\n # Add Injectiver as exception as they use ethermint but with their own definition\n # Otherwise default to ethermint\n if hrp == \"inj\":\n self._public_key_type = \"/injective.crypto.v1beta1.ethsecp256k1.PubKey\"\n else:\n self._public_key_type = \"/ethermint.crypto.v1.ethsecp256k1.PubKey\"\n else:\n self._public_key_type = \"/cosmos.crypto.secp256k1.PubKey\"\n\n if not seed_phrase and not private_key:\n self._seed_phrase = Mnemonic(language=\"english\").generate(\n strength=256)\n self._private_key = seed_to_private_key(self._seed_phrase,\n self._derivation_path())\n\n elif seed_phrase and not private_key:\n self._seed_phrase = seed_phrase\n self._private_key = seed_to_private_key(seed_phrase,\n self._derivation_path())\n\n elif private_key and not seed_phrase:\n self._seed_phrase = None\n self._private_key = bytes.fromhex(private_key)\n\n else:\n raise AttributeError(\n \"Please set only a private key or a seed phrase. Not both!\")\n\n def _derivation_path(self, address_index: int = None):\n adr_id = self._address_index if not address_index else address_index\n params = {\"slip44\": self._slip44, \"address_index\": adr_id}\n return self._RAW_DERIVATION_PATH.format(**params)\n\n @property\n def address(self) -> str:\n\"\"\"\n Current address which depends on the hrp and the private key.\n\n Returns:\n Address\n \"\"\"\n if not self._seed_phrase:\n address = privkey_to_address(self._private_key, hrp=self._hrp) if not self._eth else privkey_to_eth_address(self._private_key, hrp=self._hrp)\n else:\n sub_private_key = seed_to_private_key(\n self._seed_phrase,\n self._derivation_path(address_index=self._address_index),\n )\n address = privkey_to_address(sub_private_key, hrp=self._hrp) if not self._eth else privkey_to_eth_address(sub_private_key, hrp=self._hrp)\n\n return address\n\n @property\n def eth_address(self) -> str:\n\"\"\"\n Ethereum compatible address starting with 0x. Only available if Account is initialised with eth set to True.\n\n Returns:\n Address\n \"\"\"\n if not self._eth:\n raise TypeError(\"Account hasn't been initialised with the eth mode set to true.\")\n if not self._seed_phrase:\n address = privkey_to_eth_address(self._private_key)\n else:\n sub_private_key = seed_to_private_key(\n self._seed_phrase,\n self._derivation_path(address_index=self._address_index),\n )\n address = privkey_to_eth_address(sub_private_key)\n\n return address\n\n @property\n def seed_phrase(self) -> str:\n\"\"\"\n Current Seed Phrase\n\n Returns:\n Seed Phrase\n \"\"\"\n return self._seed_phrase\n\n @property\n def private_key(self) -> bytes:\n\"\"\"\n Current private key which depends on the slip 44 param and the address index if the account is instantiated through a seed.\n\n Returns:\n Private Key\n \"\"\"\n if self._seed_phrase:\n private_key = seed_to_private_key(\n self._seed_phrase,\n self._derivation_path(address_index=self._address_index),\n )\n return private_key\n else:\n return self._private_key\n\n @property\n def public_key(self) -> str:\n\"\"\"\n Current public key which depends on the slip 44 param and the address index if the account is instantiated through a seed.\n\n Returns:\n Public Key\n \"\"\"\n pubkey_bytes = privkey_to_pubkey(self.private_key)\n _pubkey = self.keys_pb2.PubKey()\n _pubkey.key = pubkey_bytes\n return _pubkey\n\n @property\n def account_number(self) -> int:\n\"\"\"\n On-chain account number which will be assigned when the address receives coins for the first time.\n\n Returns:\n Account number\n \"\"\"\n return self._account_number\n\n @account_number.setter\n def account_number(self, account_number: int):\n self._account_number = account_number\n\n @property\n def next_sequence(self) -> int:\n\"\"\"\n Sequence which will be used for transactions signed with this Account.\n\n Returns:\n Next Sequence\n \"\"\"\n return self._next_sequence\n\n @next_sequence.setter\n def next_sequence(self, next_sequence):\n self._next_sequence = next_sequence\n\n def increase_sequence(self, change: int = 1) -> None:\n\"\"\"\n Increase the sequence by ``change``\n\n Args:\n change (int): Value to increase the sequence\n \"\"\"\n self._next_sequence += change\n\n @property\n def address_index(self):\n\"\"\"\n Change the address index to use a sub account. This works only if a seed has been used to instantiate the Account.\n\n\n Returns:\n Address Index\n \"\"\"\n return self._address_index\n\n @address_index.setter\n def address_index(self, address_index: int) -> None:\n\n if self._seed_phrase:\n self._DEFAULT_ADDRESS_INDEX = address_index\n else:\n raise ValueError(\n \"Can't the change the address index without provided seed\")\n\n @property\n def hrp(self) -> str:\n\"\"\"\n Current address prefix used by the Account.\n\n Returns:\n Address Prefix (hrp)\n \"\"\"\n return self._hrp\n\n @hrp.setter\n def hrp(self, hrp: str) -> None:\n self._hrp = hrp\n\n @property\n def slip44(self) -> int:\n\"\"\"\n Set the Slip44 value. Cosmos defaults to 118\n\n Returns:\n Slip44\n\n \"\"\"\n return self._slip44\n\n @slip44.setter\n def slip44(self, slip44: int) -> None:\n self._slip44 = slip44\n\n @property\n def eth(self) -> bool:\n\"\"\"\n Change the eth compatibility mode. If you want to use Evmos you will need to set eth to true. Otherwise it defaults to False\n\n Returns:\n eth\n \"\"\"\n return self._eth\n\n @eth.setter\n def eth(self, eth: bool):\n\n self._eth = eth\n\n @property\n def public_key_type(self):\n\"\"\"\n Get the current pyblic key type\n\n Returns:\n public_key_type\n \"\"\"\n return self._public_key_type\n @public_key_type.setter\n def public_key_type(self, public_key_type):\n self._public_key_type = public_key_type\n "},{"location":"account/#mospy.Account.Account.account_number","title":"account_number: int property writable ","text":"On-chain account number which will be assigned when the address receives coins for the first time. Returns: Type Description int Account number "},{"location":"account/#mospy.Account.Account.address","title":"address: str property ","text":"Current address which depends on the hrp and the private key. Returns: Type Description str Address "},{"location":"account/#mospy.Account.Account.address_index","title":"address_index property writable ","text":"Change the address index to use a sub account. This works only if a seed has been used to instantiate the Account. Returns: Type Description Address Index "},{"location":"account/#mospy.Account.Account.eth","title":"eth: bool property writable ","text":"Change the eth compatibility mode. If you want to use Evmos you will need to set eth to true. Otherwise it defaults to False Returns: Type Description bool eth "},{"location":"account/#mospy.Account.Account.eth_address","title":"eth_address: str property ","text":"Ethereum compatible address starting with 0x. Only available if Account is initialised with eth set to True. Returns: Type Description str Address "},{"location":"account/#mospy.Account.Account.hrp","title":"hrp: str property writable ","text":"Current address prefix used by the Account. Returns: Type Description str Address Prefix (hrp) "},{"location":"account/#mospy.Account.Account.next_sequence","title":"next_sequence: int property writable ","text":"Sequence which will be used for transactions signed with this Account. Returns: Type Description int Next Sequence "},{"location":"account/#mospy.Account.Account.private_key","title":"private_key: bytes property ","text":"Current private key which depends on the slip 44 param and the address index if the account is instantiated through a seed. Returns: Type Description bytes Private Key "},{"location":"account/#mospy.Account.Account.public_key","title":"public_key: str property ","text":"Current public key which depends on the slip 44 param and the address index if the account is instantiated through a seed. Returns: Type Description str Public Key "},{"location":"account/#mospy.Account.Account.public_key_type","title":"public_key_type property writable ","text":"Get the current pyblic key type Returns: Type Description public_key_type "},{"location":"account/#mospy.Account.Account.seed_phrase","title":"seed_phrase: str property ","text":"Current Seed Phrase Returns: Type Description str Seed Phrase "},{"location":"account/#mospy.Account.Account.slip44","title":"slip44: int property writable ","text":"Set the Slip44 value. Cosmos defaults to 118 Returns: Type Description int Slip44 "},{"location":"account/#mospy.Account.Account.increase_sequence","title":"increase_sequence(change=1) ","text":"Increase the sequence by change Parameters: Name Type Description Default change int Value to increase the sequence 1 Source code in mospy/Account.py def increase_sequence(self, change: int = 1) -> None:\n\"\"\"\n Increase the sequence by ``change``\n\n Args:\n change (int): Value to increase the sequence\n \"\"\"\n self._next_sequence += change\n "},{"location":"examples/","title":"Examples","text":"Here you'll find some useful code snippets to get started with MosPy "},{"location":"examples/#account","title":"Account","text":"Examples showing the use of the account class "},{"location":"examples/#account-creation","title":"Account creation","text":"\nfrom mospy import Account\n\n# Generate a new Account with a new seed phrase\naccount1 = Account()\n\n# Create an account object through a seed phrase and \n# get a sub-account of that seed by passing the address index (optional)\n\naccount2 = Account(\n seed_phrase=\"law grab theory better athlete submit awkward hawk state wedding wave monkey audit blame fury wood tag rent furnace exotic jeans drift destroy style\",\n address_index=12\n)\n\n# Instantiate the Account by using a private key and\n# set a different address prefix to use another cosmos based chain as well as\n# the nex account sequence and account number (example values)\n\naccount3 = Account(\n private_key=\"8c2ae3f9c216f714c0a877e7a4952ec03462496e01452bd5ee79ef79d707ff6c\",\n hrp=\"osmo\",\n next_sequence=1,\n account_number=187486\n)\n\n\n "},{"location":"examples/#transaction","title":"Transaction","text":"Showcase how to create use the Transaction class from mospy import Transaction\nfrom cosmospy_protobuf.cosmos.base.v1beta1.coin_pb2 import Coin # Optional\n\n# Create the fee object from the protobufs and pass it when instantiating the Transaction\n# or add it later through the set_fee function\nfee = Coin(\n denom=\"uatom\",\n amount=\"1000\"\n)\n\n# Create the transaction object by passing the account object from the step above\ntx = Transaction(\n account=account3,\n fee=fee,\n gas=1000,\n)\n\n# Add a transfer message to the transaction (multiple messages can be added)\ntx.add_msg(\n tx_type='transfer',\n sender=account3,\n receipient=\"cosmos1tkv9rquxr88r7snrg42kxdj9gsnfxxg028kuh9\",\n amount=1000,\n denom=\"uatom\"\n)\n\n# Sign and encode transaction to submit it to the network manually\n\n# REST endpoint (RPC or API)\ntx_bytes = tx.get_tx_bytes_as_string()\n\n# GRPC\ntx_bytes = tx.get_tx_bytes()\n "},{"location":"examples/#custom-transaction-message","title":"Custom Transaction Message","text":"You can easily use every other tx type too. The type_url usually matches the import path. # References the tx class from above before signing\n\nfrom cosmospy_protobuf.cosmos.distribution.v1beta1.tx_pb2 import MsgSetWithdrawAddress\n\nwmsg = MsgSetWithdrawAddress(\n delegator_address=account.address,\n withdraw_address=\"newaddresshere\"\n\n)\ntx.add_raw_msg(wmsg, type_url=\"/cosmos.distribution.v1beta1.MsgSetWithdrawAddress\")\n\n "},{"location":"examples/#client","title":"Client","text":"Examples howing the usage of the included clients from mospy.clients import HTTPClient\n\n# Instantiate a HTTPClient object by passing a custom API endpoint.\n# https://api.cosmos.network is chosen if no api provider is provided\nclient = HTTPClient(\n api=\"https://api.cosmos.interbloc.org\"\n)\n\n# Update the account object to set the current on chain sequence and account_number\nclient.load_account_data(account=account)\n\n# Broadcast a transaction\n# Note: Do not call 'get_tx_bytes' on the transaction object before \n# as it will be signed twice then\nhash, code, log = client.broadcast_transaction(transaction=tx)\n "},{"location":"examples/#ethereumethermint-transaction","title":"Ethereum/Ethermint Transaction","text":"Make a transaction on chains using Ethermint like Evmos from mospy import Transaction\nfrom mospy.clients import HTTPClient\n\nfrom src.mospy import Account\n\n# As the account query returns a different json than the standard cosmos one evmos won't be compatible with the \n# client.load_account() function \naccount = Account(\n seed_phrase=\"law grab theory better athlete submit awkward hawk state wedding wave monkey audit blame fury wood tag rent furnace exotic jeans drift destroy style\",\n hrp=\"evmos\",\n slip44=60,\n eth=True,\n next_sequence=1,\n account_number=2154050,\n )\n\ntx = Transaction(\n account=account,\n gas=2000000,\n memo=\"The first mospy evmos transaction!\",\n chain_id=\"evmos_9001-2\",\n)\n\ntx.set_fee(\n denom=\"aevmos\",\n amount=40000000000000000\n)\ntx.add_msg(\n tx_type=\"transfer\",\n sender=account,\n receipient=account.address,\n amount=3500000000000000,\n denom=\"aevmos\",\n)\n\nclient = HTTPClient(api=\"https://api.evmos.interbloc.org\")\ntx_response = client.broadcast_transaction(transaction=tx)\n "},{"location":"transaction/","title":"Transaction","text":"Class to create and sign a transaction Parameters: Name Type Description Default account Account Account object to sign this transaction required gas int Gas unit for this transaction required fee coin The fee to pay for this transaction (This can also be added later through the set_fee method) None memo str Memo '' chain_id str Chain-Id \"cosmoshub-4\", 'cosmoshub-4' protobuf str Define which protobuf files to use. Cosmos, Evmos and Osmosis are built in and otherwise pass the raw package name (cosmospy-protobuf) 'cosmos' Source code in mospy/Transaction.py class Transaction:\n\"\"\"Class to create and sign a transaction\n Args:\n account (Account): Account object to sign this transaction\n gas (int): Gas unit for this transaction\n fee (coin): The fee to pay for this transaction (This can also be added later through the ``set_fee`` method)\n memo (str): Memo\n chain_id (str): Chain-Id \"cosmoshub-4\",\n protobuf (str): Define which protobuf files to use. Cosmos, Evmos and Osmosis are built in and otherwise pass the raw package name (cosmospy-protobuf)\n\n\n \"\"\"\n\n def __init__(\n self,\n *,\n account: Account,\n gas: int,\n fee: object = None,\n memo: str = \"\",\n chain_id: str = \"cosmoshub-4\",\n protobuf: str = \"cosmos\",\n feegrant: str = \"\"\n ) -> None:\n\n _protobuf_packages = {\n \"cosmos\": \"cosmospy_protobuf\",\n \"osmosis\": \"osmosis_protobuf\",\n \"evmos\": \"evmos_protobuf\",\n \"sentinel\": \"sentinel_protobuf\",\n }\n self._protobuf_package = (_protobuf_packages[protobuf.lower()]\n if protobuf.lower()\n in _protobuf_packages.keys() else protobuf)\n try:\n self.coin_pb2 = importlib.import_module(\n self._protobuf_package + \".cosmos.base.v1beta1.coin_pb2\")\n self.tx_pb2 = importlib.import_module(self._protobuf_package +\n \".cosmos.tx.v1beta1.tx_pb2\")\n except:\n raise ImportError(\n f\"Couldn't import from {self._protobuf_package}. Is the package installed?\"\n )\n\n if fee and not isinstance(fee, (self.coin_pb2.Coin)):\n raise ValueError(\"The fee is not a valid.\")\n\n self._account = account\n self._fee = fee\n self._gas = gas\n self._chain_id = chain_id\n self._tx_body = self.tx_pb2.TxBody()\n self._tx_body.memo = memo\n self._tx_raw = self.tx_pb2.TxRaw()\n self._feegrant = feegrant\n\n def add_msg(self, tx_type: str, **kwargs) -> None:\n\"\"\"\n Add a pre-defined message to the tx body.\n\n Args:\n tx_type (str): Transaction type to match the transaction with the pre-defined ones\n **kwargs: Depending on the transaction type\n \"\"\"\n msg_data = built_in_transactions[tx_type](\n protobuf_package=self._protobuf_package, **kwargs).format()\n self.add_raw_msg(msg_data[1], type_url=msg_data[0])\n\n def add_raw_msg(self, unpacked_msg, type_url: str) -> None:\n\"\"\"\n Add a message to the tx body manually.\n\n Args:\n unpacked_msg: Transaction data\n type_url: Type url for the transaction\n \"\"\"\n msg_any = any.Any()\n msg_any.Pack(unpacked_msg)\n msg_any.type_url = type_url\n self._tx_body.messages.append(msg_any)\n\n def set_fee(self, amount: int, denom: str = \"uatom\"):\n\"\"\"\n Set the fee manually\n\n Args:\n amount: Amount\n denom: Denom\n \"\"\"\n self._fee = self.coin_pb2.Coin(amount=str(amount), denom=denom)\n\n def set_gas(self, gas: int):\n\"\"\"\n Update the wanted gas for the transaction\n\n Args:\n gas: Gas\n \"\"\"\n self._gas = gas\n\n def get_tx_bytes(self) -> bytes:\n\"\"\"Sign the transaction and get the tx bytes which can be used to broadcast the transaction to the network.\n\n To broadcast the transaction through the REST endpoint use the ``get_tx_bytes_as_string()`` method instead\n\n Returns:\n tx_bytes (bytes): Transaction bytes\n \"\"\"\n self._tx_raw = self.tx_pb2.TxRaw()\n self._tx_raw.body_bytes = self._tx_body.SerializeToString()\n self._tx_raw.auth_info_bytes = self._get_auth_info().SerializeToString(\n )\n self._tx_raw.signatures.append(self._get_signatures())\n raw_tx = self._tx_raw.SerializeToString()\n tx_bytes = bytes(raw_tx)\n return tx_bytes\n\n def get_tx_bytes_as_string(self) -> str:\n\"\"\"Sign the transaction and get the base64 encoded tx bytes which can be used to broadcast the transaction to the network.\n\n Returns:\n tx_bytes (str): Transaction bytes\n \"\"\"\n tx_bytes = self.get_tx_bytes()\n tx_b64 = base64.b64encode(tx_bytes).decode(\"utf-8\")\n return tx_b64\n\n def _get_signatures(self):\n privkey = ecdsa.SigningKey.from_string(self._account.private_key,\n curve=ecdsa.SECP256k1)\n\n # Cosmos uses sha256 as main hashing function while ethereum uses keccak256\n hashfunc = hashlib.sha256 if not self._account.eth else keccak_256\n\n signature_compact = privkey.sign_deterministic(\n self._get_sign_doc().SerializeToString(),\n hashfunc=hashfunc,\n sigencode=ecdsa.util.sigencode_string_canonize,\n )\n return signature_compact\n\n def _get_sign_doc(self):\n sign_doc = self.tx_pb2.SignDoc()\n sign_doc.body_bytes = self._tx_body.SerializeToString()\n sign_doc.auth_info_bytes = self._get_auth_info().SerializeToString()\n sign_doc.chain_id = self._chain_id\n sign_doc.account_number = self._account.account_number\n return sign_doc\n\n def _get_auth_info(self):\n _auth_info = self.tx_pb2.AuthInfo()\n _auth_info.signer_infos.append(self._get_signer_infos())\n _auth_info.fee.gas_limit = self._gas\n _auth_info.fee.amount.append(self._fee)\n if self._feegrant:\n _auth_info.fee.granter = self._feegrant\n return _auth_info\n\n def _get_signer_infos(self):\n signer_infos = self.tx_pb2.SignerInfo()\n signer_infos.sequence = self._account.next_sequence\n signer_infos.public_key.Pack(self._account.public_key)\n signer_infos.public_key.type_url = self._account.public_key_type\n signer_infos.mode_info.single.mode = 1\n return signer_infos\n "},{"location":"transaction/#mospy.Transaction.Transaction.add_msg","title":"add_msg(tx_type, **kwargs) ","text":"Add a pre-defined message to the tx body. Parameters: Name Type Description Default tx_type str Transaction type to match the transaction with the pre-defined ones required **kwargs Depending on the transaction type {} Source code in mospy/Transaction.py def add_msg(self, tx_type: str, **kwargs) -> None:\n\"\"\"\n Add a pre-defined message to the tx body.\n\n Args:\n tx_type (str): Transaction type to match the transaction with the pre-defined ones\n **kwargs: Depending on the transaction type\n \"\"\"\n msg_data = built_in_transactions[tx_type](\n protobuf_package=self._protobuf_package, **kwargs).format()\n self.add_raw_msg(msg_data[1], type_url=msg_data[0])\n "},{"location":"transaction/#mospy.Transaction.Transaction.add_raw_msg","title":"add_raw_msg(unpacked_msg, type_url) ","text":"Add a message to the tx body manually. Parameters: Name Type Description Default unpacked_msg Transaction data required type_url str Type url for the transaction required Source code in mospy/Transaction.py def add_raw_msg(self, unpacked_msg, type_url: str) -> None:\n\"\"\"\n Add a message to the tx body manually.\n\n Args:\n unpacked_msg: Transaction data\n type_url: Type url for the transaction\n \"\"\"\n msg_any = any.Any()\n msg_any.Pack(unpacked_msg)\n msg_any.type_url = type_url\n self._tx_body.messages.append(msg_any)\n "},{"location":"transaction/#mospy.Transaction.Transaction.get_tx_bytes","title":"get_tx_bytes() ","text":"Sign the transaction and get the tx bytes which can be used to broadcast the transaction to the network. To broadcast the transaction through the REST endpoint use the get_tx_bytes_as_string() method instead Returns: Name Type Description tx_bytes bytes Transaction bytes Source code in mospy/Transaction.py def get_tx_bytes(self) -> bytes:\n\"\"\"Sign the transaction and get the tx bytes which can be used to broadcast the transaction to the network.\n\n To broadcast the transaction through the REST endpoint use the ``get_tx_bytes_as_string()`` method instead\n\n Returns:\n tx_bytes (bytes): Transaction bytes\n \"\"\"\n self._tx_raw = self.tx_pb2.TxRaw()\n self._tx_raw.body_bytes = self._tx_body.SerializeToString()\n self._tx_raw.auth_info_bytes = self._get_auth_info().SerializeToString(\n )\n self._tx_raw.signatures.append(self._get_signatures())\n raw_tx = self._tx_raw.SerializeToString()\n tx_bytes = bytes(raw_tx)\n return tx_bytes\n "},{"location":"transaction/#mospy.Transaction.Transaction.get_tx_bytes_as_string","title":"get_tx_bytes_as_string() ","text":"Sign the transaction and get the base64 encoded tx bytes which can be used to broadcast the transaction to the network. Returns: Name Type Description tx_bytes str Transaction bytes Source code in mospy/Transaction.py def get_tx_bytes_as_string(self) -> str:\n\"\"\"Sign the transaction and get the base64 encoded tx bytes which can be used to broadcast the transaction to the network.\n\n Returns:\n tx_bytes (str): Transaction bytes\n \"\"\"\n tx_bytes = self.get_tx_bytes()\n tx_b64 = base64.b64encode(tx_bytes).decode(\"utf-8\")\n return tx_b64\n "},{"location":"transaction/#mospy.Transaction.Transaction.set_fee","title":"set_fee(amount, denom='uatom') ","text":"Set the fee manually Parameters: Name Type Description Default amount int Amount required denom str Denom 'uatom' Source code in mospy/Transaction.py def set_fee(self, amount: int, denom: str = \"uatom\"):\n\"\"\"\n Set the fee manually\n\n Args:\n amount: Amount\n denom: Denom\n \"\"\"\n self._fee = self.coin_pb2.Coin(amount=str(amount), denom=denom)\n "},{"location":"transaction/#mospy.Transaction.Transaction.set_gas","title":"set_gas(gas) ","text":"Update the wanted gas for the transaction Parameters: Name Type Description Default gas int Gas required Source code in mospy/Transaction.py def set_gas(self, gas: int):\n\"\"\"\n Update the wanted gas for the transaction\n\n Args:\n gas: Gas\n \"\"\"\n self._gas = gas\n "},{"location":"clients/","title":"Clients","text":"The client classes contain helper functions supporting you while interacting with the chain. "},{"location":"clients/#supported-endpoints","title":"Supported Endpoints","text":" - API:
HTTPClient - GRPC:
GRPCClient "},{"location":"clients/grpcclient/","title":"HTTPClient","text":"Wrapper class to interact with a cosmos chain through their grpc endpoint Parameters: Name Type Description Default host str URL to a Cosmos api node 'cosmoshub.strange.love' port int Port to connect to 9090 ssl bool Whether a ssl encrypted endpoint should be used False protobuf str Define which protobuf files to use. Cosmos, Evmos and Osmosis are built in and otherwise pass the raw package name (cosmospy-protobuf) 'cosmos' Source code in mospy/clients/GRPCClient.py class GRPCClient:\n\"\"\"\n Wrapper class to interact with a cosmos chain through their grpc endpoint\n\n Args:\n host (str): URL to a Cosmos api node\n port (int): Port to connect to\n ssl (bool): Whether a ssl encrypted endpoint should be used\n protobuf (str): Define which protobuf files to use. Cosmos, Evmos and Osmosis are built in and otherwise pass the raw package name (cosmospy-protobuf)\n\n \"\"\"\n\n def __init__(\n self,\n *,\n host: str = \"cosmoshub.strange.love\",\n port: int = 9090,\n ssl: bool = False,\n protobuf=\"cosmos\",\n ):\n\n _protobuf_packages = {\n \"cosmos\": \"cosmospy_protobuf\",\n \"osmosis\": \"osmosis_protobuf\",\n \"evmos\": \"evmos_protobuf\",\n \"sentinel\": \"sentinel_protobuf\",\n }\n _protobuf_package = (_protobuf_packages[protobuf.lower()]\n if protobuf.lower() in _protobuf_packages.keys()\n else protobuf)\n try:\n self._cosmos_tx_service_pb2 = importlib.import_module(\n _protobuf_package +\n \".cosmos.tx.v1beta1.service_pb2\")\n self._cosmos_auth_query_pb2 = importlib.import_module(\n _protobuf_package + \".cosmos.auth.v1beta1.query_pb2\")\n self._cosmos_auth_query_pb2_grpc = importlib.import_module(\n _protobuf_package + \".cosmos.auth.v1beta1.query_pb2_grpc\")\n self._cosmos_tx_service_pb2_grpc = importlib.import_module(\n _protobuf_package + \".cosmos.tx.v1beta1.service_pb2_grpc\")\n\n self._BroadcastTxRequest = self._cosmos_tx_service_pb2.BroadcastTxRequest\n self._SimulateTxRequest = self._cosmos_tx_service_pb2.SimulateRequest\n\n except AttributeError:\n raise ImportError(\n \"It seems that you are importing conflicting protobuf files. Have sou set the protobuf attribute to specify your coin? Check out the documentation for more information.\"\n )\n except:\n raise ImportError(\n f\"Couldn't import from {_protobuf_package}. Is the package installed? \"\n )\n\n self._host = host\n self._port = port\n self._ssl = ssl\n\n def _connect(self):\n if self._ssl:\n con = grpc.secure_channel(\n f\"{self._host}:{self._port}\",\n credentials=grpc.ssl_channel_credentials())\n else:\n con = grpc.insecure_channel(f\"{self._host}:{self._port}\")\n return con\n\n def load_account_data(self, account: Account):\n\"\"\"\n Load the ``next_sequence`` and ``account_number`` into the account object.\n\n Args:\n account (Account): Account\n \"\"\"\n con = self._connect()\n address = account.address\n\n query_stub = self._cosmos_auth_query_pb2_grpc.QueryStub(con)\n account_request = self._cosmos_auth_query_pb2.QueryAccountRequest(address=address)\n\n req = query_stub.Account(account_request)\n data = dict(MessageToDict(req.account))\n\n sequence = 0 if not \"sequence\" in data else int(data[\"sequence\"])\n account_number = int(data[\"accountNumber\"])\n\n account.next_sequence = sequence\n account.account_number = account_number\n con.close()\n\n def broadcast_transaction(self,\n *,\n transaction: Transaction,\n timeout: int = 10) -> [str, int, str]:\n\"\"\"\n Sign and broadcast a transaction.\n\n Note:\n Takes only positional arguments\n\n Args:\n transaction (Transaction): The transaction object\n\n Returns:\n hash: Transaction hash\n code: Result code\n log: Log (None if transaction successful)\n \"\"\"\n con = self._connect()\n tx_bytes = transaction.get_tx_bytes()\n\n tx_request = self._BroadcastTxRequest(\n tx_bytes=tx_bytes,\n mode=2 # BROADCAST_MODE_SYNC\n )\n\n tx_stub = self._cosmos_tx_service_pb2_grpc.ServiceStub(con)\n tx_data = tx_stub.BroadcastTx(tx_request)\n\n hash = tx_data.tx_response.txhash\n code = tx_data.tx_response.code\n log = None if code == 0 else tx_data.tx_response.raw_log\n\n return {\"hash\": hash, \"code\": code, \"log\": log}\n\n def get_tx(self, *, tx_hash: str):\n\"\"\"\n Query a transaction by passing the hash\n\n Note:\n Takes only positional arguments.\n\n Args:\n tx_hash (Transaction): The transaction hash\n\n Returns:\n transaction (dict): Transaction dict as returned by the chain\n\n\n \"\"\"\n con = self._connect()\n tx_stub = self._cosmos_tx_service_pb2_grpc.ServiceStub(con)\n try:\n return MessageToDict(tx_stub.GetTx(self._cosmos_tx_service_pb2.GetTxRequest(hash=tx_hash)))\n except grpc.RpcError:\n raise TransactionNotFound(f\"The transaction {tx_hash} couldn't be found on chain.\")\n\n def wait_for_tx(self, *, tx_hash: str, timeout: float = 60, poll_period: float = 10):\n\"\"\"\n Waits for a transaction hash to hit the chain.\n\n Note:\n Takes only positional arguments\n\n Args:\n tx_hash (Transaction): The transaction hash\n timeout (bool): Time to wait before throwing a TransactionTimeout. Defaults to 60\n poll_period (float): Time to wait between each check. Defaults to 10\n\n Returns:\n transaction (dict): Transaction dict as returned by the chain\n \"\"\"\n start = time.time()\n while time.time() < (start + timeout):\n try:\n return self.get_tx(tx_hash=tx_hash)\n except TransactionNotFound:\n time.sleep(poll_period)\n\n raise TransactionTimeout(f\"The transaction {tx_hash} couldn't be found on chain within {timeout} seconds.\")\n def estimate_gas(self,\n *,\n transaction: Transaction,\n update: bool = True,\n multiplier: float = 1.2\n ) ->int:\n\"\"\"\n Simulate a transaction to get the estimated gas usage.\n\n Note:\n Takes only positional arguments\n\n Args:\n transaction (Transaction): The transaction object\n update (bool): Update the transaction with the estimated gas amount\n multiplier (float): Multiplier for the estimated gas when updating the transaction. Defaults to 1.2\n\n Returns:\n expedted_gas: Expected gas\n \"\"\"\n con = self._connect()\n tx_bytes = transaction.get_tx_bytes()\n\n simulate_request = self._SimulateTxRequest(\n tx_bytes=tx_bytes,\n )\n\n tx_stub = self._cosmos_tx_service_pb2_grpc.ServiceStub(con)\n tx_data = tx_stub.Simulate(simulate_request)\n\n gas_used = tx_data.gas_info.gas_used\n\n if update:\n transaction.set_gas(int(gas_used * multiplier))\n\n return gas_used\n "},{"location":"clients/grpcclient/#mospy.clients.GRPCClient.GRPCClient.broadcast_transaction","title":"broadcast_transaction(*, transaction, timeout=10) ","text":"Sign and broadcast a transaction. Note Takes only positional arguments Parameters: Name Type Description Default transaction Transaction The transaction object required Returns: Name Type Description hash [str, int, str] Transaction hash code [str, int, str] Result code log [str, int, str] Log (None if transaction successful) Source code in mospy/clients/GRPCClient.py def broadcast_transaction(self,\n *,\n transaction: Transaction,\n timeout: int = 10) -> [str, int, str]:\n\"\"\"\n Sign and broadcast a transaction.\n\n Note:\n Takes only positional arguments\n\n Args:\n transaction (Transaction): The transaction object\n\n Returns:\n hash: Transaction hash\n code: Result code\n log: Log (None if transaction successful)\n \"\"\"\n con = self._connect()\n tx_bytes = transaction.get_tx_bytes()\n\n tx_request = self._BroadcastTxRequest(\n tx_bytes=tx_bytes,\n mode=2 # BROADCAST_MODE_SYNC\n )\n\n tx_stub = self._cosmos_tx_service_pb2_grpc.ServiceStub(con)\n tx_data = tx_stub.BroadcastTx(tx_request)\n\n hash = tx_data.tx_response.txhash\n code = tx_data.tx_response.code\n log = None if code == 0 else tx_data.tx_response.raw_log\n\n return {\"hash\": hash, \"code\": code, \"log\": log}\n "},{"location":"clients/grpcclient/#mospy.clients.GRPCClient.GRPCClient.estimate_gas","title":"estimate_gas(*, transaction, update=True, multiplier=1.2) ","text":"Simulate a transaction to get the estimated gas usage. Note Takes only positional arguments Parameters: Name Type Description Default transaction Transaction The transaction object required update bool Update the transaction with the estimated gas amount True multiplier float Multiplier for the estimated gas when updating the transaction. Defaults to 1.2 1.2 Returns: Name Type Description expedted_gas int Expected gas Source code in mospy/clients/GRPCClient.py def estimate_gas(self,\n *,\n transaction: Transaction,\n update: bool = True,\n multiplier: float = 1.2\n ) ->int:\n\"\"\"\n Simulate a transaction to get the estimated gas usage.\n\n Note:\n Takes only positional arguments\n\n Args:\n transaction (Transaction): The transaction object\n update (bool): Update the transaction with the estimated gas amount\n multiplier (float): Multiplier for the estimated gas when updating the transaction. Defaults to 1.2\n\n Returns:\n expedted_gas: Expected gas\n \"\"\"\n con = self._connect()\n tx_bytes = transaction.get_tx_bytes()\n\n simulate_request = self._SimulateTxRequest(\n tx_bytes=tx_bytes,\n )\n\n tx_stub = self._cosmos_tx_service_pb2_grpc.ServiceStub(con)\n tx_data = tx_stub.Simulate(simulate_request)\n\n gas_used = tx_data.gas_info.gas_used\n\n if update:\n transaction.set_gas(int(gas_used * multiplier))\n\n return gas_used\n "},{"location":"clients/grpcclient/#mospy.clients.GRPCClient.GRPCClient.get_tx","title":"get_tx(*, tx_hash) ","text":"Query a transaction by passing the hash Note Takes only positional arguments. Parameters: Name Type Description Default tx_hash Transaction The transaction hash required Returns: Name Type Description transaction dict Transaction dict as returned by the chain Source code in mospy/clients/GRPCClient.py def get_tx(self, *, tx_hash: str):\n\"\"\"\n Query a transaction by passing the hash\n\n Note:\n Takes only positional arguments.\n\n Args:\n tx_hash (Transaction): The transaction hash\n\n Returns:\n transaction (dict): Transaction dict as returned by the chain\n\n\n \"\"\"\n con = self._connect()\n tx_stub = self._cosmos_tx_service_pb2_grpc.ServiceStub(con)\n try:\n return MessageToDict(tx_stub.GetTx(self._cosmos_tx_service_pb2.GetTxRequest(hash=tx_hash)))\n except grpc.RpcError:\n raise TransactionNotFound(f\"The transaction {tx_hash} couldn't be found on chain.\")\n "},{"location":"clients/grpcclient/#mospy.clients.GRPCClient.GRPCClient.load_account_data","title":"load_account_data(account) ","text":"Load the next_sequence and account_number into the account object. Parameters: Name Type Description Default account Account Account required Source code in mospy/clients/GRPCClient.py def load_account_data(self, account: Account):\n\"\"\"\n Load the ``next_sequence`` and ``account_number`` into the account object.\n\n Args:\n account (Account): Account\n \"\"\"\n con = self._connect()\n address = account.address\n\n query_stub = self._cosmos_auth_query_pb2_grpc.QueryStub(con)\n account_request = self._cosmos_auth_query_pb2.QueryAccountRequest(address=address)\n\n req = query_stub.Account(account_request)\n data = dict(MessageToDict(req.account))\n\n sequence = 0 if not \"sequence\" in data else int(data[\"sequence\"])\n account_number = int(data[\"accountNumber\"])\n\n account.next_sequence = sequence\n account.account_number = account_number\n con.close()\n "},{"location":"clients/grpcclient/#mospy.clients.GRPCClient.GRPCClient.wait_for_tx","title":"wait_for_tx(*, tx_hash, timeout=60, poll_period=10) ","text":"Waits for a transaction hash to hit the chain. Note Takes only positional arguments Parameters: Name Type Description Default tx_hash Transaction The transaction hash required timeout bool Time to wait before throwing a TransactionTimeout. Defaults to 60 60 poll_period float Time to wait between each check. Defaults to 10 10 Returns: Name Type Description transaction dict Transaction dict as returned by the chain Source code in mospy/clients/GRPCClient.py def wait_for_tx(self, *, tx_hash: str, timeout: float = 60, poll_period: float = 10):\n\"\"\"\n Waits for a transaction hash to hit the chain.\n\n Note:\n Takes only positional arguments\n\n Args:\n tx_hash (Transaction): The transaction hash\n timeout (bool): Time to wait before throwing a TransactionTimeout. Defaults to 60\n poll_period (float): Time to wait between each check. Defaults to 10\n\n Returns:\n transaction (dict): Transaction dict as returned by the chain\n \"\"\"\n start = time.time()\n while time.time() < (start + timeout):\n try:\n return self.get_tx(tx_hash=tx_hash)\n except TransactionNotFound:\n time.sleep(poll_period)\n\n raise TransactionTimeout(f\"The transaction {tx_hash} couldn't be found on chain within {timeout} seconds.\")\n "},{"location":"clients/httpclient/","title":"HTTPClient","text":"Wrapper class to interact with a cosmos chain through their API endpoint Parameters: Name Type Description Default api str URL to a Api node 'https://rest.cosmos.directory/cosmoshub' Source code in mospy/clients/HTTPClient.py class HTTPClient:\n\"\"\"\n Wrapper class to interact with a cosmos chain through their API endpoint\n\n Args:\n api (str): URL to a Api node\n \"\"\"\n\n def __init__(self, *, api: str = \"https://rest.cosmos.directory/cosmoshub\"):\n self._api = api\n\n def _make_post_request(self, path, payload, timeout):\n try:\n req = httpx.post(self._api + path, json=payload, timeout=timeout)\n except httpx.TimeoutException:\n raise NodeTimeoutException(f\"Node {self._api} timed out after {timeout} seconds\")\n\n if req.status_code != 200:\n try:\n data = req.json()\n message = f\"({data['message']}\"\n except:\n message = \"\"\n raise NodeException(f\"Error while doing request to api endpoint {message}\")\n\n data = req.json()\n return data\n\n def _make_get_request(self, path, timeout):\n try:\n req = httpx.get(self._api + path, timeout=timeout)\n except httpx.TimeoutException:\n raise NodeTimeoutException(f\"Node {self._api} timed out after {timeout} seconds\")\n if req.status_code != 200:\n try:\n data = req.json()\n message = f\"({data['message']}\"\n except:\n message = \"\"\n raise NodeException(f\"Error while doing request to api endpoint {message}\")\n\n data = req.json()\n return data\n\n\n def load_account_data(self, account: Account):\n\"\"\"\n Load the ``next_sequence`` and ``account_number`` into the account object.\n\n Args:\n account (Account): Account\n \"\"\"\n\n address = account.address\n url = self._api + \"/cosmos/auth/v1beta1/accounts/\" + address\n req = httpx.get(url=url)\n if req.status_code != 200:\n raise NodeException(\"Error while doing request to api endpoint\")\n\n data = req.json()\n sequence = int(data[\"account\"][\"sequence\"])\n account_number = int(data[\"account\"][\"account_number\"])\n\n account.next_sequence = sequence\n account.account_number = account_number\n\n def broadcast_transaction(self,\n *,\n transaction: Transaction,\n timeout: int = 10) -> [str, int, str]:\n\"\"\"\n Sign and broadcast a transaction.\n\n Note:\n Takes only positional arguments\n\n Args:\n transaction (Transaction): The transaction object\n timeout (int): Timeout\n\n Returns:\n hash: Transaction hash\n code: Result code\n log: Log (None if transaction successful)\n \"\"\"\n path = \"/cosmos/tx/v1beta1/txs\"\n tx_bytes = transaction.get_tx_bytes_as_string()\n payload = {\"tx_bytes\": tx_bytes, \"mode\": \"BROADCAST_MODE_SYNC\"}\n\n data = self._make_post_request(path, payload, timeout)\n\n hash = data[\"tx_response\"][\"txhash\"]\n code = data[\"tx_response\"][\"code\"]\n log = None if code == 0 else data[\"tx_response\"][\"raw_log\"]\n\n return {\"hash\": hash, \"code\": code, \"log\": log}\n\n def estimate_gas(self,\n *,\n transaction: Transaction,\n update: bool = True,\n multiplier: float = 1.2,\n timeout: int = 10) ->int:\n\"\"\"\n Simulate a transaction to get the estimated gas usage.\n\n Note:\n Takes only positional arguments\n\n Args:\n transaction (Transaction): The transaction object\n update (bool): Update the transaction with the estimated gas amount\n multiplier (float): Multiplier for the estimated gas when updating the transaction. Defaults to 1.2\n timeout (int): Timeout\n\n Returns:\n expedted_gas: Expected gas\n \"\"\"\n path = \"/cosmos/tx/v1beta1/simulate\"\n tx_bytes = transaction.get_tx_bytes_as_string()\n payload = {\"tx_bytes\": tx_bytes}\n\n data = self._make_post_request(path, payload, timeout)\n\n gas_used = int(data[\"gas_info\"][\"gas_used\"])\n\n if update:\n transaction.set_gas(int(gas_used * multiplier))\n\n return gas_used\n\n def get_tx(self, *, tx_hash: str, timeout: int = 5):\n\"\"\"\n Query a transaction by passing the hash\n\n Note:\n Takes only positional arguments.\n\n Args:\n tx_hash (Transaction): The transaction hash\n timeout (int): Timeout for the request before throwing a NodeException\n\n Returns:\n transaction (dict): Transaction dict as returned by the chain\n\n\n \"\"\"\n path = \"/cosmos/tx/v1beta1/txs/\" + tx_hash\n\n try:\n data = self._make_get_request(path=path, timeout=timeout)\n except NodeException:\n raise TransactionNotFound(f\"The transaction {tx_hash} couldn't be found\")\n\n return data\n\n\n def wait_for_tx(self, *, tx_hash: str, timeout: float = 60, poll_period: float = 10):\n\"\"\"\n Waits for a transaction hash to hit the chain.\n\n Note:\n Takes only positional arguments\n\n Args:\n tx_hash (Transaction): The transaction hash\n timeout (bool): Time to wait before throwing a TransactionTimeout. Defaults to 60\n poll_period (float): Time to wait between each check. Defaults to 10\n\n Returns:\n transaction (dict): Transaction dict as returned by the chain\n \"\"\"\n start = time.time()\n while time.time() < (start + timeout):\n try:\n return self.get_tx(tx_hash=tx_hash)\n except TransactionNotFound:\n time.sleep(poll_period)\n\n raise TransactionTimeout(f\"The transaction {tx_hash} couldn't be found on chain within {timeout} seconds.\")\n "},{"location":"clients/httpclient/#mospy.clients.HTTPClient.HTTPClient.broadcast_transaction","title":"broadcast_transaction(*, transaction, timeout=10) ","text":"Sign and broadcast a transaction. Note Takes only positional arguments Parameters: Name Type Description Default transaction Transaction The transaction object required timeout int Timeout 10 Returns: Name Type Description hash [str, int, str] Transaction hash code [str, int, str] Result code log [str, int, str] Log (None if transaction successful) Source code in mospy/clients/HTTPClient.py def broadcast_transaction(self,\n *,\n transaction: Transaction,\n timeout: int = 10) -> [str, int, str]:\n\"\"\"\n Sign and broadcast a transaction.\n\n Note:\n Takes only positional arguments\n\n Args:\n transaction (Transaction): The transaction object\n timeout (int): Timeout\n\n Returns:\n hash: Transaction hash\n code: Result code\n log: Log (None if transaction successful)\n \"\"\"\n path = \"/cosmos/tx/v1beta1/txs\"\n tx_bytes = transaction.get_tx_bytes_as_string()\n payload = {\"tx_bytes\": tx_bytes, \"mode\": \"BROADCAST_MODE_SYNC\"}\n\n data = self._make_post_request(path, payload, timeout)\n\n hash = data[\"tx_response\"][\"txhash\"]\n code = data[\"tx_response\"][\"code\"]\n log = None if code == 0 else data[\"tx_response\"][\"raw_log\"]\n\n return {\"hash\": hash, \"code\": code, \"log\": log}\n "},{"location":"clients/httpclient/#mospy.clients.HTTPClient.HTTPClient.estimate_gas","title":"estimate_gas(*, transaction, update=True, multiplier=1.2, timeout=10) ","text":"Simulate a transaction to get the estimated gas usage. Note Takes only positional arguments Parameters: Name Type Description Default transaction Transaction The transaction object required update bool Update the transaction with the estimated gas amount True multiplier float Multiplier for the estimated gas when updating the transaction. Defaults to 1.2 1.2 timeout int Timeout 10 Returns: Name Type Description expedted_gas int Expected gas Source code in mospy/clients/HTTPClient.py def estimate_gas(self,\n *,\n transaction: Transaction,\n update: bool = True,\n multiplier: float = 1.2,\n timeout: int = 10) ->int:\n\"\"\"\n Simulate a transaction to get the estimated gas usage.\n\n Note:\n Takes only positional arguments\n\n Args:\n transaction (Transaction): The transaction object\n update (bool): Update the transaction with the estimated gas amount\n multiplier (float): Multiplier for the estimated gas when updating the transaction. Defaults to 1.2\n timeout (int): Timeout\n\n Returns:\n expedted_gas: Expected gas\n \"\"\"\n path = \"/cosmos/tx/v1beta1/simulate\"\n tx_bytes = transaction.get_tx_bytes_as_string()\n payload = {\"tx_bytes\": tx_bytes}\n\n data = self._make_post_request(path, payload, timeout)\n\n gas_used = int(data[\"gas_info\"][\"gas_used\"])\n\n if update:\n transaction.set_gas(int(gas_used * multiplier))\n\n return gas_used\n "},{"location":"clients/httpclient/#mospy.clients.HTTPClient.HTTPClient.get_tx","title":"get_tx(*, tx_hash, timeout=5) ","text":"Query a transaction by passing the hash Note Takes only positional arguments. Parameters: Name Type Description Default tx_hash Transaction The transaction hash required timeout int Timeout for the request before throwing a NodeException 5 Returns: Name Type Description transaction dict Transaction dict as returned by the chain Source code in mospy/clients/HTTPClient.py def get_tx(self, *, tx_hash: str, timeout: int = 5):\n\"\"\"\n Query a transaction by passing the hash\n\n Note:\n Takes only positional arguments.\n\n Args:\n tx_hash (Transaction): The transaction hash\n timeout (int): Timeout for the request before throwing a NodeException\n\n Returns:\n transaction (dict): Transaction dict as returned by the chain\n\n\n \"\"\"\n path = \"/cosmos/tx/v1beta1/txs/\" + tx_hash\n\n try:\n data = self._make_get_request(path=path, timeout=timeout)\n except NodeException:\n raise TransactionNotFound(f\"The transaction {tx_hash} couldn't be found\")\n\n return data\n "},{"location":"clients/httpclient/#mospy.clients.HTTPClient.HTTPClient.load_account_data","title":"load_account_data(account) ","text":"Load the next_sequence and account_number into the account object. Parameters: Name Type Description Default account Account Account required Source code in mospy/clients/HTTPClient.py def load_account_data(self, account: Account):\n\"\"\"\n Load the ``next_sequence`` and ``account_number`` into the account object.\n\n Args:\n account (Account): Account\n \"\"\"\n\n address = account.address\n url = self._api + \"/cosmos/auth/v1beta1/accounts/\" + address\n req = httpx.get(url=url)\n if req.status_code != 200:\n raise NodeException(\"Error while doing request to api endpoint\")\n\n data = req.json()\n sequence = int(data[\"account\"][\"sequence\"])\n account_number = int(data[\"account\"][\"account_number\"])\n\n account.next_sequence = sequence\n account.account_number = account_number\n "},{"location":"clients/httpclient/#mospy.clients.HTTPClient.HTTPClient.wait_for_tx","title":"wait_for_tx(*, tx_hash, timeout=60, poll_period=10) ","text":"Waits for a transaction hash to hit the chain. Note Takes only positional arguments Parameters: Name Type Description Default tx_hash Transaction The transaction hash required timeout bool Time to wait before throwing a TransactionTimeout. Defaults to 60 60 poll_period float Time to wait between each check. Defaults to 10 10 Returns: Name Type Description transaction dict Transaction dict as returned by the chain Source code in mospy/clients/HTTPClient.py def wait_for_tx(self, *, tx_hash: str, timeout: float = 60, poll_period: float = 10):\n\"\"\"\n Waits for a transaction hash to hit the chain.\n\n Note:\n Takes only positional arguments\n\n Args:\n tx_hash (Transaction): The transaction hash\n timeout (bool): Time to wait before throwing a TransactionTimeout. Defaults to 60\n poll_period (float): Time to wait between each check. Defaults to 10\n\n Returns:\n transaction (dict): Transaction dict as returned by the chain\n \"\"\"\n start = time.time()\n while time.time() < (start + timeout):\n try:\n return self.get_tx(tx_hash=tx_hash)\n except TransactionNotFound:\n time.sleep(poll_period)\n\n raise TransactionTimeout(f\"The transaction {tx_hash} couldn't be found on chain within {timeout} seconds.\")\n "},{"location":"transaction/types/","title":"Transaction Types","text":"Nearly every cosmos chain has its transaction types usually on top of the standard cosmos ones. Mospy supports some standard transaction types that should be the same on every chain. However, every chain can modify these and you would then need to implement that change by yourself. But this will be explained here. "},{"location":"transaction/types/#data-structures","title":"Data structures","text":"In general, the cosmos sdk uses the protobuf data format to define data structures. These protobuf files serve as documentation and help to serialize the data directly in your code. To make protobufs more accessible for python I am maintaining the cosmospy-protobuf library which contains all cosmos protobuf files compiled for python. Mospy is using cosmospy-protobuf. The naming scheme is following the official cosmos naming scheme. This is especially useful when working with different transaction types. "},{"location":"transaction/types/#included-transaction-types","title":"Included transaction types","text":"Mospy ships some standard transaction types for easier implementation. Currently, following transaction types are supported: * MsgSend * MsgDelegate * MsgUndelegate * MsgWithdrawDelegatorReward Each transaction type takes different keyword arguments. You can check out the examples to see how to use each type. The following example will use the MsgSend type as it is the most common one: from mospy import Transaction, Account\n\naccount = Account(...)\ntx = Transaction(...)\n\ntx.add_msg(\n tx_type='transfer',\n sender=account,\n receipient=\"cosmos1tkv9rquxr88r7snrg42kxdj9gsnfxxg028kuh9\",\n amount=1000,\n denom=\"uatom\"\n)\n\n# Sign and broadcast\n The first argument always defines the transaction type. The following required arguments are then defined by each adapter. You have to use keyword arguments. "},{"location":"transaction/types/#custom-transaction-types","title":"Custom transaction types","text":"Transaction types that aren't integrated can be added to the transaction class through the add_raw_msg method. This function takes two arguments. The method takes two arguments. The first one is the msg data in the protobuf format and the second one is the type url. For instance, if you want to make a transaction that changes the reward withdraw address you will need to implement the transaction with the type /cosmos.distribution.v1beta1.MsgSetWithdrawAddress . The compiled protobuf files are available at cosmospy_protobuf.cosmos.distribution.v1beta1.tx_pb2 . To see what data you need to pass you can check out the according protobuf file in the cosmospy-protobuf repository: https://github.com/ctrl-Felix/cosmospy-protobuf/blob/main/src/cosmospy_protobuf/cosmos/distribution/v1beta1/tx.proto#L31 The full example will look like this: from mospy import Transaction\nfrom cosmospy_protobuf.cosmos.distribution.v1beta1.tx_pb2 import MsgSetWithdrawAddress\n\ntx = Transaction(...)\n\nwmsg = MsgSetWithdrawAddress(\n delegator_address=\"cosmos1...\",\n withdraw_address=\"cosmos1...\"\n\n)\ntx.add_raw_msg(wmsg, type_url=\"/cosmos.distribution.v1beta1.MsgSetWithdrawAddress\")\n\n# Sign and broadcast\n\n You see! It's not complicated at all. "},{"location":"transaction/types/#transaction-body","title":"Transaction body","text":"A transaction can have many messages with different transaction types. You can save a lot of fees by aggregating your messages into one big transaction. But keep in mind. If one message fails the whole transaction and all messages fail. "}]}
\ No newline at end of file
diff --git a/sitemap.xml b/sitemap.xml
index 82c604e..3fc1c61 100644
--- a/sitemap.xml
+++ b/sitemap.xml
@@ -2,42 +2,42 @@
None
- 2023-06-11
+ 2024-02-13
daily
None
- 2023-06-11
+ 2024-02-13
daily
None
- 2023-06-11
+ 2024-02-13
daily
None
- 2023-06-11
+ 2024-02-13
daily
None
- 2023-06-11
+ 2024-02-13
daily
None
- 2023-06-11
+ 2024-02-13
daily
None
- 2023-06-11
+ 2024-02-13
daily
None
- 2023-06-11
+ 2024-02-13
daily
\ No newline at end of file
diff --git a/sitemap.xml.gz b/sitemap.xml.gz
index e5fcf2a..6a4495b 100644
Binary files a/sitemap.xml.gz and b/sitemap.xml.gz differ
diff --git a/transaction/index.html b/transaction/index.html
index a3c448c..3c1a0a3 100644
--- a/transaction/index.html
+++ b/transaction/index.html
@@ -802,9 +802,7 @@ Transaction
180
181
182
-183
-184
-185 | | class Transaction:
"""Class to create and sign a transaction
Args:
account (Account): Account object to sign this transaction
@@ -833,6 +831,7 @@ Transaction
"cosmos": "cosmospy_protobuf",
"osmosis": "osmosis_protobuf",
"evmos": "evmos_protobuf",
+ "sentinel": "sentinel_protobuf",
}
self._protobuf_package = (_protobuf_packages[protobuf.lower()]
if protobuf.lower()
@@ -965,10 +964,7 @@ Transaction
signer_infos = self.tx_pb2.SignerInfo()
signer_infos.sequence = self._account.next_sequence
signer_infos.public_key.Pack(self._account.public_key)
- if self._account.eth:
- signer_infos.public_key.type_url = "/ethermint.crypto.v1.ethsecp256k1.PubKey"
- else:
- signer_infos.public_key.type_url = "/cosmos.crypto.secp256k1.PubKey"
+ signer_infos.public_key.type_url = self._account.public_key_type
signer_infos.mode_info.single.mode = 1
return signer_infos
|