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/hive.py
ADDED
|
@@ -0,0 +1,630 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import math
|
|
3
|
+
from datetime import date, datetime, timezone
|
|
4
|
+
from typing import Any, Dict, Optional, Union
|
|
5
|
+
|
|
6
|
+
from nectar.blockchaininstance import BlockChainInstance
|
|
7
|
+
from nectar.constants import HIVE_100_PERCENT
|
|
8
|
+
from nectar.price import Price
|
|
9
|
+
from nectargraphenebase.chains import known_chains
|
|
10
|
+
|
|
11
|
+
from .amount import Amount
|
|
12
|
+
from .utils import formatToTimeStamp
|
|
13
|
+
|
|
14
|
+
log = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Hive(BlockChainInstance):
|
|
18
|
+
"""Connect to the Hive network.
|
|
19
|
+
|
|
20
|
+
:param str node: Node to connect to *(optional)*
|
|
21
|
+
:param str rpcuser: RPC user *(optional)*
|
|
22
|
+
:param str rpcpassword: RPC password *(optional)*
|
|
23
|
+
:param bool nobroadcast: Do **not** broadcast a transaction!
|
|
24
|
+
*(optional)*
|
|
25
|
+
:param bool unsigned: Do **not** sign a transaction! *(optional)*
|
|
26
|
+
:param bool debug: Enable Debugging *(optional)*
|
|
27
|
+
:param keys: Predefine the wif keys to shortcut the
|
|
28
|
+
wallet database *(optional)*
|
|
29
|
+
:type keys: array, dict, string
|
|
30
|
+
:param wif: Predefine the wif keys to shortcut the
|
|
31
|
+
wallet database *(optional)*
|
|
32
|
+
:type wif: array, dict, string
|
|
33
|
+
:param bool offline: Boolean to prevent connecting to network (defaults
|
|
34
|
+
to ``False``) *(optional)*
|
|
35
|
+
:param int expiration: Delay in seconds until transactions are supposed
|
|
36
|
+
to expire *(optional)* (default is 300)
|
|
37
|
+
:param str blocking: Wait for broadcasted transactions to be included
|
|
38
|
+
in a block and return full transaction (can be "head" or
|
|
39
|
+
"irreversible")
|
|
40
|
+
:param bool bundle: Do not broadcast transactions right away, but allow
|
|
41
|
+
to bundle operations. It is not possible to send out more than one
|
|
42
|
+
vote operation and more than one comment operation in a single broadcast *(optional)*
|
|
43
|
+
:param dict custom_chains: custom chain which should be added to the known chains
|
|
44
|
+
|
|
45
|
+
Three wallet operation modes are possible:
|
|
46
|
+
|
|
47
|
+
* **Wallet Database**: Here, the nectarlibs load the keys from the
|
|
48
|
+
locally stored wallet SQLite database (see ``storage.py``).
|
|
49
|
+
To use this mode, simply call ``Hive()`` without the
|
|
50
|
+
``keys`` parameter
|
|
51
|
+
* **Providing Keys**: Here, you can provide the keys for
|
|
52
|
+
your accounts manually. All you need to do is add the wif
|
|
53
|
+
keys for the accounts you want to use as a simple array
|
|
54
|
+
using the ``keys`` parameter to ``Hive()``.
|
|
55
|
+
* **Force keys**: This more is for advanced users and
|
|
56
|
+
requires that you know what you are doing. Here, the
|
|
57
|
+
``keys`` parameter is a dictionary that overwrite the
|
|
58
|
+
``active``, ``owner``, ``posting`` or ``memo`` keys for
|
|
59
|
+
any account. This mode is only used for *foreign*
|
|
60
|
+
signatures!
|
|
61
|
+
|
|
62
|
+
If no node is provided, it will connect to default nodes from
|
|
63
|
+
nectar.NodeList. Default settings can be changed with:
|
|
64
|
+
|
|
65
|
+
.. code-block:: python
|
|
66
|
+
|
|
67
|
+
hive = Hive(<host>)
|
|
68
|
+
|
|
69
|
+
where ``<host>`` starts with ``https://``, ``ws://`` or ``wss://``.
|
|
70
|
+
|
|
71
|
+
The purpose of this class it to simplify interaction with
|
|
72
|
+
Hive.
|
|
73
|
+
|
|
74
|
+
The idea is to have a class that allows to do this:
|
|
75
|
+
|
|
76
|
+
.. code-block:: python
|
|
77
|
+
|
|
78
|
+
>>> from nectar import Hive
|
|
79
|
+
>>> hive = Hive()
|
|
80
|
+
>>> print(hive.get_blockchain_version()) # doctest: +SKIP
|
|
81
|
+
|
|
82
|
+
This class also deals with edits, votes and reading content.
|
|
83
|
+
|
|
84
|
+
Example for adding a custom chain:
|
|
85
|
+
|
|
86
|
+
.. code-block:: python
|
|
87
|
+
|
|
88
|
+
from nectar import Hive
|
|
89
|
+
hv = Hive(node=["https://mytstnet.com"], custom_chains={"MYTESTNET":
|
|
90
|
+
{'chain_assets': [{'asset': 'HBD', 'id': 0, 'precision': 3, 'symbol': 'HBD'},
|
|
91
|
+
{'asset': 'HIVE', 'id': 1, 'precision': 3, 'symbol': 'HIVE'},
|
|
92
|
+
{'asset': 'VESTS', 'id': 2, 'precision': 6, 'symbol': 'VESTS'}],
|
|
93
|
+
'chain_id': '79276aea5d4877d9a25892eaa01b0adf019d3e5cb12a97478df3298ccdd01674',
|
|
94
|
+
'min_version': '0.0.0',
|
|
95
|
+
'prefix': 'MTN'}
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
def get_network(
|
|
102
|
+
self, use_stored_data: bool = True, config: Optional[Dict[str, Any]] = None
|
|
103
|
+
) -> Optional[Dict[str, Any]]:
|
|
104
|
+
"""Identify the network
|
|
105
|
+
|
|
106
|
+
:param bool use_stored_data: if True, stored data will be returned. If stored data are
|
|
107
|
+
empty or old, refresh_data() is used.
|
|
108
|
+
|
|
109
|
+
:returns: Network parameters
|
|
110
|
+
:rtype: dictionary
|
|
111
|
+
"""
|
|
112
|
+
if use_stored_data:
|
|
113
|
+
self.refresh_data("config")
|
|
114
|
+
return self.data["network"]
|
|
115
|
+
|
|
116
|
+
if self.rpc is None:
|
|
117
|
+
return known_chains["HIVE"]
|
|
118
|
+
try:
|
|
119
|
+
return self.rpc.get_network(props=config)
|
|
120
|
+
except Exception:
|
|
121
|
+
return known_chains["HIVE"]
|
|
122
|
+
|
|
123
|
+
def rshares_to_token_backed_dollar(
|
|
124
|
+
self,
|
|
125
|
+
rshares: Union[int, float],
|
|
126
|
+
not_broadcasted_vote: bool = False,
|
|
127
|
+
use_stored_data: bool = True,
|
|
128
|
+
) -> float:
|
|
129
|
+
return self.rshares_to_hbd(
|
|
130
|
+
rshares, not_broadcasted_vote=not_broadcasted_vote, use_stored_data=use_stored_data
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
def rshares_to_hbd(
|
|
134
|
+
self,
|
|
135
|
+
rshares: Union[int, float],
|
|
136
|
+
not_broadcasted_vote: bool = False,
|
|
137
|
+
use_stored_data: bool = True,
|
|
138
|
+
) -> float:
|
|
139
|
+
"""Calculates the current HBD value of a vote"""
|
|
140
|
+
payout = float(rshares) * self.get_hbd_per_rshares(
|
|
141
|
+
use_stored_data=use_stored_data,
|
|
142
|
+
not_broadcasted_vote_rshares=rshares if not_broadcasted_vote else 0,
|
|
143
|
+
)
|
|
144
|
+
return payout
|
|
145
|
+
|
|
146
|
+
def get_hbd_per_rshares(
|
|
147
|
+
self, not_broadcasted_vote_rshares: Union[int, float] = 0, use_stored_data: bool = True
|
|
148
|
+
) -> float:
|
|
149
|
+
"""Returns the current rshares to HBD ratio"""
|
|
150
|
+
reward_fund = self.get_reward_funds(use_stored_data=use_stored_data)
|
|
151
|
+
if not reward_fund or not isinstance(reward_fund, dict):
|
|
152
|
+
return 0
|
|
153
|
+
reward_balance = float(Amount(reward_fund["reward_balance"], blockchain_instance=self))
|
|
154
|
+
recent_claims = float(reward_fund["recent_claims"]) + not_broadcasted_vote_rshares
|
|
155
|
+
if recent_claims == 0:
|
|
156
|
+
return 0
|
|
157
|
+
fund_per_share = reward_balance / (recent_claims)
|
|
158
|
+
median_price = self.get_median_price(use_stored_data=use_stored_data)
|
|
159
|
+
# Check if median_price is a valid Price object (not None or raw dict)
|
|
160
|
+
from nectar.price import Price
|
|
161
|
+
|
|
162
|
+
if median_price is None or (
|
|
163
|
+
isinstance(median_price, dict) and not isinstance(median_price, Price)
|
|
164
|
+
):
|
|
165
|
+
return 0
|
|
166
|
+
HBD_price = float(median_price * Amount(1, self.hive_symbol, blockchain_instance=self))
|
|
167
|
+
return fund_per_share * HBD_price
|
|
168
|
+
|
|
169
|
+
def get_token_per_mvest(
|
|
170
|
+
self, time_stamp: Optional[Union[datetime, int]] = None, use_stored_data: bool = True
|
|
171
|
+
) -> float:
|
|
172
|
+
return self.get_hive_per_mvest(time_stamp=time_stamp, use_stored_data=use_stored_data)
|
|
173
|
+
|
|
174
|
+
def get_hive_per_mvest(
|
|
175
|
+
self, time_stamp: Optional[Union[datetime, int]] = None, use_stored_data: bool = True
|
|
176
|
+
) -> float:
|
|
177
|
+
"""Returns the MVEST to HIVE ratio
|
|
178
|
+
|
|
179
|
+
:param int time_stamp: (optional) if set, return an estimated
|
|
180
|
+
HIVE per MVEST ratio for the given time stamp. If unset the
|
|
181
|
+
current ratio is returned (default). (can also be a datetime object)
|
|
182
|
+
"""
|
|
183
|
+
if self.offline and time_stamp is None:
|
|
184
|
+
time_stamp = datetime.now(timezone.utc)
|
|
185
|
+
|
|
186
|
+
if time_stamp is not None:
|
|
187
|
+
if isinstance(time_stamp, (datetime, date)):
|
|
188
|
+
time_stamp = formatToTimeStamp(time_stamp)
|
|
189
|
+
a = 2.1325476281078992e-05
|
|
190
|
+
b = -31099.685481490847
|
|
191
|
+
a2 = 2.9019227739473682e-07
|
|
192
|
+
b2 = 48.41432402074669
|
|
193
|
+
|
|
194
|
+
if time_stamp < (b2 - b) / (a - a2):
|
|
195
|
+
return a * time_stamp + b
|
|
196
|
+
else:
|
|
197
|
+
return a2 * time_stamp + b2
|
|
198
|
+
global_properties = self.get_dynamic_global_properties(use_stored_data=use_stored_data)
|
|
199
|
+
if not global_properties or not isinstance(global_properties, dict):
|
|
200
|
+
return 0.0
|
|
201
|
+
return float(
|
|
202
|
+
Amount(global_properties["total_vesting_fund_hive"], blockchain_instance=self)
|
|
203
|
+
) / (
|
|
204
|
+
float(Amount(global_properties["total_vesting_shares"], blockchain_instance=self)) / 1e6
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
def vests_to_hp(
|
|
208
|
+
self,
|
|
209
|
+
vests: Union[Amount, float],
|
|
210
|
+
timestamp: Optional[Union[datetime, int]] = None,
|
|
211
|
+
use_stored_data: bool = True,
|
|
212
|
+
) -> float:
|
|
213
|
+
"""Converts vests to HP
|
|
214
|
+
|
|
215
|
+
:param amount.Amount vests/float vests: Vests to convert
|
|
216
|
+
:param int timestamp: (Optional) Can be used to calculate
|
|
217
|
+
the conversion rate from the past
|
|
218
|
+
|
|
219
|
+
"""
|
|
220
|
+
if isinstance(vests, Amount):
|
|
221
|
+
vests = float(vests)
|
|
222
|
+
return float(
|
|
223
|
+
float(vests)
|
|
224
|
+
/ 1e6
|
|
225
|
+
* float(self.get_hive_per_mvest(timestamp, use_stored_data=use_stored_data))
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
def vests_to_token_power(
|
|
229
|
+
self,
|
|
230
|
+
vests: Union[Amount, float],
|
|
231
|
+
timestamp: Optional[Union[datetime, int]] = None,
|
|
232
|
+
use_stored_data: bool = True,
|
|
233
|
+
) -> float:
|
|
234
|
+
return self.vests_to_hp(vests, timestamp=timestamp, use_stored_data=use_stored_data)
|
|
235
|
+
|
|
236
|
+
def hp_to_vests(
|
|
237
|
+
self,
|
|
238
|
+
hp: Union[Amount, float],
|
|
239
|
+
timestamp: Optional[Union[datetime, int]] = None,
|
|
240
|
+
use_stored_data: bool = True,
|
|
241
|
+
) -> float:
|
|
242
|
+
"""Converts HP to vests
|
|
243
|
+
|
|
244
|
+
:param float hp: Hive power to convert
|
|
245
|
+
:param datetime timestamp: (Optional) Can be used to calculate
|
|
246
|
+
the conversion rate from the past
|
|
247
|
+
"""
|
|
248
|
+
return (
|
|
249
|
+
float(hp)
|
|
250
|
+
* 1e6
|
|
251
|
+
/ float(self.get_hive_per_mvest(timestamp, use_stored_data=use_stored_data))
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
def token_power_to_vests(
|
|
255
|
+
self,
|
|
256
|
+
token_power: Union[Amount, float],
|
|
257
|
+
timestamp: Optional[Union[datetime, int]] = None,
|
|
258
|
+
use_stored_data: bool = True,
|
|
259
|
+
) -> float:
|
|
260
|
+
return self.hp_to_vests(token_power, timestamp=timestamp, use_stored_data=use_stored_data)
|
|
261
|
+
|
|
262
|
+
def token_power_to_token_backed_dollar(
|
|
263
|
+
self,
|
|
264
|
+
token_power: Union[Amount, float],
|
|
265
|
+
post_rshares: int = 0,
|
|
266
|
+
voting_power: int = HIVE_100_PERCENT,
|
|
267
|
+
vote_pct: int = HIVE_100_PERCENT,
|
|
268
|
+
not_broadcasted_vote: bool = True,
|
|
269
|
+
use_stored_data: bool = True,
|
|
270
|
+
) -> float:
|
|
271
|
+
"""
|
|
272
|
+
Convert token power (Hive Power) to its token-backed dollar equivalent (HBD).
|
|
273
|
+
|
|
274
|
+
Parameters:
|
|
275
|
+
token_power: Hive Power amount (numeric or Amount-like) to convert.
|
|
276
|
+
post_rshares (int): Optional existing rshares on the post to include when estimating payout.
|
|
277
|
+
voting_power (int): Voter's current voting power (use HIVE_100_PERCENT for full power).
|
|
278
|
+
vote_pct (int): Vote weight to apply (use HIVE_100_PERCENT for 100%).
|
|
279
|
+
not_broadcasted_vote (bool): If True, include the vote as not-yet-broadcasted when computing reward pool effects.
|
|
280
|
+
use_stored_data (bool): If True, prefer cached chain data when available.
|
|
281
|
+
|
|
282
|
+
Returns:
|
|
283
|
+
The estimated HBD value (token-backed dollar) corresponding to the provided token power.
|
|
284
|
+
"""
|
|
285
|
+
return self.hp_to_hbd(
|
|
286
|
+
token_power,
|
|
287
|
+
post_rshares=post_rshares,
|
|
288
|
+
voting_power=voting_power,
|
|
289
|
+
vote_pct=vote_pct,
|
|
290
|
+
not_broadcasted_vote=not_broadcasted_vote,
|
|
291
|
+
use_stored_data=use_stored_data,
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
def hp_to_hbd(
|
|
295
|
+
self,
|
|
296
|
+
hp: Union[Amount, float],
|
|
297
|
+
post_rshares: int = 0,
|
|
298
|
+
voting_power: int = HIVE_100_PERCENT,
|
|
299
|
+
vote_pct: int = HIVE_100_PERCENT,
|
|
300
|
+
not_broadcasted_vote: bool = True,
|
|
301
|
+
use_stored_data: bool = True,
|
|
302
|
+
) -> float:
|
|
303
|
+
"""
|
|
304
|
+
Convert Hive Power (HP) to the estimated HBD payout this vote would produce.
|
|
305
|
+
|
|
306
|
+
Parameters:
|
|
307
|
+
hp (number): Amount of Hive Power to convert.
|
|
308
|
+
post_rshares (int): Current post rshares to include when computing marginal effect of this vote.
|
|
309
|
+
voting_power (int): Voter's current voting power (100% = 10000).
|
|
310
|
+
vote_pct (int): Vote percentage to apply (100% = 10000).
|
|
311
|
+
not_broadcasted_vote (bool): If True, treat the vote as not yet broadcast — the function will account for the vote reducing the available reward pool when applicable.
|
|
312
|
+
use_stored_data (bool): If True, use cached chain/state data when available.
|
|
313
|
+
|
|
314
|
+
Returns:
|
|
315
|
+
HBD value corresponding to the provided HP under the current reward pool and price conditions (same type/format as the library's Amount/HBD results).
|
|
316
|
+
"""
|
|
317
|
+
vesting_shares = int(self.hp_to_vests(hp, use_stored_data=use_stored_data))
|
|
318
|
+
return self.vests_to_hbd(
|
|
319
|
+
vesting_shares,
|
|
320
|
+
post_rshares=post_rshares,
|
|
321
|
+
voting_power=voting_power,
|
|
322
|
+
vote_pct=vote_pct,
|
|
323
|
+
not_broadcasted_vote=not_broadcasted_vote,
|
|
324
|
+
use_stored_data=use_stored_data,
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
def vests_to_hbd(
|
|
328
|
+
self,
|
|
329
|
+
vests: Union[Amount, float],
|
|
330
|
+
post_rshares: int = 0,
|
|
331
|
+
voting_power: int = HIVE_100_PERCENT,
|
|
332
|
+
vote_pct: int = HIVE_100_PERCENT,
|
|
333
|
+
not_broadcasted_vote: bool = True,
|
|
334
|
+
use_stored_data: bool = True,
|
|
335
|
+
) -> float:
|
|
336
|
+
"""
|
|
337
|
+
Convert vesting shares to their equivalent HBD payout for a single vote.
|
|
338
|
+
|
|
339
|
+
Given vesting shares, computes the vote's r-shares (taking into account post r-shares,
|
|
340
|
+
voter power and percentage) and converts that r-shares value to an HBD payout.
|
|
341
|
+
|
|
342
|
+
Parameters:
|
|
343
|
+
vests: Vesting shares to use for the vote (number or Amount-like).
|
|
344
|
+
post_rshares (int): Existing r-shares of the post being voted on; affects the r-shares calculation.
|
|
345
|
+
voting_power (int): Voter's current voting power (units where 100% == HIVE_100_PERCENT).
|
|
346
|
+
vote_pct (int): Vote percentage to apply (units where 100% == HIVE_100_PERCENT).
|
|
347
|
+
not_broadcasted_vote (bool): If True, treat this as a not-yet-broadcast vote (it reduces the effective reward pool);
|
|
348
|
+
if False, treat as already-applied (affects conversion math for very large votes).
|
|
349
|
+
use_stored_data (bool): Whether to use cached chain parameters/reward state or query fresh data.
|
|
350
|
+
|
|
351
|
+
Returns:
|
|
352
|
+
The estimated HBD value (same type returned by rshares_to_hbd) for the vote.
|
|
353
|
+
"""
|
|
354
|
+
vote_rshares = self.vests_to_rshares(
|
|
355
|
+
vests, post_rshares=post_rshares, voting_power=voting_power, vote_pct=vote_pct
|
|
356
|
+
)
|
|
357
|
+
return self.rshares_to_hbd(
|
|
358
|
+
vote_rshares, not_broadcasted_vote=not_broadcasted_vote, use_stored_data=use_stored_data
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
def hp_to_rshares(
|
|
362
|
+
self,
|
|
363
|
+
hive_power: Union[Amount, float],
|
|
364
|
+
post_rshares: int = 0,
|
|
365
|
+
voting_power: int = HIVE_100_PERCENT,
|
|
366
|
+
vote_pct: int = HIVE_100_PERCENT,
|
|
367
|
+
use_stored_data: bool = True,
|
|
368
|
+
) -> float:
|
|
369
|
+
"""
|
|
370
|
+
Convert Hive Power (HP) to r-shares used for voting.
|
|
371
|
+
|
|
372
|
+
Given a Hive Power amount, computes the equivalent vesting shares and then the r-shares that a vote with the specified voting_power and vote_pct would produce against a post that currently has post_rshares. `voting_power` and `vote_pct` use the chain-normalized scale (100% == HIVE_100_PERCENT).
|
|
373
|
+
|
|
374
|
+
Parameters:
|
|
375
|
+
hive_power (number): Hive Power (HP) value to convert.
|
|
376
|
+
post_rshares (int, optional): Current r-shares of the post being voted on; used to adjust the resulting r-shares. Defaults to 0.
|
|
377
|
+
voting_power (int, optional): Voter's current voting power on the HIVE_100_PERCENT scale. Defaults to HIVE_100_PERCENT.
|
|
378
|
+
vote_pct (int, optional): Vote percentage to apply on the HIVE_100_PERCENT scale. Defaults to HIVE_100_PERCENT.
|
|
379
|
+
use_stored_data (bool, optional): Whether to use cached chain data when performing conversions. Defaults to True.
|
|
380
|
+
|
|
381
|
+
Returns:
|
|
382
|
+
int: The computed r-shares produced by the specified vote.
|
|
383
|
+
"""
|
|
384
|
+
# calculate our account voting shares (from vests)
|
|
385
|
+
vesting_shares = int(self.hp_to_vests(hive_power, use_stored_data=use_stored_data))
|
|
386
|
+
rshares = self.vests_to_rshares(
|
|
387
|
+
vesting_shares,
|
|
388
|
+
post_rshares=post_rshares,
|
|
389
|
+
voting_power=voting_power,
|
|
390
|
+
vote_pct=vote_pct,
|
|
391
|
+
use_stored_data=use_stored_data,
|
|
392
|
+
)
|
|
393
|
+
return rshares
|
|
394
|
+
|
|
395
|
+
def hbd_to_rshares(
|
|
396
|
+
self,
|
|
397
|
+
hbd: Union[str, int, Amount],
|
|
398
|
+
not_broadcasted_vote: bool = False,
|
|
399
|
+
use_stored_data: bool = True,
|
|
400
|
+
) -> float:
|
|
401
|
+
"""Obtain the r-shares from HBD
|
|
402
|
+
|
|
403
|
+
:param hbd: HBD
|
|
404
|
+
:type hbd: str, int, amount.Amount
|
|
405
|
+
:param bool not_broadcasted_vote: not_broadcasted or already broadcasted vote (True = not_broadcasted vote).
|
|
406
|
+
Only impactful for very high amounts of HBD. Slight modification to the value calculation, as the not_broadcasted
|
|
407
|
+
vote rshares decreases the reward pool.
|
|
408
|
+
|
|
409
|
+
"""
|
|
410
|
+
if isinstance(hbd, Amount):
|
|
411
|
+
hbd = Amount(hbd, blockchain_instance=self)
|
|
412
|
+
elif isinstance(hbd, str):
|
|
413
|
+
hbd = Amount(hbd, blockchain_instance=self)
|
|
414
|
+
else:
|
|
415
|
+
hbd = Amount(hbd, self.hbd_symbol, blockchain_instance=self)
|
|
416
|
+
if hbd["symbol"] != self.hbd_symbol:
|
|
417
|
+
raise AssertionError("Should input HBD, not any other asset!")
|
|
418
|
+
|
|
419
|
+
# If the vote was already broadcasted we can assume the blockchain values to be true
|
|
420
|
+
if not not_broadcasted_vote:
|
|
421
|
+
return int(float(hbd) / self.get_hbd_per_rshares(use_stored_data=use_stored_data))
|
|
422
|
+
|
|
423
|
+
# If the vote wasn't broadcasted (yet), we have to calculate the rshares while considering
|
|
424
|
+
# the change our vote is causing to the recent_claims. This is more important for really
|
|
425
|
+
# big votes which have a significant impact on the recent_claims.
|
|
426
|
+
reward_fund = self.get_reward_funds(use_stored_data=use_stored_data)
|
|
427
|
+
median_price = self.get_median_price(use_stored_data=use_stored_data)
|
|
428
|
+
if (
|
|
429
|
+
not reward_fund
|
|
430
|
+
or not isinstance(reward_fund, dict)
|
|
431
|
+
or not median_price
|
|
432
|
+
or (isinstance(median_price, dict) and not isinstance(median_price, Price))
|
|
433
|
+
):
|
|
434
|
+
return int(float(hbd) / self.get_hbd_per_rshares(use_stored_data=use_stored_data))
|
|
435
|
+
recent_claims = int(reward_fund["recent_claims"])
|
|
436
|
+
reward_balance = Amount(reward_fund["reward_balance"], blockchain_instance=self)
|
|
437
|
+
reward_pool_hbd = median_price * reward_balance
|
|
438
|
+
if hbd > reward_pool_hbd:
|
|
439
|
+
raise ValueError("Provided more HBD than available in the reward pool.")
|
|
440
|
+
|
|
441
|
+
# This is the formula we can use to determine the "true" rshares.
|
|
442
|
+
# We get this formula by some math magic using the previous used formulas
|
|
443
|
+
# FundsPerShare = (balance / (claims + newShares)) * Price
|
|
444
|
+
# newShares = amount / FundsPerShare
|
|
445
|
+
# We can now resolve both formulas for FundsPerShare and set the formulas to be equal
|
|
446
|
+
# (balance / (claims + newShares)) * price = amount / newShares
|
|
447
|
+
# Now we resolve for newShares resulting in:
|
|
448
|
+
# newShares = claims * amount / (balance * price - amount)
|
|
449
|
+
rshares = (
|
|
450
|
+
recent_claims
|
|
451
|
+
* float(hbd)
|
|
452
|
+
/ ((float(reward_balance) * float(median_price)) - float(hbd))
|
|
453
|
+
)
|
|
454
|
+
return int(rshares)
|
|
455
|
+
|
|
456
|
+
def rshares_to_vote_pct(
|
|
457
|
+
self,
|
|
458
|
+
rshares: Union[int, float],
|
|
459
|
+
post_rshares: int = 0,
|
|
460
|
+
hive_power: Optional[Union[Amount, float]] = None,
|
|
461
|
+
vests: Optional[Union[Amount, float]] = None,
|
|
462
|
+
voting_power: int = HIVE_100_PERCENT,
|
|
463
|
+
use_stored_data: bool = True,
|
|
464
|
+
) -> float:
|
|
465
|
+
"""
|
|
466
|
+
Compute the voting percentage required to achieve a target r-shares value.
|
|
467
|
+
|
|
468
|
+
Given a desired r-shares (positive for upvotes, negative for downvotes) and either
|
|
469
|
+
hive_power or vests (exactly one must be provided), return the voting percentage
|
|
470
|
+
where 100% = 10000. The calculation accounts for post-vote r-shares adjustments,
|
|
471
|
+
current dust-threshold behavior (post-hardfork), and the configured voting power.
|
|
472
|
+
|
|
473
|
+
Parameters:
|
|
474
|
+
rshares (int | float): Target r-shares value (signed).
|
|
475
|
+
post_rshares (int, optional): R-shares already present on the post (positive
|
|
476
|
+
for existing upvotes, negative for downvotes). Defaults to 0.
|
|
477
|
+
hive_power (float, optional): Hive Power to use for the calculation. Provide
|
|
478
|
+
this or `vests`, not both. If given, it is converted to vesting shares.
|
|
479
|
+
vests (int, optional): Vesting shares (in micro-vests, i.e., vest*1e6). Provide
|
|
480
|
+
this or `hive_power`, not both.
|
|
481
|
+
voting_power (int, optional): Voter's current voting power where 100% = 10000.
|
|
482
|
+
Defaults to HIVE_100_PERCENT.
|
|
483
|
+
use_stored_data (bool, optional): Whether to use cached chain properties when
|
|
484
|
+
available. Defaults to True.
|
|
485
|
+
|
|
486
|
+
Returns:
|
|
487
|
+
int: Signed voting percentage required (100% = 10000). The sign matches the
|
|
488
|
+
sign of `rshares`.
|
|
489
|
+
|
|
490
|
+
Raises:
|
|
491
|
+
ValueError: If neither or both of `hive_power` and `vests` are provided.
|
|
492
|
+
"""
|
|
493
|
+
if hive_power is None and vests is None:
|
|
494
|
+
raise ValueError("Either hive_power or vests has to be set!")
|
|
495
|
+
if hive_power is not None and vests is not None:
|
|
496
|
+
raise ValueError("Either hive_power or vests has to be set. Not both!")
|
|
497
|
+
if hive_power is not None:
|
|
498
|
+
vests_value = self.hp_to_vests(hive_power, use_stored_data=use_stored_data)
|
|
499
|
+
vests = int(vests_value) if vests_value is not None else 0
|
|
500
|
+
|
|
501
|
+
# Parse version as tuple for reliable comparison
|
|
502
|
+
version_parts = self.hardfork.split(".")
|
|
503
|
+
try:
|
|
504
|
+
major, minor = int(version_parts[0]), int(version_parts[1]) if len(version_parts) > 1 else 0
|
|
505
|
+
except (ValueError, IndexError):
|
|
506
|
+
major, minor = 1, 20 # Default to current behavior
|
|
507
|
+
if (major, minor) >= (1, 20):
|
|
508
|
+
rshares += math.copysign(
|
|
509
|
+
self.get_dust_threshold(use_stored_data=use_stored_data), rshares
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
if post_rshares >= 0 and rshares > 0:
|
|
513
|
+
rshares = math.copysign(
|
|
514
|
+
self._calc_revert_vote_claim(abs(rshares), post_rshares), rshares
|
|
515
|
+
)
|
|
516
|
+
elif post_rshares < 0 and rshares < 0:
|
|
517
|
+
rshares = math.copysign(
|
|
518
|
+
self._calc_revert_vote_claim(abs(rshares), abs(post_rshares)), rshares
|
|
519
|
+
)
|
|
520
|
+
elif post_rshares < 0 and rshares > 0:
|
|
521
|
+
rshares = math.copysign(self._calc_revert_vote_claim(abs(rshares), 0), rshares)
|
|
522
|
+
elif post_rshares > 0 and rshares < 0:
|
|
523
|
+
rshares = math.copysign(
|
|
524
|
+
self._calc_revert_vote_claim(abs(rshares), post_rshares), rshares
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
# Invert the chain-accurate power model used above:
|
|
528
|
+
# rshares ≈ sign * (vests*1e6 * used_power / HIVE_100_PERCENT)
|
|
529
|
+
# used_power ≈ abs(rshares) * HIVE_100_PERCENT / (vests*1e6)
|
|
530
|
+
# and used_power ≈ ceil((voting_power * abs(vote_pct) / HIVE_100_PERCENT * 86400) / max_vote_denom)
|
|
531
|
+
if vests == 0 or voting_power == 0:
|
|
532
|
+
return 0
|
|
533
|
+
max_vote_denom = self._max_vote_denom(use_stored_data=use_stored_data)
|
|
534
|
+
vests_value = vests if vests is not None else 0
|
|
535
|
+
used_power_est = (abs(rshares) * HIVE_100_PERCENT) / (vests_value * 1e6)
|
|
536
|
+
# Invert the linear relation (ignoring ceil):
|
|
537
|
+
vote_pct_abs = used_power_est * max_vote_denom * HIVE_100_PERCENT / (86400 * voting_power)
|
|
538
|
+
return round(math.copysign(vote_pct_abs, rshares))
|
|
539
|
+
|
|
540
|
+
def hbd_to_vote_pct(
|
|
541
|
+
self,
|
|
542
|
+
hbd: Union[str, int, Amount],
|
|
543
|
+
post_rshares: int = 0,
|
|
544
|
+
hive_power: Optional[Union[Amount, float]] = None,
|
|
545
|
+
vests: Optional[Union[Amount, float]] = None,
|
|
546
|
+
voting_power: int = HIVE_100_PERCENT,
|
|
547
|
+
not_broadcasted_vote: bool = True,
|
|
548
|
+
use_stored_data: bool = True,
|
|
549
|
+
) -> float:
|
|
550
|
+
"""
|
|
551
|
+
Calculate the voting percentage required to achieve a target HBD payout for a given voting power and stake.
|
|
552
|
+
|
|
553
|
+
Given a desired HBD amount, this returns the vote percentage (100% == 10000) that, when applied from the provided Hive Power or vesting shares, would produce approximately that payout. Exactly one of `hive_power` or `vests` must be provided.
|
|
554
|
+
|
|
555
|
+
Parameters:
|
|
556
|
+
hbd (str|int|Amount): Desired HBD payout. Accepts an Amount, numeric value, or asset string; will be converted to an Amount in the chain's HBD symbol.
|
|
557
|
+
hive_power (number, optional): Voter's Hive Power. Mutually exclusive with `vests`.
|
|
558
|
+
vests (number, optional): Voter's vesting shares. Mutually exclusive with `hive_power`.
|
|
559
|
+
voting_power (int, optional): Current voting power normalization constant (default HIVE_100_PERCENT).
|
|
560
|
+
not_broadcasted_vote (bool, optional): If True, treat the vote as not yet broadcast; this slightly changes calculations for very large HBD amounts because an unbroadcasted vote reduces the available reward pool.
|
|
561
|
+
post_rshares (int, optional): rshares already present on the post (used when calculating required vote to reach a target).
|
|
562
|
+
use_stored_data (bool, optional): Use cached chain properties when available.
|
|
563
|
+
|
|
564
|
+
Returns:
|
|
565
|
+
int: Required vote percentage where 100% == 10000. Values >10000 or < -10000 indicate the requested HBD is too large for a single vote.
|
|
566
|
+
|
|
567
|
+
Raises:
|
|
568
|
+
AssertionError: If the provided `hbd` cannot be interpreted as the chain's HBD asset.
|
|
569
|
+
"""
|
|
570
|
+
if isinstance(hbd, Amount):
|
|
571
|
+
hbd = Amount(hbd, blockchain_instance=self)
|
|
572
|
+
elif isinstance(hbd, str):
|
|
573
|
+
hbd = Amount(hbd, blockchain_instance=self)
|
|
574
|
+
else:
|
|
575
|
+
hbd = Amount(hbd, self.hbd_symbol, blockchain_instance=self)
|
|
576
|
+
if hbd["symbol"] != self.hbd_symbol:
|
|
577
|
+
raise AssertionError()
|
|
578
|
+
rshares = self.hbd_to_rshares(
|
|
579
|
+
hbd, not_broadcasted_vote=not_broadcasted_vote, use_stored_data=use_stored_data
|
|
580
|
+
)
|
|
581
|
+
return self.rshares_to_vote_pct(
|
|
582
|
+
rshares,
|
|
583
|
+
post_rshares=post_rshares,
|
|
584
|
+
hive_power=hive_power,
|
|
585
|
+
vests=vests,
|
|
586
|
+
voting_power=voting_power,
|
|
587
|
+
use_stored_data=use_stored_data,
|
|
588
|
+
)
|
|
589
|
+
|
|
590
|
+
@property
|
|
591
|
+
def chain_params(self) -> Optional[Dict[str, Any]]:
|
|
592
|
+
if self.offline or self.rpc is None:
|
|
593
|
+
return known_chains["HIVE"]
|
|
594
|
+
else:
|
|
595
|
+
return self.get_network()
|
|
596
|
+
|
|
597
|
+
@property
|
|
598
|
+
def hardfork(self) -> str:
|
|
599
|
+
if self.offline or self.rpc is None:
|
|
600
|
+
versions = known_chains["HIVE"]["min_version"]
|
|
601
|
+
else:
|
|
602
|
+
hf_prop = self.get_hardfork_properties()
|
|
603
|
+
if hf_prop and isinstance(hf_prop, dict) and "current_hardfork_version" in hf_prop:
|
|
604
|
+
versions = hf_prop["current_hardfork_version"]
|
|
605
|
+
else:
|
|
606
|
+
versions = known_chains["HIVE"]["min_version"]
|
|
607
|
+
return versions
|
|
608
|
+
|
|
609
|
+
@property
|
|
610
|
+
def is_hive(self) -> bool:
|
|
611
|
+
return True
|
|
612
|
+
|
|
613
|
+
@property
|
|
614
|
+
def hbd_symbol(self) -> str:
|
|
615
|
+
params = self.chain_params
|
|
616
|
+
if params and isinstance(params, dict):
|
|
617
|
+
return params.get("backed_token_symbol", "HBD")
|
|
618
|
+
return "HBD"
|
|
619
|
+
|
|
620
|
+
@property
|
|
621
|
+
def hive_symbol(self) -> str:
|
|
622
|
+
params = self.chain_params
|
|
623
|
+
if params and isinstance(params, dict):
|
|
624
|
+
return params.get("token_symbol", "HIVE")
|
|
625
|
+
return "HIVE"
|
|
626
|
+
|
|
627
|
+
@property
|
|
628
|
+
def vests_symbol(self) -> str:
|
|
629
|
+
"""get the current chains symbol for VESTS"""
|
|
630
|
+
return self.vest_token_symbol
|