hive-nectar 0.2.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hive_nectar-0.2.9.dist-info/METADATA +194 -0
- hive_nectar-0.2.9.dist-info/RECORD +87 -0
- hive_nectar-0.2.9.dist-info/WHEEL +4 -0
- hive_nectar-0.2.9.dist-info/entry_points.txt +2 -0
- hive_nectar-0.2.9.dist-info/licenses/LICENSE.txt +23 -0
- nectar/__init__.py +37 -0
- nectar/account.py +5076 -0
- nectar/amount.py +553 -0
- nectar/asciichart.py +303 -0
- nectar/asset.py +122 -0
- nectar/block.py +574 -0
- nectar/blockchain.py +1242 -0
- nectar/blockchaininstance.py +2590 -0
- nectar/blockchainobject.py +263 -0
- nectar/cli.py +5937 -0
- nectar/comment.py +1552 -0
- nectar/community.py +854 -0
- nectar/constants.py +95 -0
- nectar/discussions.py +1437 -0
- nectar/exceptions.py +152 -0
- nectar/haf.py +381 -0
- nectar/hive.py +630 -0
- nectar/imageuploader.py +114 -0
- nectar/instance.py +113 -0
- nectar/market.py +876 -0
- nectar/memo.py +542 -0
- nectar/message.py +379 -0
- nectar/nodelist.py +309 -0
- nectar/price.py +603 -0
- nectar/profile.py +74 -0
- nectar/py.typed +0 -0
- nectar/rc.py +333 -0
- nectar/snapshot.py +1024 -0
- nectar/storage.py +62 -0
- nectar/transactionbuilder.py +659 -0
- nectar/utils.py +630 -0
- nectar/version.py +3 -0
- nectar/vote.py +722 -0
- nectar/wallet.py +472 -0
- nectar/witness.py +728 -0
- nectarapi/__init__.py +12 -0
- nectarapi/exceptions.py +126 -0
- nectarapi/graphenerpc.py +596 -0
- nectarapi/node.py +194 -0
- nectarapi/noderpc.py +79 -0
- nectarapi/openapi.py +107 -0
- nectarapi/py.typed +0 -0
- nectarapi/rpcutils.py +98 -0
- nectarapi/version.py +3 -0
- nectarbase/__init__.py +15 -0
- nectarbase/ledgertransactions.py +106 -0
- nectarbase/memo.py +242 -0
- nectarbase/objects.py +521 -0
- nectarbase/objecttypes.py +21 -0
- nectarbase/operationids.py +102 -0
- nectarbase/operations.py +1357 -0
- nectarbase/py.typed +0 -0
- nectarbase/signedtransactions.py +89 -0
- nectarbase/transactions.py +11 -0
- nectarbase/version.py +3 -0
- nectargraphenebase/__init__.py +27 -0
- nectargraphenebase/account.py +1121 -0
- nectargraphenebase/aes.py +49 -0
- nectargraphenebase/base58.py +197 -0
- nectargraphenebase/bip32.py +575 -0
- nectargraphenebase/bip38.py +110 -0
- nectargraphenebase/chains.py +15 -0
- nectargraphenebase/dictionary.py +2 -0
- nectargraphenebase/ecdsasig.py +309 -0
- nectargraphenebase/objects.py +130 -0
- nectargraphenebase/objecttypes.py +8 -0
- nectargraphenebase/operationids.py +5 -0
- nectargraphenebase/operations.py +25 -0
- nectargraphenebase/prefix.py +13 -0
- nectargraphenebase/py.typed +0 -0
- nectargraphenebase/signedtransactions.py +221 -0
- nectargraphenebase/types.py +557 -0
- nectargraphenebase/unsignedtransactions.py +288 -0
- nectargraphenebase/version.py +3 -0
- nectarstorage/__init__.py +57 -0
- nectarstorage/base.py +317 -0
- nectarstorage/exceptions.py +15 -0
- nectarstorage/interfaces.py +244 -0
- nectarstorage/masterpassword.py +237 -0
- nectarstorage/py.typed +0 -0
- nectarstorage/ram.py +27 -0
- nectarstorage/sqlite.py +343 -0
nectar/exceptions.py
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
class NectarException(Exception):
|
|
2
|
+
"""Base exception for all Nectar-related errors"""
|
|
3
|
+
|
|
4
|
+
pass
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class WalletExists(NectarException):
|
|
8
|
+
"""A wallet has already been created and requires a password to be
|
|
9
|
+
unlocked by means of :func:`nectar.wallet.Wallet.unlock`.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class RPCConnectionRequired(NectarException):
|
|
16
|
+
"""An RPC connection is required"""
|
|
17
|
+
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class InvalidMemoKeyException(NectarException):
|
|
22
|
+
"""Memo key in message is invalid"""
|
|
23
|
+
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class WrongMemoKey(NectarException):
|
|
28
|
+
"""The memo provided is not equal the one on the blockchain"""
|
|
29
|
+
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class OfflineHasNoRPCException(NectarException):
|
|
34
|
+
"""When in offline mode, we don't have RPC"""
|
|
35
|
+
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class AccountExistsException(NectarException):
|
|
40
|
+
"""The requested account already exists"""
|
|
41
|
+
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class AccountDoesNotExistsException(NectarException):
|
|
46
|
+
"""The account does not exist"""
|
|
47
|
+
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class AssetDoesNotExistsException(NectarException):
|
|
52
|
+
"""The asset does not exist"""
|
|
53
|
+
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class InvalidAssetException(NectarException):
|
|
58
|
+
"""An invalid asset has been provided"""
|
|
59
|
+
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class InsufficientAuthorityError(NectarException):
|
|
64
|
+
"""The transaction requires signature of a higher authority"""
|
|
65
|
+
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class VotingInvalidOnArchivedPost(NectarException):
|
|
70
|
+
"""The transaction requires signature of a higher authority"""
|
|
71
|
+
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class MissingKeyError(NectarException):
|
|
76
|
+
"""A required key couldn't be found in the wallet"""
|
|
77
|
+
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class InvalidWifError(NectarException):
|
|
82
|
+
"""The provided private Key has an invalid format"""
|
|
83
|
+
|
|
84
|
+
pass
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class BlockDoesNotExistsException(NectarException):
|
|
88
|
+
"""The block does not exist"""
|
|
89
|
+
|
|
90
|
+
pass
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class NoWalletException(NectarException):
|
|
94
|
+
"""No Wallet could be found, please use :func:`nectar.wallet.Wallet.create` to
|
|
95
|
+
create a new wallet
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
pass
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class WitnessDoesNotExistsException(NectarException):
|
|
102
|
+
"""The witness does not exist"""
|
|
103
|
+
|
|
104
|
+
pass
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class ContentDoesNotExistsException(NectarException):
|
|
108
|
+
"""The content does not exist"""
|
|
109
|
+
|
|
110
|
+
pass
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class VoteDoesNotExistsException(NectarException):
|
|
114
|
+
"""The vote does not exist"""
|
|
115
|
+
|
|
116
|
+
pass
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class WrongMasterPasswordException(NectarException):
|
|
120
|
+
"""The password provided could not properly unlock the wallet"""
|
|
121
|
+
|
|
122
|
+
pass
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class VestingBalanceDoesNotExistsException(NectarException):
|
|
126
|
+
"""Vesting Balance does not exist"""
|
|
127
|
+
|
|
128
|
+
pass
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class InvalidMessageSignature(NectarException):
|
|
132
|
+
"""The message signature does not fit the message"""
|
|
133
|
+
|
|
134
|
+
pass
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class NoWriteAccess(NectarException):
|
|
138
|
+
"""Cannot store to sqlite3 database due to missing write access"""
|
|
139
|
+
|
|
140
|
+
pass
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class BatchedCallsNotSupported(NectarException):
|
|
144
|
+
"""Batch calls do not work"""
|
|
145
|
+
|
|
146
|
+
pass
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class BlockWaitTimeExceeded(NectarException):
|
|
150
|
+
"""Wait time for new block exceeded"""
|
|
151
|
+
|
|
152
|
+
pass
|
nectar/haf.py
ADDED
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
|
|
7
|
+
from nectar.instance import shared_blockchain_instance
|
|
8
|
+
|
|
9
|
+
log = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class HAF:
|
|
13
|
+
"""Hive Account Feed (HAF) API client for accessing Hive blockchain endpoints.
|
|
14
|
+
|
|
15
|
+
This class provides access to various Hive API endpoints that are not part of the
|
|
16
|
+
standard RPC blockchain calls. It supports multiple API providers and handles
|
|
17
|
+
reputation queries and other HAF-related data.
|
|
18
|
+
|
|
19
|
+
:param str api: Base API URL to use for requests. Supported endpoints include:
|
|
20
|
+
- 'https://api.hive.blog' (default)
|
|
21
|
+
- 'https://api.syncad.com'
|
|
22
|
+
:param blockchain_instance: Blockchain instance for compatibility with the nectar ecosystem
|
|
23
|
+
|
|
24
|
+
.. code-block:: python
|
|
25
|
+
|
|
26
|
+
>>> from nectar.haf import HAF
|
|
27
|
+
>>> haf = HAF() # doctest: +SKIP
|
|
28
|
+
>>> reputation = haf.reputation("thecrazygm") # doctest: +SKIP
|
|
29
|
+
>>> print(reputation) # doctest: +SKIP
|
|
30
|
+
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
DEFAULT_APIS = ["https://api.hive.blog", "https://api.syncad.com"]
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self, api: Optional[str] = None, blockchain_instance=None, timeout: Optional[float] = None
|
|
37
|
+
):
|
|
38
|
+
"""
|
|
39
|
+
Initialize the HAF client.
|
|
40
|
+
|
|
41
|
+
Parameters:
|
|
42
|
+
api (str, optional): Base API URL. If None, uses the first available default API.
|
|
43
|
+
blockchain_instance: Blockchain instance for ecosystem compatibility.
|
|
44
|
+
timeout (float, optional): Timeout for requests in seconds.
|
|
45
|
+
"""
|
|
46
|
+
self.api = api or self.DEFAULT_APIS[0]
|
|
47
|
+
self.blockchain = blockchain_instance or shared_blockchain_instance()
|
|
48
|
+
self._timeout = float(timeout) if timeout else 30.0
|
|
49
|
+
|
|
50
|
+
# Validate API URL
|
|
51
|
+
if not self.api.startswith(("http://", "https://")):
|
|
52
|
+
raise ValueError(f"Invalid API URL: {self.api}. Must start with http:// or https://")
|
|
53
|
+
|
|
54
|
+
# Remove trailing slash if present
|
|
55
|
+
self.api = self.api.rstrip("/")
|
|
56
|
+
|
|
57
|
+
log.debug(f"Initialized HAF client with API: {self.api}")
|
|
58
|
+
|
|
59
|
+
def _make_request(self, endpoint: str, method: str = "GET", **kwargs) -> Any:
|
|
60
|
+
"""
|
|
61
|
+
Make an HTTP request to the HAF API.
|
|
62
|
+
|
|
63
|
+
Parameters:
|
|
64
|
+
endpoint (str): API endpoint path (without leading slash)
|
|
65
|
+
method (str): HTTP method (default: 'GET')
|
|
66
|
+
**kwargs: Additional arguments passed to requests
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
dict: JSON response from the API
|
|
70
|
+
|
|
71
|
+
Raises:
|
|
72
|
+
httpx.RequestError: If the request fails
|
|
73
|
+
ValueError: If the response is not valid JSON
|
|
74
|
+
"""
|
|
75
|
+
url = f"{self.api}/{endpoint}"
|
|
76
|
+
|
|
77
|
+
# Set default headers
|
|
78
|
+
headers = kwargs.pop("headers", {})
|
|
79
|
+
headers.setdefault("accept", "application/json")
|
|
80
|
+
from nectar.version import version as nectar_version
|
|
81
|
+
|
|
82
|
+
headers.setdefault("User-Agent", f"hive-nectar/{nectar_version}")
|
|
83
|
+
|
|
84
|
+
log.debug(f"Making {method} request to: {url}")
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
timeout = kwargs.pop("timeout", self._timeout)
|
|
88
|
+
with httpx.Client(timeout=timeout) as client:
|
|
89
|
+
response = client.request(method, url, headers=headers, **kwargs)
|
|
90
|
+
response.raise_for_status()
|
|
91
|
+
return response.json()
|
|
92
|
+
|
|
93
|
+
except httpx.RequestError as e:
|
|
94
|
+
log.error(f"Request failed for {url}: {e}")
|
|
95
|
+
raise
|
|
96
|
+
except (httpx.HTTPStatusError, json.JSONDecodeError) as e:
|
|
97
|
+
log.error(f"Invalid response from {url}: {e}")
|
|
98
|
+
raise ValueError(f"Invalid response from API: {e}")
|
|
99
|
+
|
|
100
|
+
def reputation(self, account: str) -> Optional[Dict[str, Any]]:
|
|
101
|
+
"""
|
|
102
|
+
Get reputation information for a Hive account.
|
|
103
|
+
|
|
104
|
+
This method queries the reputation API endpoint to retrieve the account's
|
|
105
|
+
reputation score and related metadata.
|
|
106
|
+
|
|
107
|
+
Parameters:
|
|
108
|
+
account (str): Hive account name
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
dict or None: Reputation data containing account information and reputation score,
|
|
112
|
+
or None if the request fails or account is not found
|
|
113
|
+
|
|
114
|
+
Example:
|
|
115
|
+
>>> haf = HAF() # doctest: +SKIP
|
|
116
|
+
>>> rep = haf.reputation("thecrazygm") # doctest: +SKIP
|
|
117
|
+
>>> print(rep) # doctest: +SKIP
|
|
118
|
+
{'account': 'thecrazygm', 'reputation': '71', ...}
|
|
119
|
+
|
|
120
|
+
"""
|
|
121
|
+
if not account or not isinstance(account, str):
|
|
122
|
+
raise ValueError("Account name must be a non-empty string")
|
|
123
|
+
|
|
124
|
+
try:
|
|
125
|
+
endpoint = f"reputation-api/accounts/{account}/reputation"
|
|
126
|
+
response = self._make_request(endpoint)
|
|
127
|
+
|
|
128
|
+
log.debug(f"Retrieved reputation for account: {account}")
|
|
129
|
+
return response
|
|
130
|
+
|
|
131
|
+
except httpx.RequestError as e:
|
|
132
|
+
log.warning(f"Failed to retrieve reputation for account {account}: {e}")
|
|
133
|
+
return None
|
|
134
|
+
except Exception as e:
|
|
135
|
+
log.error(f"Unexpected error retrieving reputation for {account}: {e}")
|
|
136
|
+
return None
|
|
137
|
+
|
|
138
|
+
def get_available_apis(self) -> list[str]:
|
|
139
|
+
"""
|
|
140
|
+
Get the list of available API endpoints.
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
list: List of supported API URLs
|
|
144
|
+
"""
|
|
145
|
+
return self.DEFAULT_APIS.copy()
|
|
146
|
+
|
|
147
|
+
def set_api(self, api: str) -> None:
|
|
148
|
+
"""
|
|
149
|
+
Change the API endpoint.
|
|
150
|
+
|
|
151
|
+
Parameters:
|
|
152
|
+
api (str): New API URL to use
|
|
153
|
+
|
|
154
|
+
Raises:
|
|
155
|
+
ValueError: If the API URL is invalid
|
|
156
|
+
"""
|
|
157
|
+
if api not in self.DEFAULT_APIS:
|
|
158
|
+
log.warning(f"Using non-default API: {api}")
|
|
159
|
+
|
|
160
|
+
# Validate URL
|
|
161
|
+
if not api.startswith(("http://", "https://")):
|
|
162
|
+
raise ValueError(f"Invalid API URL: {api}. Must start with http:// or https://")
|
|
163
|
+
|
|
164
|
+
self.api = api.rstrip("/")
|
|
165
|
+
log.info(f"Switched to API: {self.api}")
|
|
166
|
+
|
|
167
|
+
def get_current_api(self) -> str:
|
|
168
|
+
"""
|
|
169
|
+
Get the currently active API endpoint.
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
str: Current API URL
|
|
173
|
+
"""
|
|
174
|
+
return self.api
|
|
175
|
+
|
|
176
|
+
def get_account_balances(self, account: str) -> Optional[Dict[str, Any]]:
|
|
177
|
+
"""
|
|
178
|
+
Get account balances from the balance API.
|
|
179
|
+
|
|
180
|
+
This method retrieves comprehensive balance information including HBD, HIVE,
|
|
181
|
+
vesting shares, rewards, and other balance-related data for an account.
|
|
182
|
+
|
|
183
|
+
Parameters:
|
|
184
|
+
account (str): Hive account name
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
dict or None: Account balance data or None if request fails
|
|
188
|
+
|
|
189
|
+
Example:
|
|
190
|
+
>>> haf = HAF() # doctest: +SKIP
|
|
191
|
+
>>> balances = haf.get_account_balances("thecrazygm") # doctest: +SKIP
|
|
192
|
+
>>> print(balances['hive_balance']) # doctest: +SKIP
|
|
193
|
+
"""
|
|
194
|
+
if not account or not isinstance(account, str):
|
|
195
|
+
raise ValueError("Account name must be a non-empty string")
|
|
196
|
+
|
|
197
|
+
try:
|
|
198
|
+
endpoint = f"balance-api/accounts/{account}/balances"
|
|
199
|
+
response = self._make_request(endpoint)
|
|
200
|
+
|
|
201
|
+
log.debug(f"Retrieved balances for account: {account}")
|
|
202
|
+
return response
|
|
203
|
+
|
|
204
|
+
except httpx.RequestError as e:
|
|
205
|
+
log.warning(f"Failed to retrieve balances for account {account}: {e}")
|
|
206
|
+
return None
|
|
207
|
+
except Exception as e:
|
|
208
|
+
log.error(f"Unexpected error retrieving balances for {account}: {e}")
|
|
209
|
+
return None
|
|
210
|
+
|
|
211
|
+
def get_account_delegations(self, account: str) -> Optional[Dict[str, Any]]:
|
|
212
|
+
"""
|
|
213
|
+
Get account delegations from the balance API.
|
|
214
|
+
|
|
215
|
+
This method retrieves both incoming and outgoing delegations for an account.
|
|
216
|
+
|
|
217
|
+
Parameters:
|
|
218
|
+
account (str): Hive account name
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
dict or None: Delegation data containing incoming and outgoing delegations
|
|
222
|
+
|
|
223
|
+
Example:
|
|
224
|
+
>>> haf = HAF() # doctest: +SKIP
|
|
225
|
+
>>> delegations = haf.get_account_delegations("thecrazygm") # doctest: +SKIP
|
|
226
|
+
>>> print(delegations['incoming_delegations']) # doctest: +SKIP
|
|
227
|
+
"""
|
|
228
|
+
if not account or not isinstance(account, str):
|
|
229
|
+
raise ValueError("Account name must be a non-empty string")
|
|
230
|
+
|
|
231
|
+
try:
|
|
232
|
+
endpoint = f"balance-api/accounts/{account}/delegations"
|
|
233
|
+
response = self._make_request(endpoint)
|
|
234
|
+
|
|
235
|
+
log.debug(f"Retrieved delegations for account: {account}")
|
|
236
|
+
return response
|
|
237
|
+
|
|
238
|
+
except httpx.RequestError as e:
|
|
239
|
+
log.warning(f"Failed to retrieve delegations for account {account}: {e}")
|
|
240
|
+
return None
|
|
241
|
+
except Exception as e:
|
|
242
|
+
log.error(f"Unexpected error retrieving delegations for {account}: {e}")
|
|
243
|
+
return None
|
|
244
|
+
|
|
245
|
+
def get_account_recurrent_transfers(self, account: str) -> Optional[Dict[str, Any]]:
|
|
246
|
+
"""
|
|
247
|
+
Get account recurrent transfers from the balance API.
|
|
248
|
+
|
|
249
|
+
This method retrieves both incoming and outgoing recurrent transfers for an account.
|
|
250
|
+
|
|
251
|
+
Parameters:
|
|
252
|
+
account (str): Hive account name
|
|
253
|
+
|
|
254
|
+
Returns:
|
|
255
|
+
dict or None: Recurrent transfer data containing incoming and outgoing transfers
|
|
256
|
+
|
|
257
|
+
Example:
|
|
258
|
+
>>> haf = HAF() # doctest: +SKIP
|
|
259
|
+
>>> transfers = haf.get_account_recurrent_transfers("thecrazygm") # doctest: +SKIP
|
|
260
|
+
>>> print(transfers['outgoing_recurrent_transfers']) # doctest: +SKIP
|
|
261
|
+
"""
|
|
262
|
+
if not account or not isinstance(account, str):
|
|
263
|
+
raise ValueError("Account name must be a non-empty string")
|
|
264
|
+
|
|
265
|
+
try:
|
|
266
|
+
endpoint = f"balance-api/accounts/{account}/recurrent-transfers"
|
|
267
|
+
response = self._make_request(endpoint)
|
|
268
|
+
|
|
269
|
+
log.debug(f"Retrieved recurrent transfers for account: {account}")
|
|
270
|
+
return response
|
|
271
|
+
|
|
272
|
+
except httpx.RequestError as e:
|
|
273
|
+
log.warning(f"Failed to retrieve recurrent transfers for account {account}: {e}")
|
|
274
|
+
return None
|
|
275
|
+
except Exception as e:
|
|
276
|
+
log.error(f"Unexpected error retrieving recurrent transfers for {account}: {e}")
|
|
277
|
+
return None
|
|
278
|
+
|
|
279
|
+
def get_reputation_version(self) -> Optional[str]:
|
|
280
|
+
"""
|
|
281
|
+
Get the reputation tracker's version from the reputation API.
|
|
282
|
+
|
|
283
|
+
Returns:
|
|
284
|
+
str or None: Version string or None if request fails
|
|
285
|
+
|
|
286
|
+
Example:
|
|
287
|
+
>>> haf = HAF() # doctest: +SKIP
|
|
288
|
+
>>> version = haf.get_reputation_version() # doctest: +SKIP
|
|
289
|
+
>>> print(version) # doctest: +SKIP
|
|
290
|
+
"""
|
|
291
|
+
try:
|
|
292
|
+
endpoint = "reputation-api/version"
|
|
293
|
+
response = self._make_request(endpoint)
|
|
294
|
+
|
|
295
|
+
log.debug("Retrieved reputation tracker version")
|
|
296
|
+
return response
|
|
297
|
+
|
|
298
|
+
except httpx.RequestError as e:
|
|
299
|
+
log.warning(f"Failed to retrieve reputation version: {e}")
|
|
300
|
+
return None
|
|
301
|
+
except Exception as e:
|
|
302
|
+
log.error(f"Unexpected error retrieving reputation version: {e}")
|
|
303
|
+
return None
|
|
304
|
+
|
|
305
|
+
def get_reputation_last_synced_block(self) -> Optional[int]:
|
|
306
|
+
"""
|
|
307
|
+
Get the last block number synced by the reputation tracker.
|
|
308
|
+
|
|
309
|
+
Returns:
|
|
310
|
+
int or None: Last synced block number or None if request fails
|
|
311
|
+
|
|
312
|
+
Example:
|
|
313
|
+
>>> haf = HAF() # doctest: +SKIP
|
|
314
|
+
>>> block = haf.get_reputation_last_synced_block() # doctest: +SKIP
|
|
315
|
+
>>> print(block) # doctest: +SKIP
|
|
316
|
+
"""
|
|
317
|
+
try:
|
|
318
|
+
endpoint = "reputation-api/last-synced-block"
|
|
319
|
+
response = self._make_request(endpoint)
|
|
320
|
+
|
|
321
|
+
log.debug("Retrieved last synced block for reputation tracker")
|
|
322
|
+
return response
|
|
323
|
+
|
|
324
|
+
except httpx.RequestError as e:
|
|
325
|
+
log.warning(f"Failed to retrieve last synced block: {e}")
|
|
326
|
+
return None
|
|
327
|
+
except Exception as e:
|
|
328
|
+
log.error(f"Unexpected error retrieving last synced block: {e}")
|
|
329
|
+
return None
|
|
330
|
+
|
|
331
|
+
def get_balance_version(self) -> Optional[str]:
|
|
332
|
+
"""
|
|
333
|
+
Get the balance tracker's version from the balance API.
|
|
334
|
+
|
|
335
|
+
Returns:
|
|
336
|
+
str or None: Version string or None if request fails
|
|
337
|
+
|
|
338
|
+
Example:
|
|
339
|
+
>>> haf = HAF() # doctest: +SKIP
|
|
340
|
+
>>> version = haf.get_balance_version() # doctest: +SKIP
|
|
341
|
+
>>> print(version) # doctest: +SKIP
|
|
342
|
+
"""
|
|
343
|
+
try:
|
|
344
|
+
endpoint = "balance-api/version"
|
|
345
|
+
response = self._make_request(endpoint)
|
|
346
|
+
|
|
347
|
+
log.debug("Retrieved balance tracker version")
|
|
348
|
+
return response
|
|
349
|
+
|
|
350
|
+
except httpx.RequestError as e:
|
|
351
|
+
log.warning(f"Failed to retrieve balance version: {e}")
|
|
352
|
+
return None
|
|
353
|
+
except Exception as e:
|
|
354
|
+
log.error(f"Unexpected error retrieving balance version: {e}")
|
|
355
|
+
return None
|
|
356
|
+
|
|
357
|
+
def get_balance_last_synced_block(self) -> Optional[int]:
|
|
358
|
+
"""
|
|
359
|
+
Get the last block number synced by the balance tracker.
|
|
360
|
+
|
|
361
|
+
Returns:
|
|
362
|
+
int or None: Last synced block number or None if request fails
|
|
363
|
+
|
|
364
|
+
Example:
|
|
365
|
+
>>> haf = HAF() # doctest: +SKIP
|
|
366
|
+
>>> block = haf.get_balance_last_synced_block() # doctest: +SKIP
|
|
367
|
+
>>> print(block) # doctest: +SKIP
|
|
368
|
+
"""
|
|
369
|
+
try:
|
|
370
|
+
endpoint = "balance-api/last-synced-block"
|
|
371
|
+
response = self._make_request(endpoint)
|
|
372
|
+
|
|
373
|
+
log.debug("Retrieved last synced block for balance tracker")
|
|
374
|
+
return response
|
|
375
|
+
|
|
376
|
+
except httpx.RequestError as e:
|
|
377
|
+
log.warning(f"Failed to retrieve last synced block: {e}")
|
|
378
|
+
return None
|
|
379
|
+
except Exception as e:
|
|
380
|
+
log.error(f"Unexpected error retrieving last synced block: {e}")
|
|
381
|
+
return None
|