diff --git a/account/index.html b/account/index.html index 07fda51..4bad013 100644 --- a/account/index.html +++ b/account/index.html @@ -302,6 +302,13 @@ public_key + + +
  • + + public_key_type + +
  • @@ -594,6 +601,13 @@ public_key +
  • + +
  • + + public_key_type + +
  • @@ -1048,7 +1062,19 @@

    Account

    296 297 298 -299
    class Account:
    +299
    +300
    +301
    +302
    +303
    +304
    +305
    +306
    +307
    +308
    +309
    +310
    +311
    class Account:
         """
         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
     
    @@ -1086,12 +1112,14 @@ 

    Account

    hrp: str = "cosmos", address_index: int = 0, protobuf: str = "cosmos", - eth: bool = False + eth: bool = False, + public_key_type: str = None ): _protobuf_packages = { "cosmos": "cosmospy_protobuf", "osmosis": "osmosis_protobuf", "evmos": "evmos_protobuf", + "sentinel": "sentinel_protobuf", } _protobuf_package = (_protobuf_packages[protobuf.lower()] if protobuf.lower() in _protobuf_packages.keys() @@ -1117,6 +1145,20 @@

    Account

    self._next_sequence = next_sequence self._account_number = account_number + # Set the public key type + if public_key_type: + self._public_key_type = public_key_type + else: + if eth: + # Add Injectiver as exception as they use ethermint but with their own definition + # Otherwise default to ethermint + if hrp == "inj": + self._public_key_type = "/injective.crypto.v1beta1.ethsecp256k1.PubKey" + else: + self._public_key_type = "/ethermint.crypto.v1.ethsecp256k1.PubKey" + else: + self._public_key_type = "/cosmos.crypto.secp256k1.PubKey" + if not seed_phrase and not private_key: self._seed_phrase = Mnemonic(language="english").generate( strength=256) @@ -1226,8 +1268,6 @@

    Account

    """ On-chain account number which will be assigned when the address receives coins for the first time. - Args: - account_number (int): Account Number Returns: Account number """ @@ -1242,9 +1282,6 @@

    Account

    """ Sequence which will be used for transactions signed with this Account. - Args: - next_sequence (int): Next sequence (only when used as setter) - Returns: Next Sequence """ @@ -1268,8 +1305,6 @@

    Account

    """ Change the address index to use a sub account. This works only if a seed has been used to instantiate the Account. - Args: - address_index (int): New address index Returns: Address Index @@ -1290,10 +1325,6 @@

    Account

    """ Current address prefix used by the Account. - Args: - hrp (str): New address prefix - - Returns: Address Prefix (hrp) """ @@ -1305,12 +1336,9 @@

    Account

    @property def slip44(self) -> int: - """" + """ Set the Slip44 value. Cosmos defaults to 118 - Args: - slip44 (int): New slip44 value as defined in the [slip44 registry](https://github.com/satoshilabs/slips/blob/master/slip-0044.md) - Returns: Slip44 @@ -1326,9 +1354,6 @@

    Account

    """ Change the eth compatibility mode. If you want to use Evmos you will need to set eth to true. Otherwise it defaults to False - Args: - eth (bool): ETH compatibility mode - Returns: eth """ @@ -1338,6 +1363,19 @@

    Account

    def eth(self, eth: bool): self._eth = eth + + @property + def public_key_type(self): + """ + Get the current pyblic key type + + Returns: + public_key_type + """ + return self._public_key_type + @public_key_type.setter + def public_key_type(self, public_key_type): + self._public_key_type = public_key_type
    @@ -1370,30 +1408,6 @@

    On-chain account number which will be assigned when the address receives coins for the first time.

    -

    Parameters:

    - - - - - - - - - - - - - - - - - -
    NameTypeDescriptionDefault
    account_number - int -

    Account Number

    - required -
    -

    Returns:

    @@ -1473,30 +1487,6 @@

    Change the address index to use a sub account. This works only if a seed has been used to instantiate the Account.

    -

    Parameters:

    -

    - - - - - - - - - - - - - - - - -
    NameTypeDescriptionDefault
    address_index - int -

    New address index

    - required -
    -

    Returns:

    @@ -1536,30 +1526,6 @@

    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:

    -

    - - - - - - - - - - - - - - - - -
    NameTypeDescriptionDefault
    eth - bool -

    ETH compatibility mode

    - required -
    -

    Returns:

    @@ -1639,30 +1605,6 @@

    Current address prefix used by the Account.

    -

    Parameters:

    -

    - - - - - - - - - - - - - - - - -
    NameTypeDescriptionDefault
    hrp - str -

    New address prefix

    - required -
    -

    Returns:

    @@ -1703,30 +1645,6 @@

    Sequence which will be used for transactions signed with this Account.

    -

    Parameters:

    -

    - - - - - - - - - - - - - - - - -
    NameTypeDescriptionDefault
    next_sequence - int -

    Next sequence (only when used as setter)

    - required -
    -

    Returns:

    @@ -1830,11 +1748,12 @@

    -

    -seed_phrase: str +

    +public_key_type property + writable

    @@ -1842,7 +1761,7 @@

    -

    Current Seed Phrase

    +

    Get the current pyblic key type

    Returns:

    @@ -1855,9 +1774,8 @@

    - +
    - str

    Seed Phrase

    public_key_type

    @@ -1869,12 +1787,11 @@

    -

    -slip44: int +

    +seed_phrase: str property - writable

    @@ -1882,32 +1799,47 @@

    -

    " -Set the Slip44 value. Cosmos defaults to 118

    +

    Current Seed Phrase

    -

    Parameters:

    +

    Returns:

    - - - - - +
    Name Type DescriptionDefault
    slip44 - int -

    New slip44 value as defined in the slip44 registry

    - required + str

    Seed Phrase

    +
    + + + +
    + + + +

    +slip44: int + + + property + writable + + +

    + + +
    + +

    Set the Slip44 value. Cosmos defaults to 118

    Returns:

    @@ -1972,14 +1904,14 @@

    Source code in mospy/Account.py -

    216
    -217
    -218
    -219
    -220
    -221
    -222
    -223
    def increase_sequence(self, change: int = 1) -> None:
    +        
    227
    +228
    +229
    +230
    +231
    +232
    +233
    +234
    def increase_sequence(self, change: int = 1) -> None:
         """
         Increase the sequence by ``change``
     
    diff --git a/clients/grpcclient/index.html b/clients/grpcclient/index.html
    index a95bc46..85b63dd 100644
    --- a/clients/grpcclient/index.html
    +++ b/clients/grpcclient/index.html
    @@ -406,6 +406,13 @@
         estimate_gas()
       
       
    +
    +      
    +        
  • + + get_tx() + +
  • @@ -413,6 +420,13 @@ load_account_data() +
  • + +
  • + + wait_for_tx() + +
  • @@ -490,6 +504,13 @@ estimate_gas() + + +
  • + + get_tx() + +
  • @@ -497,6 +518,13 @@ load_account_data() +
  • + +
  • + + wait_for_tx() + +
  • @@ -583,10 +611,7 @@

    HTTPClient

    Source code in mospy/clients/GRPCClient.py -
     10
    - 11
    - 12
    - 13
    +          
     13
      14
      15
      16
    @@ -741,7 +766,56 @@ 

    HTTPClient

    165 166 167 -168
    class GRPCClient:
    +168
    +169
    +170
    +171
    +172
    +173
    +174
    +175
    +176
    +177
    +178
    +179
    +180
    +181
    +182
    +183
    +184
    +185
    +186
    +187
    +188
    +189
    +190
    +191
    +192
    +193
    +194
    +195
    +196
    +197
    +198
    +199
    +200
    +201
    +202
    +203
    +204
    +205
    +206
    +207
    +208
    +209
    +210
    +211
    +212
    +213
    +214
    +215
    +216
    +217
    class GRPCClient:
         """
         Wrapper class to interact with a cosmos chain through their grpc endpoint
     
    @@ -766,6 +840,7 @@ 

    HTTPClient

    "cosmos": "cosmospy_protobuf", "osmosis": "osmosis_protobuf", "evmos": "evmos_protobuf", + "sentinel": "sentinel_protobuf", } _protobuf_package = (_protobuf_packages[protobuf.lower()] if protobuf.lower() in _protobuf_packages.keys() @@ -864,6 +939,51 @@

    HTTPClient

    return {"hash": hash, "code": code, "log": log} + def get_tx(self, *, tx_hash: str): + """ + Query a transaction by passing the hash + + Note: + Takes only positional arguments. + + Args: + tx_hash (Transaction): The transaction hash + + Returns: + transaction (dict): Transaction dict as returned by the chain + + + """ + con = self._connect() + tx_stub = self._cosmos_tx_service_pb2_grpc.ServiceStub(con) + try: + return MessageToDict(tx_stub.GetTx(self._cosmos_tx_service_pb2.GetTxRequest(hash=tx_hash))) + except grpc.RpcError: + raise TransactionNotFound(f"The transaction {tx_hash} couldn't be found on chain.") + + 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.") def estimate_gas(self, *, transaction: Transaction, @@ -989,11 +1109,7 @@

    Source code in mospy/clients/GRPCClient.py -
     98
    - 99
    -100
    -101
    -102
    +        
    102
     103
     104
     105
    @@ -1022,7 +1138,11 @@ 

    128 129 130 -131

    def broadcast_transaction(self,
    +131
    +132
    +133
    +134
    +135
    def broadcast_transaction(self,
                               *,
                               transaction: Transaction,
                               timeout: int = 10) -> [str, int, str]:
    @@ -1144,42 +1264,42 @@ 

    Source code in mospy/clients/GRPCClient.py -
    133
    -134
    -135
    -136
    -137
    -138
    -139
    -140
    -141
    -142
    -143
    -144
    -145
    -146
    -147
    -148
    -149
    -150
    -151
    -152
    -153
    -154
    -155
    -156
    -157
    -158
    -159
    -160
    -161
    -162
    -163
    -164
    -165
    -166
    -167
    -168
    def estimate_gas(self,
    +        
    182
    +183
    +184
    +185
    +186
    +187
    +188
    +189
    +190
    +191
    +192
    +193
    +194
    +195
    +196
    +197
    +198
    +199
    +200
    +201
    +202
    +203
    +204
    +205
    +206
    +207
    +208
    +209
    +210
    +211
    +212
    +213
    +214
    +215
    +216
    +217
    def estimate_gas(self,
                               *,
                               transaction: Transaction,
                               update: bool = True,
    @@ -1225,6 +1345,115 @@ 

    +get_tx(*, tx_hash) + +

    + + +
    + +

    Query a transaction by passing the hash

    + +
    + Note +

    Takes only positional arguments.

    +
    +

    Parameters:

    + + + + + + + + + + + + + + + + + +
    NameTypeDescriptionDefault
    tx_hash + Transaction +

    The transaction hash

    + required +
    + +

    Returns:

    + + + + + + + + + + + + + +
    Name TypeDescription
    transaction + dict +

    Transaction dict as returned by the chain

    + +
    + Source code in mospy/clients/GRPCClient.py +
    137
    +138
    +139
    +140
    +141
    +142
    +143
    +144
    +145
    +146
    +147
    +148
    +149
    +150
    +151
    +152
    +153
    +154
    +155
    +156
    +157
    def get_tx(self, *, tx_hash: str):
    +    """
    +    Query a transaction by passing the hash
    +
    +    Note:
    +        Takes only positional arguments.
    +
    +    Args:
    +        tx_hash (Transaction): The transaction hash
    +
    +    Returns:
    +        transaction (dict): Transaction dict as returned by the chain
    +
    +
    +    """
    +    con = self._connect()
    +    tx_stub = self._cosmos_tx_service_pb2_grpc.ServiceStub(con)
    +    try:
    +        return MessageToDict(tx_stub.GetTx(self._cosmos_tx_service_pb2.GetTxRequest(hash=tx_hash)))
    +    except grpc.RpcError:
    +        raise TransactionNotFound(f"The transaction {tx_hash} couldn't be found on chain.")
    +
    +
    +
    + +
    + +
    + + +

    load_account_data(account) @@ -1261,28 +1490,28 @@

    Source code in mospy/clients/GRPCClient.py -
    75
    -76
    -77
    -78
    -79
    -80
    -81
    -82
    -83
    -84
    -85
    -86
    -87
    -88
    -89
    -90
    -91
    -92
    -93
    -94
    -95
    -96
    def load_account_data(self, account: Account):
    +        
    @@ -553,9 +581,7 @@

    HTTPClient

    Source code in mospy/clients/HTTPClient.py -
     79
    + 80
    + 81
    + 82
    + 83
    + 84
    + 85
    + 86
    + 87
    + 88
    + 89
    + 90
    + 91
    + 92
    + 93
    + 94
    + 95
    + 96
    + 97
    + 98
    + 99
    +100
    def load_account_data(self, account: Account):
         """
         Load the ``next_sequence`` and ``account_number`` into the account object.
     
    @@ -1310,6 +1539,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:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescriptionDefault
    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 TypeDescription
    transaction + dict +

    Transaction dict as returned by the chain

    + +
    + Source code in mospy/clients/GRPCClient.py +
    159
    +160
    +161
    +162
    +163
    +164
    +165
    +166
    +167
    +168
    +169
    +170
    +171
    +172
    +173
    +174
    +175
    +176
    +177
    +178
    +179
    +180
    +181
    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/clients/httpclient/index.html b/clients/httpclient/index.html index d98190e..2a8b0ec 100644 --- a/clients/httpclient/index.html +++ b/clients/httpclient/index.html @@ -392,6 +392,13 @@ estimate_gas() + + +
  • + + get_tx() + +
  • @@ -399,6 +406,13 @@ load_account_data() +
  • + +
  • + + wait_for_tx() + +
  • @@ -490,6 +504,13 @@ estimate_gas() + + +
  • + + get_tx() + +
  • @@ -497,6 +518,13 @@ load_account_data() +
  • + +
  • + + wait_for_tx() + +
  • @@ -544,7 +572,7 @@

    HTTPClient

    URL to a Api node

    - 'https://api.cosmos.interbloc.org' + 'https://rest.cosmos.directory/cosmoshub'
     10
    - 11
    - 12
    +          
     12
      13
      14
      15
    @@ -662,7 +688,79 @@ 

    HTTPClient

    116 117 118 -119
    class HTTPClient:
    +119
    +120
    +121
    +122
    +123
    +124
    +125
    +126
    +127
    +128
    +129
    +130
    +131
    +132
    +133
    +134
    +135
    +136
    +137
    +138
    +139
    +140
    +141
    +142
    +143
    +144
    +145
    +146
    +147
    +148
    +149
    +150
    +151
    +152
    +153
    +154
    +155
    +156
    +157
    +158
    +159
    +160
    +161
    +162
    +163
    +164
    +165
    +166
    +167
    +168
    +169
    +170
    +171
    +172
    +173
    +174
    +175
    +176
    +177
    +178
    +179
    +180
    +181
    +182
    +183
    +184
    +185
    +186
    +187
    +188
    +189
    +190
    +191
    class HTTPClient:
         """
         Wrapper class to interact with a cosmos chain through their API endpoint
     
    @@ -670,11 +768,14 @@ 

    HTTPClient

    api (str): URL to a Api node """ - def __init__(self, *, api: str = "https://api.cosmos.interbloc.org"): + def __init__(self, *, api: str = "https://rest.cosmos.directory/cosmoshub"): self._api = api def _make_post_request(self, path, payload, timeout): - req = httpx.post(self._api + path, json=payload, timeout=timeout) + try: + req = httpx.post(self._api + path, json=payload, timeout=timeout) + except httpx.TimeoutException: + raise NodeTimeoutException(f"Node {self._api} timed out after {timeout} seconds") if req.status_code != 200: try: @@ -687,6 +788,23 @@

    HTTPClient

    data = req.json() return data + def _make_get_request(self, path, timeout): + try: + req = httpx.get(self._api + path, timeout=timeout) + except httpx.TimeoutException: + raise NodeTimeoutException(f"Node {self._api} timed out after {timeout} seconds") + if req.status_code != 200: + try: + data = req.json() + message = f"({data['message']}" + except: + message = "" + raise NodeException(f"Error while doing request to api endpoint {message}") + + data = req.json() + return data + + def load_account_data(self, account: Account): """ Load the ``next_sequence`` and ``account_number`` into the account object. @@ -772,6 +890,56 @@

    HTTPClient

    transaction.set_gas(int(gas_used * multiplier)) return gas_used + + def get_tx(self, *, tx_hash: str, timeout: int = 5): + """ + Query a transaction by passing the hash + + Note: + Takes only positional arguments. + + Args: + tx_hash (Transaction): The transaction hash + timeout (int): Timeout for the request before throwing a NodeException + + Returns: + transaction (dict): Transaction dict as returned by the chain + + + """ + path = "/cosmos/tx/v1beta1/txs/" + tx_hash + + try: + data = self._make_get_request(path=path, timeout=timeout) + except NodeException: + raise TransactionNotFound(f"The transaction {tx_hash} couldn't be found") + + return data + + + 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.")
    @@ -871,36 +1039,36 @@

    Source code in mospy/clients/HTTPClient.py -
    56
    -57
    -58
    -59
    -60
    -61
    -62
    -63
    -64
    -65
    -66
    -67
    -68
    -69
    -70
    -71
    -72
    -73
    -74
    -75
    -76
    -77
    -78
    -79
    -80
    -81
    -82
    -83
    -84
    -85
    def broadcast_transaction(self,
    +        
     78
    + 79
    + 80
    + 81
    + 82
    + 83
    + 84
    + 85
    + 86
    + 87
    + 88
    + 89
    + 90
    + 91
    + 92
    + 93
    + 94
    + 95
    + 96
    + 97
    + 98
    + 99
    +100
    +101
    +102
    +103
    +104
    +105
    +106
    +107
    def broadcast_transaction(self,
                               *,
                               transaction: Transaction,
                               timeout: int = 10) -> [str, int, str]:
    @@ -1028,29 +1196,7 @@ 

    Source code in mospy/clients/HTTPClient.py -
     87
    - 88
    - 89
    - 90
    - 91
    - 92
    - 93
    - 94
    - 95
    - 96
    - 97
    - 98
    - 99
    -100
    -101
    -102
    -103
    -104
    -105
    -106
    -107
    -108
    -109
    +        
    109
     110
     111
     112
    @@ -1060,7 +1206,29 @@ 

    116 117 118 -119

    def estimate_gas(self,
    +119
    +120
    +121
    +122
    +123
    +124
    +125
    +126
    +127
    +128
    +129
    +130
    +131
    +132
    +133
    +134
    +135
    +136
    +137
    +138
    +139
    +140
    +141
    def estimate_gas(self,
                               *,
                               transaction: Transaction,
                               update: bool = True,
    @@ -1103,6 +1271,131 @@ 

    +get_tx(*, tx_hash, timeout=5) + +

    + + +
    + +

    Query a transaction by passing the hash

    + +
    + Note +

    Takes only positional arguments.

    +
    +

    Parameters:

    + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescriptionDefault
    tx_hash + Transaction +

    The transaction hash

    + required +
    timeout + int +

    Timeout for the request before throwing a NodeException

    + 5 +
    + +

    Returns:

    + + + + + + + + + + + + + +
    Name TypeDescription
    transaction + dict +

    Transaction dict as returned by the chain

    + +
    + Source code in mospy/clients/HTTPClient.py +
    143
    +144
    +145
    +146
    +147
    +148
    +149
    +150
    +151
    +152
    +153
    +154
    +155
    +156
    +157
    +158
    +159
    +160
    +161
    +162
    +163
    +164
    +165
    +166
    def get_tx(self, *, tx_hash: str, timeout: int = 5):
    +    """
    +    Query a transaction by passing the hash
    +
    +    Note:
    +        Takes only positional arguments.
    +
    +    Args:
    +        tx_hash (Transaction): The transaction hash
    +        timeout (int): Timeout for the request before throwing a NodeException
    +
    +    Returns:
    +        transaction (dict): Transaction dict as returned by the chain
    +
    +
    +    """
    +    path = "/cosmos/tx/v1beta1/txs/" + tx_hash
    +
    +    try:
    +        data = self._make_get_request(path=path, timeout=timeout)
    +    except NodeException:
    +        raise TransactionNotFound(f"The transaction {tx_hash} couldn't be found")
    +
    +    return data
    +
    +
    +
    + +
    + +
    + + +

    load_account_data(account) @@ -1139,26 +1432,26 @@

    Source code in mospy/clients/HTTPClient.py -
    35
    -36
    -37
    -38
    -39
    -40
    -41
    -42
    -43
    -44
    -45
    -46
    -47
    -48
    -49
    -50
    -51
    -52
    -53
    -54
    def load_account_data(self, account: Account):
    +        
    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:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescriptionDefault
    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 TypeDescription
    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:
    +183
    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
    @@ -1035,8 +1031,7 @@

    Source code in mospy/Transaction.py -
    74
    -75
    +        
    75
     76
     77
     78
    @@ -1045,7 +1040,8 @@ 

    81 82 83 -84

    def add_msg(self, tx_type: str, **kwargs) -> None:
    +84
    +85
    def add_msg(self, tx_type: str, **kwargs) -> None:
         """
         Add a pre-defined message to the tx body.
     
    @@ -1111,8 +1107,7 @@ 

    Source code in mospy/Transaction.py -
    86
    -87
    +        
    87
     88
     89
     90
    @@ -1122,7 +1117,8 @@ 

    94 95 96 -97

    def add_raw_msg(self, unpacked_msg, type_url: str) -> None:
    +97
    +98
    def add_raw_msg(self, unpacked_msg, type_url: str) -> None:
         """
         Add a message to the tx body manually.
     
    @@ -1175,8 +1171,7 @@ 

    Source code in mospy/Transaction.py -
    118
    -119
    +        
    119
     120
     121
     122
    @@ -1190,7 +1185,8 @@ 

    130 131 132 -133

    def get_tx_bytes(self) -> bytes:
    +133
    +134
    def get_tx_bytes(self) -> bytes:
         """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
    @@ -1246,15 +1242,15 @@ 

    Source code in mospy/Transaction.py -
    135
    -136
    +        
    136
     137
     138
     139
     140
     141
     142
    -143
    def get_tx_bytes_as_string(self) -> str:
    +143
    +144
    def get_tx_bytes_as_string(self) -> str:
         """Sign the transaction and get the base64 encoded tx bytes which can be used to broadcast the transaction to the network.
     
         Returns:
    @@ -1319,15 +1315,15 @@ 

    Source code in mospy/Transaction.py -
     99
    -100
    +        
    100
     101
     102
     103
     104
     105
     106
    -107
    def set_fee(self, amount: int, denom: str = "uatom"):
    +107
    +108
    def set_fee(self, amount: int, denom: str = "uatom"):
         """
         Set the fee manually
     
    @@ -1382,14 +1378,14 @@ 

    Source code in mospy/Transaction.py -
    109
    -110
    +        
    110
     111
     112
     113
     114
     115
    -116
    def set_gas(self, gas: int):
    +116
    +117
    def set_gas(self, gas: int):
         """
         Update the wanted gas for the transaction