hive-nectar 0.0.10__py3-none-any.whl → 0.1.0__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.

Potentially problematic release.


This version of hive-nectar might be problematic. Click here for more details.

Files changed (56) hide show
  1. {hive_nectar-0.0.10.dist-info → hive_nectar-0.1.0.dist-info}/METADATA +10 -11
  2. hive_nectar-0.1.0.dist-info/RECORD +88 -0
  3. nectar/__init__.py +1 -4
  4. nectar/account.py +791 -685
  5. nectar/amount.py +82 -21
  6. nectar/asset.py +1 -2
  7. nectar/block.py +34 -22
  8. nectar/blockchain.py +111 -143
  9. nectar/blockchaininstance.py +396 -247
  10. nectar/blockchainobject.py +33 -5
  11. nectar/cli.py +1058 -1349
  12. nectar/comment.py +317 -182
  13. nectar/community.py +39 -43
  14. nectar/constants.py +1 -14
  15. nectar/discussions.py +793 -139
  16. nectar/hive.py +137 -77
  17. nectar/hivesigner.py +106 -68
  18. nectar/imageuploader.py +33 -23
  19. nectar/instance.py +31 -79
  20. nectar/market.py +128 -264
  21. nectar/memo.py +40 -13
  22. nectar/message.py +23 -10
  23. nectar/nodelist.py +118 -82
  24. nectar/price.py +80 -61
  25. nectar/profile.py +6 -3
  26. nectar/rc.py +45 -25
  27. nectar/snapshot.py +285 -163
  28. nectar/storage.py +16 -5
  29. nectar/transactionbuilder.py +132 -41
  30. nectar/utils.py +37 -17
  31. nectar/version.py +1 -1
  32. nectar/vote.py +171 -30
  33. nectar/wallet.py +26 -19
  34. nectar/witness.py +153 -54
  35. nectarapi/graphenerpc.py +147 -133
  36. nectarapi/noderpc.py +12 -6
  37. nectarapi/rpcutils.py +12 -6
  38. nectarapi/version.py +1 -1
  39. nectarbase/ledgertransactions.py +24 -1
  40. nectarbase/objects.py +17 -6
  41. nectarbase/operations.py +160 -90
  42. nectarbase/signedtransactions.py +38 -2
  43. nectarbase/version.py +1 -1
  44. nectargraphenebase/account.py +295 -17
  45. nectargraphenebase/chains.py +0 -135
  46. nectargraphenebase/ecdsasig.py +152 -176
  47. nectargraphenebase/types.py +18 -4
  48. nectargraphenebase/unsignedtransactions.py +1 -1
  49. nectargraphenebase/version.py +1 -1
  50. hive_nectar-0.0.10.dist-info/RECORD +0 -91
  51. nectar/blurt.py +0 -562
  52. nectar/conveyor.py +0 -308
  53. nectar/steem.py +0 -581
  54. {hive_nectar-0.0.10.dist-info → hive_nectar-0.1.0.dist-info}/WHEEL +0 -0
  55. {hive_nectar-0.0.10.dist-info → hive_nectar-0.1.0.dist-info}/entry_points.txt +0 -0
  56. {hive_nectar-0.0.10.dist-info → hive_nectar-0.1.0.dist-info}/licenses/LICENSE.txt +0 -0
nectar/comment.py CHANGED
@@ -5,9 +5,10 @@ import math
5
5
  from datetime import date, datetime, timezone
6
6
 
7
7
  from nectar.constants import (
8
- STEEM_REVERSE_AUCTION_WINDOW_SECONDS_HF6,
9
- STEEM_REVERSE_AUCTION_WINDOW_SECONDS_HF20,
10
- STEEM_REVERSE_AUCTION_WINDOW_SECONDS_HF21,
8
+ HIVE_100_PERCENT,
9
+ HIVE_REVERSE_AUCTION_WINDOW_SECONDS_HF6,
10
+ HIVE_REVERSE_AUCTION_WINDOW_SECONDS_HF20,
11
+ HIVE_REVERSE_AUCTION_WINDOW_SECONDS_HF21,
11
12
  )
12
13
  from nectarbase import operations
13
14
 
@@ -34,16 +35,17 @@ class Comment(BlockchainObject):
34
35
  :param str authorperm: identifier to post/comment in the form of
35
36
  ``@author/permlink``
36
37
  :param str tags: defines which api is used. Can be bridge, tags, condenser or database (default = bridge)
37
- :param Hive blockchain_instance: :class:`nectar.hive.Steem` instance to use when accessing a RPC
38
+ :param Blockchain blockchain_instance: Blockchain instance to use when accessing the RPC
38
39
 
39
40
 
40
41
  .. code-block:: python
41
42
 
42
43
  >>> from nectar.comment import Comment
43
44
  >>> from nectar.account import Account
44
- >>> from nectar import Steem
45
- >>> stm = Steem()
46
- >>> acc = Account("gtg", blockchain_instance=stm)
45
+ >>> # Create a Hive blockchain instance
46
+ >>> from nectar.blockchain import Blockchain as Hive
47
+ >>> hv = Hive()
48
+ >>> acc = Account("gtg", blockchain_instance=hv)
47
49
  >>> authorperm = acc.get_blog(limit=1)[0]["authorperm"]
48
50
  >>> c = Comment(authorperm)
49
51
  >>> postdate = c["created"]
@@ -61,17 +63,25 @@ class Comment(BlockchainObject):
61
63
  full=True,
62
64
  lazy=False,
63
65
  blockchain_instance=None,
64
- **kwargs,
65
66
  ):
67
+ """
68
+ Create a Comment object representing a Hive post or comment.
69
+
70
+ Supports initializing from either an author/permlink string ("author/permlink") or a dict containing at least "author" and "permlink". For a string input the constructor resolves and stores author, permlink, and authorperm. For a dict input the constructor normalizes the dict via _parse_json_data (timestamps, amounts, metadata) and sets the canonical "authorperm" before delegating to the BlockchainObject constructor.
71
+
72
+ Parameters:
73
+ authorperm: Either an "author/permlink" string or a dict with "author" and "permlink".
74
+ api: RPC bridge to use (defaults to "bridge"); stored on the instance.
75
+ observer: Optional observer identifier stored on the instance.
76
+ full: If True, load all fields immediately; if False, allow partial/lazy loading.
77
+ lazy: If True, delay full object loading until needed.
78
+
79
+ Note: The blockchain instance is taken from blockchain_instance (if provided) or the module's shared_blockchain_instance(). The constructor sets instance attributes and then calls the parent initializer with id_item="authorperm".
80
+ """
66
81
  self.full = full
67
82
  self.lazy = lazy
68
83
  self.api = api
69
84
  self.observer = observer
70
- if blockchain_instance is None:
71
- if kwargs.get("steem_instance"):
72
- blockchain_instance = kwargs["steem_instance"]
73
- elif kwargs.get("hive_instance"):
74
- blockchain_instance = kwargs["hive_instance"]
75
85
  self.blockchain = blockchain_instance or shared_blockchain_instance()
76
86
  if isinstance(authorperm, str) and authorperm != "":
77
87
  [author, permlink] = resolve_authorperm(authorperm)
@@ -89,10 +99,26 @@ class Comment(BlockchainObject):
89
99
  id_item="authorperm",
90
100
  lazy=lazy,
91
101
  full=full,
92
- blockchain_instance=blockchain_instance,
102
+ blockchain_instance=self.blockchain,
93
103
  )
94
104
 
95
105
  def _parse_json_data(self, comment):
106
+ """
107
+ Normalize and convert raw comment JSON fields into Python-native types.
108
+
109
+ This parses and mutates the given comment dict in-place and returns it. Normalizations:
110
+ - Converts known timestamp strings (e.g., "created", "last_update", "cashout_time") to datetime using formatTimeString.
111
+ - Converts monetary fields backed by the chain's backed token (HBD) into Amount objects using the instance's backed_token_symbol.
112
+ - Ensures a "community" key exists and parses `json_metadata` (string/bytes) into a dict; extracts `tags` and `community` from that metadata when present.
113
+ - Converts numeric string fields like `author_reputation` and `net_rshares` to ints.
114
+ - Normalizes each entry in `active_votes`: converts vote `time` to datetime and numeric strings (`rshares`, `reputation`) to ints (falling back to 0 on parse errors).
115
+
116
+ Parameters:
117
+ comment (dict): Raw comment/post data as returned by the node RPC.
118
+
119
+ Returns:
120
+ dict: The same comment dict with normalized fields (timestamps as datetimes, amounts as Amount objects, json_metadata as dict, numeric fields as ints).
121
+ """
96
122
  parse_times = [
97
123
  "active",
98
124
  "cashout_time",
@@ -106,7 +132,7 @@ class Comment(BlockchainObject):
106
132
  if p in comment and isinstance(comment.get(p), str):
107
133
  comment[p] = formatTimeString(comment.get(p, "1970-01-01T00:00:00"))
108
134
  # Parse Amounts
109
- sbd_amounts = [
135
+ hbd_amounts = [
110
136
  "total_payout_value",
111
137
  "max_accepted_payout",
112
138
  "pending_payout_value",
@@ -114,7 +140,7 @@ class Comment(BlockchainObject):
114
140
  "total_pending_payout_value",
115
141
  "promoted",
116
142
  ]
117
- for p in sbd_amounts:
143
+ for p in hbd_amounts:
118
144
  if p in comment and isinstance(comment.get(p), (str, list, dict)):
119
145
  value = comment.get(p, "0.000 %s" % (self.blockchain.backed_token_symbol))
120
146
  if (
@@ -124,6 +150,9 @@ class Comment(BlockchainObject):
124
150
  value = value.split(" ")[0] + " " + self.blockchain.backed_token_symbol
125
151
  comment[p] = Amount(value, blockchain_instance=self.blockchain)
126
152
 
153
+ if "community" not in comment:
154
+ comment["community"] = ""
155
+
127
156
  # turn json_metadata into python dict
128
157
  meta_str = comment.get("json_metadata", "{}")
129
158
  if meta_str == "{}":
@@ -138,7 +167,7 @@ class Comment(BlockchainObject):
138
167
  if isinstance(comment["json_metadata"], dict):
139
168
  if "tags" in comment["json_metadata"]:
140
169
  comment["tags"] = comment["json_metadata"]["tags"]
141
- if "community" in comment["json_metadata"] and not comment["community"]:
170
+ if "community" in comment["json_metadata"]:
142
171
  comment["community"] = comment["json_metadata"]["community"]
143
172
 
144
173
  parse_int = [
@@ -223,6 +252,19 @@ class Comment(BlockchainObject):
223
252
  )
224
253
 
225
254
  def json(self):
255
+ """
256
+ Return a JSON-serializable dict representation of the Comment.
257
+
258
+ Removes internal-only keys (e.g., "authorperm", "tags"), ensures json-compatible types, and normalizes several fields so the result can be safely serialized to JSON and consumed by external callers or APIs. Normalizations performed:
259
+ - Serializes `json_metadata` to a compact JSON string.
260
+ - Converts datetime/date values in fields like "created", "updated", "last_payout", "cashout_time", "active", and "max_cashout_time" to formatted time strings.
261
+ - Converts Amount instances in HBD-related fields (e.g., "total_payout_value", "pending_payout_value", "curator_payout_value", "promoted", etc.) to their JSON representation via Amount.json().
262
+ - Converts selected integer fields ("author_reputation", "net_rshares") and vote numeric fields ("rshares", "reputation") to strings to preserve precision across transports.
263
+ - Normalizes times and numeric fields inside each entry of "active_votes".
264
+
265
+ Returns:
266
+ dict: A JSON-safe copy of the comment data suitable for json.dumps or returning from an API.
267
+ """
226
268
  output = self.copy()
227
269
  if "authorperm" in output:
228
270
  output.pop("authorperm")
@@ -246,7 +288,7 @@ class Comment(BlockchainObject):
246
288
  output[p] = formatTimeString(p_date)
247
289
  else:
248
290
  output[p] = p_date
249
- sbd_amounts = [
291
+ hbd_amounts = [
250
292
  "total_payout_value",
251
293
  "max_accepted_payout",
252
294
  "pending_payout_value",
@@ -254,7 +296,7 @@ class Comment(BlockchainObject):
254
296
  "total_pending_payout_value",
255
297
  "promoted",
256
298
  ]
257
- for p in sbd_amounts:
299
+ for p in hbd_amounts:
258
300
  if p in output and isinstance(output[p], Amount):
259
301
  output[p] = output[p].json()
260
302
  parse_int = [
@@ -377,7 +419,16 @@ class Comment(BlockchainObject):
377
419
 
378
420
  @property
379
421
  def reward(self):
380
- """Return the estimated total SBD reward."""
422
+ """
423
+ Return the post's total estimated reward as an Amount.
424
+
425
+ This is the sum of `total_payout_value`, `curator_payout_value`, and `pending_payout_value`
426
+ (from the comment data). Each component is converted to an Amount using the comment's
427
+ blockchain-backed token symbol before summing.
428
+
429
+ Returns:
430
+ Amount: Total estimated reward (in the blockchain's backed token, e.g., HBD).
431
+ """
381
432
  a_zero = Amount(0, self.blockchain.backed_token_symbol, blockchain_instance=self.blockchain)
382
433
  author = Amount(self.get("total_payout_value", a_zero), blockchain_instance=self.blockchain)
383
434
  curator = Amount(
@@ -398,52 +449,74 @@ class Comment(BlockchainObject):
398
449
  return post_age_days < 7.0 and float(total) == 0
399
450
 
400
451
  def time_elapsed(self):
401
- """Returns a timedelta on how old the post is."""
452
+ """
453
+ Return the time elapsed since the post was created as a timedelta.
454
+
455
+ The difference is computed as now (UTC) minus the post's `created` timestamp (a timezone-aware datetime).
456
+ A positive timedelta indicates the post is in the past; a negative value can occur if `created` is in the future.
457
+ """
402
458
  return datetime.now(timezone.utc) - self["created"]
403
459
 
404
- def curation_penalty_compensation_SBD(self):
405
- """Returns The required post payout amount after 15 minutes
406
- which will compentsate the curation penalty, if voting earlier than 15 minutes
460
+ def curation_penalty_compensation_hbd(self):
461
+ """
462
+ Calculate the HBD payout a post would need (after 15 minutes) to fully compensate the curation penalty for voting earlier than 15 minutes.
463
+
464
+ This refreshes the comment data, selects the reverse-auction window based on the blockchain hardfork (HF6/HF20/HF21), and computes the required payout using the post's current reward and age.
465
+
466
+ Returns:
467
+ Amount: Estimated HBD payout required to offset the early-vote curation penalty.
407
468
  """
408
469
  self.refresh()
409
- if self.blockchain.hardfork >= 21:
410
- reverse_auction_window_seconds = STEEM_REVERSE_AUCTION_WINDOW_SECONDS_HF21
411
- elif self.blockchain.hardfork >= 20:
412
- reverse_auction_window_seconds = STEEM_REVERSE_AUCTION_WINDOW_SECONDS_HF20
470
+ if self.blockchain.hardfork() >= 21:
471
+ reverse_auction_window_seconds = HIVE_REVERSE_AUCTION_WINDOW_SECONDS_HF21
472
+ elif self.blockchain.hardfork() >= 20:
473
+ reverse_auction_window_seconds = HIVE_REVERSE_AUCTION_WINDOW_SECONDS_HF20
413
474
  else:
414
- reverse_auction_window_seconds = STEEM_REVERSE_AUCTION_WINDOW_SECONDS_HF6
415
- return (
416
- self.reward
417
- * reverse_auction_window_seconds
418
- / ((self.time_elapsed()).total_seconds() / 60) ** 2
419
- )
475
+ reverse_auction_window_seconds = HIVE_REVERSE_AUCTION_WINDOW_SECONDS_HF6
476
+ elapsed_minutes = max((self.time_elapsed()).total_seconds() / 60, 1e-6)
477
+ return self.reward * reverse_auction_window_seconds / (elapsed_minutes**2)
478
+
479
+ def estimate_curation_hbd(self, vote_value_hbd, estimated_value_hbd=None):
480
+ """
481
+ Estimate the curation reward (in HBD) for a given vote on this post.
482
+
483
+ Refreshes the post data from the chain before computing. If `estimated_value_hbd` is not provided, the current post reward is used as the estimated total post value. The returned value is an estimate of the curator's HBD payout for a vote of size `vote_value_hbd`, accounting for the current curation penalty.
420
484
 
421
- def estimate_curation_SBD(self, vote_value_SBD, estimated_value_SBD=None):
422
- """Estimates curation reward
485
+ Parameters:
486
+ vote_value_hbd (float): Vote value in HBD used to compute the curation share.
487
+ estimated_value_hbd (float, optional): Estimated total post value in HBD to scale the curation; defaults to the post's current reward.
423
488
 
424
- :param float vote_value_SBD: The vote value in SBD for which the curation
425
- should be calculated
426
- :param float estimated_value_SBD: When set, this value is used for calculate
427
- the curation. When not set, the current post value is used.
489
+ Returns:
490
+ float: Estimated curation reward in HBD for the provided vote value.
428
491
  """
429
492
  self.refresh()
430
- if estimated_value_SBD is None:
431
- estimated_value_SBD = float(self.reward)
493
+ if estimated_value_hbd is None:
494
+ estimated_value_hbd = float(self.reward)
432
495
  t = 1.0 - self.get_curation_penalty()
433
- k = vote_value_SBD / (vote_value_SBD + float(self.reward))
496
+ k = vote_value_hbd / (vote_value_hbd + float(self.reward))
434
497
  K = (1 - math.sqrt(1 - k)) / 4 / k
435
- return K * vote_value_SBD * t * math.sqrt(estimated_value_SBD)
498
+ return K * vote_value_hbd * t * math.sqrt(estimated_value_hbd)
436
499
 
437
500
  def get_curation_penalty(self, vote_time=None):
438
- """If post is less than 5 minutes old, it will incur a curation
439
- reward penalty.
501
+ """
502
+ Return the curation penalty factor for a vote at a given time.
503
+
504
+ Calculates a value in [0.0, 1.0] representing the fraction of curation rewards
505
+ that will be removed due to early voting (0.0 = no penalty, 1.0 = full penalty).
506
+ The penalty is based on the elapsed time between the post's creation and
507
+ the vote time, scaled by the Hive reverse-auction window for the node's
508
+ current hardfork (HF21, HF20, or HF6).
509
+
510
+ Parameters:
511
+ vote_time (datetime | date | str | None): Time of the vote. If None,
512
+ the current time is used. If a string is given it will be parsed
513
+ with the module's time formatter.
440
514
 
441
- :param datetime vote_time: A vote time can be given and the curation
442
- penalty is calculated regarding the given time (default is None)
443
- When set to None, the current date is used.
444
- :returns: Float number between 0 and 1 (0.0 -> no penalty, 1.0 -> 100 % curation penalty)
445
- :rtype: float
515
+ Returns:
516
+ float: Penalty fraction in the range [0.0, 1.0].
446
517
 
518
+ Raises:
519
+ ValueError: If vote_time is not None and not a datetime, date, or parseable string.
447
520
  """
448
521
  if vote_time is None:
449
522
  elapsed_seconds = self.time_elapsed().total_seconds()
@@ -453,25 +526,33 @@ class Comment(BlockchainObject):
453
526
  elapsed_seconds = (vote_time - self["created"]).total_seconds()
454
527
  else:
455
528
  raise ValueError("vote_time must be a string or a datetime")
456
- if self.blockchain.hardfork >= 21:
457
- reward = elapsed_seconds / STEEM_REVERSE_AUCTION_WINDOW_SECONDS_HF21
458
- elif self.blockchain.hardfork >= 20:
459
- reward = elapsed_seconds / STEEM_REVERSE_AUCTION_WINDOW_SECONDS_HF20
529
+ if self.blockchain.hardfork() >= 21:
530
+ reward = elapsed_seconds / HIVE_REVERSE_AUCTION_WINDOW_SECONDS_HF21
531
+ elif self.blockchain.hardfork() >= 20:
532
+ reward = elapsed_seconds / HIVE_REVERSE_AUCTION_WINDOW_SECONDS_HF20
460
533
  else:
461
- reward = elapsed_seconds / STEEM_REVERSE_AUCTION_WINDOW_SECONDS_HF6
534
+ reward = elapsed_seconds / HIVE_REVERSE_AUCTION_WINDOW_SECONDS_HF6
462
535
  if reward > 1:
463
536
  reward = 1.0
464
537
  return 1.0 - reward
465
538
 
466
539
  def get_vote_with_curation(self, voter=None, raw_data=False, pending_payout_value=None):
467
- """Returns vote for voter. Returns None, if the voter cannot be found in `active_votes`.
540
+ """
541
+ Return the specified voter's vote for this comment, optionally augmented with curation data.
542
+
543
+ If `voter` is not found in the comment's votes returns None. When a vote is found:
544
+ - If `raw_data` is True or the post is not pending payout, returns the raw vote dict.
545
+ - If the post is pending and `raw_data` is False, returns the vote dict augmented with:
546
+ - `curation_reward`: the vote's curation reward (in HBD)
547
+ - `ROI`: percent return on the voter's effective voting value
468
548
 
469
- :param str voter: Voter for which the vote should be returned
470
- :param bool raw_data: If True, the raw data are returned
471
- :param pending_payout_SBD: When not None this value instead of the current
472
- value is used for calculating the rewards
473
- :type pending_payout_SBD: float, str
549
+ Parameters:
550
+ voter (str or Account, optional): Voter name or Account. If omitted, defaults to the post author as an Account.
551
+ raw_data (bool, optional): If True, return the found vote without adding curation/ROI fields.
552
+ pending_payout_value (float or str, optional): If provided, use this HBD value instead of the current pending payout when computing curation rewards.
474
553
 
554
+ Returns:
555
+ dict or None: The vote dictionary (possibly augmented with `curation_reward` and `ROI`) or None if the voter has not voted.
475
556
  """
476
557
  specific_vote = None
477
558
  if voter is None:
@@ -491,12 +572,16 @@ class Comment(BlockchainObject):
491
572
  return specific_vote
492
573
  elif specific_vote is not None:
493
574
  curation_reward = self.get_curation_rewards(
494
- pending_payout_SBD=True, pending_payout_value=pending_payout_value
575
+ pending_payout_hbd=True, pending_payout_value=pending_payout_value
495
576
  )
496
577
  specific_vote["curation_reward"] = curation_reward["active_votes"][voter["name"]]
497
578
  specific_vote["ROI"] = (
498
579
  float(curation_reward["active_votes"][voter["name"]])
499
- / float(voter.get_voting_value_SBD(voting_weight=specific_vote["percent"] / 100))
580
+ / float(
581
+ voter.get_voting_value(
582
+ voting_power=None, voting_weight=specific_vote["percent"] / 100
583
+ )
584
+ )
500
585
  * 100
501
586
  )
502
587
  return specific_vote
@@ -504,32 +589,35 @@ class Comment(BlockchainObject):
504
589
  return None
505
590
 
506
591
  def get_beneficiaries_pct(self):
507
- """Returns the sum of all post beneficiaries in percentage"""
592
+ """
593
+ Return the sum of beneficiary weights as a fraction of the full payout.
594
+
595
+ If the post has a `beneficiaries` list of dicts with integer `weight` fields (0–10000 representing 0%–100%), this returns the total weight divided by 100.0 (i.e., a float in 0.0–100.0/100 range; typical values are 0.0–1.0).
596
+ """
508
597
  beneficiaries = self["beneficiaries"]
509
598
  weight = 0
510
599
  for b in beneficiaries:
511
600
  weight += b["weight"]
512
- return weight / 100.0
601
+ return weight / HIVE_100_PERCENT
513
602
 
514
603
  def get_rewards(self):
515
- """Returns the total_payout, author_payout and the curator payout in SBD.
516
- When the payout is still pending, the estimated payout is given out.
604
+ """
605
+ Return the post's total, author, and curator payouts as Amount objects (HBD).
517
606
 
518
- .. note:: Potential beneficiary rewards were already deducted from the
519
- `author_payout` and the `total_payout`
607
+ If the post is pending, returns an estimated total based on pending_payout_value and derives the author's share via get_author_rewards(); curator_payout is computed as the difference. For finalized posts, uses total_payout_value and curator_payout_value.
520
608
 
521
- Example:::
609
+ Note: beneficiary rewards (if any) are already deducted from the returned author_payout and total_payout.
522
610
 
523
- {
524
- 'total_payout': 9.956 SBD,
525
- 'author_payout': 7.166 SBD,
526
- 'curator_payout': 2.790 SBD
611
+ Returns:
612
+ dict: {
613
+ "total_payout": Amount,
614
+ "author_payout": Amount,
615
+ "curator_payout": Amount,
527
616
  }
528
-
529
617
  """
530
618
  if self.is_pending():
531
619
  total_payout = Amount(self["pending_payout_value"], blockchain_instance=self.blockchain)
532
- author_payout = self.get_author_rewards()["total_payout_SBD"]
620
+ author_payout = self.get_author_rewards()["total_payout_HBD"]
533
621
  curator_payout = total_payout - author_payout
534
622
  else:
535
623
  author_payout = Amount(self["total_payout_value"], blockchain_instance=self.blockchain)
@@ -544,30 +632,38 @@ class Comment(BlockchainObject):
544
632
  }
545
633
 
546
634
  def get_author_rewards(self):
547
- """Returns the author rewards.
548
-
635
+ """
636
+ Return the computed author-side rewards for this post.
549
637
 
638
+ If the post payout is not pending, returns zero HP/HBD payouts and the concrete total payout as `total_payout_HBD`. If the payout is pending, computes the author’s share after curation and beneficiaries, and—when price history and percent_hbd are available—splits that share into HBD and HP equivalents.
550
639
 
551
- Example::
640
+ Returns:
641
+ dict: A dictionary with the following keys:
642
+ - pending_rewards (bool): True when the post payout is still pending.
643
+ - payout_HP (Amount or None): Estimated Hive Power payout (Amount) when pending and convertible; otherwise 0 Amount (when not pending) or None.
644
+ - payout_HBD (Amount or None): Estimated HBD payout (Amount) when pending and convertible; otherwise 0 Amount (when not pending) or None.
645
+ - total_payout_HBD (Amount): Total author-side payout expressed in HBD-equivalent units when pending, or the concrete total payout when not pending.
646
+ - total_payout (Amount, optional): Present only for pending payouts in the non-convertible branch; the author-side token amount before HBD/HP splitting.
647
+ - Note: When price/percent data is not available, `payout_HP` and `payout_HBD` will be None and only `total_payout_HBD`/`total_payout` convey the author share.
552
648
 
649
+ Example:
553
650
  {
554
- 'pending_rewards': True,
555
- 'payout_SP': 0.912 STEEM,
556
- 'payout_SBD': 3.583 SBD,
557
- 'total_payout_SBD': 7.166 SBD
651
+ "pending_rewards": True,
652
+ "payout_HP": Amount(...), # HP equivalent (when convertible)
653
+ "payout_HBD": Amount(...), # HBD portion (when convertible)
654
+ "total_payout_HBD": Amount(...) # Total author share in HBD-equivalent
558
655
  }
559
-
560
656
  """
561
657
  if not self.is_pending():
562
658
  return {
563
659
  "pending_rewards": False,
564
- "payout_SP": Amount(
660
+ "payout_HP": Amount(
565
661
  0, self.blockchain.token_symbol, blockchain_instance=self.blockchain
566
662
  ),
567
- "payout_SBD": Amount(
663
+ "payout_HBD": Amount(
568
664
  0, self.blockchain.backed_token_symbol, blockchain_instance=self.blockchain
569
665
  ),
570
- "total_payout_SBD": Amount(
666
+ "total_payout_HBD": Amount(
571
667
  self["total_payout_value"], blockchain_instance=self.blockchain
572
668
  ),
573
669
  }
@@ -579,70 +675,52 @@ class Comment(BlockchainObject):
579
675
  curation_tokens = self.reward * author_reward_factor
580
676
  author_tokens = self.reward - curation_tokens
581
677
  curation_rewards = self.get_curation_rewards()
582
- if self.blockchain.hardfork >= 20 and median_hist is not None:
678
+ if self.blockchain.hardfork() >= 20 and median_hist is not None:
583
679
  author_tokens += median_price * curation_rewards["unclaimed_rewards"]
584
-
585
- benefactor_tokens = author_tokens * beneficiaries_pct / 100.0
680
+ benefactor_tokens = author_tokens * beneficiaries_pct / HIVE_100_PERCENT
586
681
  author_tokens -= benefactor_tokens
587
682
 
588
- if median_hist is not None and "percent_steem_dollars" in self:
589
- sbd_steem = author_tokens * self["percent_steem_dollars"] / 20000.0
590
- vesting_steem = median_price.as_base(self.blockchain.token_symbol) * (
591
- author_tokens - sbd_steem
683
+ if median_hist is not None and "percent_hbd" in self:
684
+ hbd_payout = author_tokens * self["percent_hbd"] / 20000.0
685
+ hp_payout = median_price.as_base(self.blockchain.token_symbol) * (
686
+ author_tokens - hbd_payout
592
687
  )
593
688
  return {
594
689
  "pending_rewards": True,
595
- "payout_SP": vesting_steem,
596
- "payout_SBD": sbd_steem,
597
- "total_payout_SBD": author_tokens,
598
- }
599
- elif median_hist is not None and "percent_hbd" in self:
600
- sbd_steem = author_tokens * self["percent_hbd"] / 20000.0
601
- vesting_steem = median_price.as_base(self.blockchain.token_symbol) * (
602
- author_tokens - sbd_steem
603
- )
604
- return {
605
- "pending_rewards": True,
606
- "payout_SP": vesting_steem,
607
- "payout_SBD": sbd_steem,
608
- "total_payout_SBD": author_tokens,
690
+ "payout_HP": hp_payout,
691
+ "payout_HBD": hbd_payout,
692
+ "total_payout_HBD": author_tokens,
609
693
  }
610
694
  else:
611
695
  return {
612
696
  "pending_rewards": True,
613
697
  "total_payout": author_tokens,
614
- "payout_SBD": None,
615
- "total_payout_SBD": None,
698
+ # HBD/HP primary fields
699
+ "total_payout_HBD": author_tokens,
700
+ "payout_HBD": None,
701
+ "payout_HP": None,
616
702
  }
617
703
 
618
- def get_curation_rewards(self, pending_payout_SBD=False, pending_payout_value=None):
619
- """Returns the curation rewards. The split between creator/curator is currently 50%/50%.
620
-
621
- :param bool pending_payout_SBD: If True, the rewards are returned in SBD and not in STEEM (default is False)
622
- :param pending_payout_value: When not None this value instead of the current
623
- value is used for calculating the rewards
624
- :type pending_payout_value: float, str
625
-
626
- `pending_rewards` is True when
627
- the post is younger than 7 days. `unclaimed_rewards` is the
628
- amount of curation_rewards that goes to the author (self-vote or votes within
629
- the first 30 minutes). `active_votes` contains all voter with their curation reward.
630
-
631
- Example::
632
-
633
- {
634
- 'pending_rewards': True, 'unclaimed_rewards': 0.245 STEEM,
635
- 'active_votes': {
636
- 'leprechaun': 0.006 STEEM, 'timcliff': 0.186 STEEM,
637
- 'st3llar': 0.000 STEEM, 'crokkon': 0.015 STEEM, 'feedyourminnows': 0.003 STEEM,
638
- 'isnochys': 0.003 STEEM, 'loshcat': 0.001 STEEM, 'greenorange': 0.000 STEEM,
639
- 'qustodian': 0.123 STEEM, 'jpphotography': 0.002 STEEM, 'thinkingmind': 0.001 STEEM,
640
- 'oups': 0.006 STEEM, 'mattockfs': 0.001 STEEM, 'thecrazygm': 0.003 STEEM, 'michaelizer': 0.004 STEEM,
641
- 'flugschwein': 0.010 STEEM, 'ulisessabeque': 0.000 STEEM, 'hakancelik': 0.002 STEEM, 'sbi2': 0.008 STEEM,
642
- 'zcool': 0.000 STEEM, 'steemhq': 0.002 STEEM, 'rowdiya': 0.000 STEEM, 'qurator-tier-1-2': 0.012 STEEM
643
- }
704
+ def get_curation_rewards(self, pending_payout_hbd=False, pending_payout_value=None):
705
+ """
706
+ Calculate curation rewards for this post and distribute them across active voters.
707
+
708
+ Parameters:
709
+ pending_payout_hbd (bool): If True, compute and return rewards in HBD (do not convert to HIVE/HP). Default False.
710
+ pending_payout_value (float | str | Amount | None): Optional override for the post's pending payout value used when the post is still pending.
711
+ - If None and the post is pending, the function uses the post's stored pending_payout_value.
712
+ - Accepted types: numeric, string amount, or an Amount instance.
713
+
714
+ Returns:
715
+ dict: {
716
+ "pending_rewards": bool, # True if the post is still within the payout window (uses pending_payout_value)
717
+ "unclaimed_rewards": Amount, # Amount reserved for unclaimed curation (e.g., self-votes or early votes)
718
+ "active_votes": dict # Mapping voter_name -> Amount of curation reward allocated to that voter
644
719
  }
645
720
 
721
+ Notes:
722
+ - The function splits the curation pool using the protocol's curator share (50% by default) and prorates per-voter claims by vote weight.
723
+ - When a current median price history is available, rewards may be converted between HBD and the chain's token (HP) according to pending_payout_hbd.
646
724
  """
647
725
  median_hist = self.blockchain.get_current_median_history()
648
726
  if median_hist is not None:
@@ -666,7 +744,7 @@ class Comment(BlockchainObject):
666
744
  total_vote_weight += vote["weight"]
667
745
 
668
746
  if not self.is_pending():
669
- if pending_payout_SBD or median_hist is None:
747
+ if pending_payout_hbd or median_hist is None:
670
748
  max_rewards = Amount(
671
749
  self["curator_payout_value"], blockchain_instance=self.blockchain
672
750
  )
@@ -694,7 +772,7 @@ class Comment(BlockchainObject):
694
772
  pending_payout_value = Amount(
695
773
  pending_payout_value, blockchain_instance=self.blockchain
696
774
  )
697
- if pending_payout_SBD or median_hist is None:
775
+ if pending_payout_hbd or median_hist is None:
698
776
  max_rewards = pending_payout_value * curator_reward_factor
699
777
  else:
700
778
  max_rewards = median_price.as_base(self.blockchain.token_symbol) * (
@@ -921,19 +999,22 @@ class Comment(BlockchainObject):
921
999
  )
922
1000
 
923
1001
  def delete(self, account=None, identifier=None):
924
- """Delete an existing post/comment
1002
+ """
1003
+ Delete this post or comment from the blockchain.
1004
+
1005
+ If `identifier` is provided it must be an author/permlink string (e.g. "@author/permlink"); otherwise the current Comment's author and permlink are used. If `account` is not provided the method will use `blockchain.config["default_account"]` when present; otherwise a ValueError is raised.
925
1006
 
926
- :param str account: (optional) Account to use for deletion. If
927
- ``account`` is not defined, the ``default_account`` will be
928
- taken or a ValueError will be raised.
1007
+ Note: a post/comment can only be deleted if it has no replies and no positive rshares.
929
1008
 
930
- :param str identifier: (optional) Identifier for the post to delete.
931
- Takes the form ``@author/permlink``. By default the current post
932
- will be used.
1009
+ Parameters:
1010
+ account (str, optional): Account name to perform the deletion. If omitted, the configured default_account is used.
1011
+ identifier (str, optional): Author/permlink of the post to delete (format "@author/permlink"). Defaults to the current Comment.
933
1012
 
934
- .. note:: A post/comment can only be deleted as long as it has no
935
- replies and no positive rshares on it.
1013
+ Returns:
1014
+ dict: Result of the blockchain finalizeOp / transaction broadcast.
936
1015
 
1016
+ Raises:
1017
+ ValueError: If no account is provided and no default_account is configured.
937
1018
  """
938
1019
  if not account:
939
1020
  if "default_account" in self.blockchain.config:
@@ -949,13 +1030,19 @@ class Comment(BlockchainObject):
949
1030
  op = operations.Delete_comment(**{"author": post_author, "permlink": post_permlink})
950
1031
  return self.blockchain.finalizeOp(op, account, "posting")
951
1032
 
952
- def resteem(self, identifier=None, account=None):
953
- """Resteem a post
1033
+ def reblog(self, identifier=None, account=None):
1034
+ """
1035
+ Create a reblog (resteem) for the specified post.
1036
+
1037
+ Parameters:
1038
+ identifier (str, optional): Post identifier in the form "@author/permlink". If omitted, uses this Comment's identifier.
1039
+ account (str, optional): Name of the posting account to perform the reblog. If omitted, the configured `default_account` is used.
954
1040
 
955
- :param str identifier: post identifier (@<account>/<permlink>)
956
- :param str account: (optional) the account to allow access
957
- to (defaults to ``default_account``)
1041
+ Returns:
1042
+ dict: Result from the blockchain custom_json operation.
958
1043
 
1044
+ Raises:
1045
+ ValueError: If no account is provided and no `default_account` is configured.
959
1046
  """
960
1047
  if not account:
961
1048
  account = self.blockchain.configStorage.get("default_account")
@@ -977,7 +1064,7 @@ class RecentReplies(list):
977
1064
  :param str author: author
978
1065
  :param bool skip_own: (optional) Skip replies of the author to him/herself.
979
1066
  Default: True
980
- :param Steem blockchain_instance: Steem() instance to use when accesing a RPC
1067
+ :param Blockchain blockchain_instance: Blockchain instance to use when accessing the RPC
981
1068
  """
982
1069
 
983
1070
  def __init__(
@@ -989,13 +1076,24 @@ class RecentReplies(list):
989
1076
  lazy=False,
990
1077
  full=True,
991
1078
  blockchain_instance=None,
992
- **kwargs,
993
1079
  ):
994
- if blockchain_instance is None:
995
- if kwargs.get("steem_instance"):
996
- blockchain_instance = kwargs["steem_instance"]
997
- elif kwargs.get("hive_instance"):
998
- blockchain_instance = kwargs["hive_instance"]
1080
+ """
1081
+ Create a list of recent replies to a given account.
1082
+
1083
+ Initializes the instance as a list of Comment objects built from the account's recent "replies" feed. By default replies authored by the same account are omitted when skip_own is True. If no blockchain connection is available during construction, initialization is aborted (the constructor returns early).
1084
+
1085
+ Parameters:
1086
+ author (str): Account name whose replies to collect.
1087
+ skip_own (bool): If True, omit replies authored by `author`. Default True.
1088
+ start_permlink (str): Legacy/paging parameter; currently ignored by this implementation.
1089
+ limit (int): Maximum number of replies to collect; currently ignored (the underlying API call controls results).
1090
+ lazy (bool): If True, create Comment objects in lazy mode.
1091
+ full (bool): If True, create Comment objects with full data populated.
1092
+
1093
+ Notes:
1094
+ - The blockchain_instance parameter is used to resolve RPC access and is intentionally undocumented here as a shared service.
1095
+ - The underlying account.get_account_posts(sort="replies", raw_data=True) call provides the source data; when it returns None or the instance is not connected, construction exits early.
1096
+ """
999
1097
  self.blockchain = blockchain_instance or shared_blockchain_instance()
1000
1098
  if not self.blockchain.is_connected():
1001
1099
  return None
@@ -1020,7 +1118,7 @@ class RecentByPath(list):
1020
1118
  :param str path: path
1021
1119
  :param str tag: tag
1022
1120
  :param str observer: observer
1023
- :param Steem blockchain_instance: Steem() instance to use when accesing a RPC
1121
+ :param Blockchain blockchain_instance: Blockchain instance to use when accessing the RPC
1024
1122
  """
1025
1123
 
1026
1124
  def __init__(
@@ -1032,13 +1130,18 @@ class RecentByPath(list):
1032
1130
  full=True,
1033
1131
  limit=20,
1034
1132
  blockchain_instance=None,
1035
- **kwargs,
1036
1133
  ):
1037
- if blockchain_instance is None:
1038
- if kwargs.get("steem_instance"):
1039
- blockchain_instance = kwargs["steem_instance"]
1040
- elif kwargs.get("hive_instance"):
1041
- blockchain_instance = kwargs["hive_instance"]
1134
+ """
1135
+ Create a RecentByPath list by fetching ranked posts for a given path/tag and initializing the list with those posts.
1136
+
1137
+ Parameters:
1138
+ path (str): Ranking category to fetch (e.g., "trending", "hot").
1139
+ tag (str): Optional tag to filter posts.
1140
+ observer (str): Observer account used for context-aware fetches (affects reward/curation visibility).
1141
+ lazy (bool): If True, create Comment objects lazily (defer full data loading).
1142
+ full (bool): If True, initialize Comment objects with full data when available.
1143
+ limit (int): Maximum number of posts to fetch.
1144
+ """
1042
1145
  self.blockchain = blockchain_instance or shared_blockchain_instance()
1043
1146
 
1044
1147
  # Create RankedPosts with proper parameters
@@ -1050,7 +1153,6 @@ class RecentByPath(list):
1050
1153
  lazy=lazy,
1051
1154
  full=full,
1052
1155
  blockchain_instance=self.blockchain,
1053
- **kwargs,
1054
1156
  )
1055
1157
 
1056
1158
  super(RecentByPath, self).__init__(ranked_posts)
@@ -1065,7 +1167,7 @@ class RankedPosts(list):
1065
1167
  :param int limit: limits the number of returns comments
1066
1168
  :param str start_author: start author
1067
1169
  :param str start_permlink: start permlink
1068
- :param Steem blockchain_instance: Steem() instance to use when accesing a RPC
1170
+ :param Blockchain blockchain_instance: Blockchain instance to use when accessing the RPC
1069
1171
  """
1070
1172
 
1071
1173
  def __init__(
@@ -1080,13 +1182,29 @@ class RankedPosts(list):
1080
1182
  full=True,
1081
1183
  raw_data=False,
1082
1184
  blockchain_instance=None,
1083
- **kwargs,
1084
1185
  ):
1085
- if blockchain_instance is None:
1086
- if kwargs.get("steem_instance"):
1087
- blockchain_instance = kwargs["steem_instance"]
1088
- elif kwargs.get("hive_instance"):
1089
- blockchain_instance = kwargs["hive_instance"]
1186
+ """
1187
+ Initialize a RankedPosts list by fetching paginated ranked posts from the blockchain.
1188
+
1189
+ Fetches up to `limit` posts for the given `sort` and `tag` using the bridge `get_ranked_posts`
1190
+ RPC, paging with `start_author` / `start_permlink`. Results are appended to the list as raw
1191
+ post dicts when `raw_data` is True, or as Comment objects otherwise. The constructor:
1192
+ - uses `blockchain_instance` (or the shared instance) and returns early (None) if not connected;
1193
+ - pages through results with an API page size up to 100, updating `start_author`/`start_permlink`;
1194
+ - avoids repeating the last item returned by the API; and
1195
+ - on an RPC error, returns partial results if any posts were already collected, otherwise re-raises.
1196
+
1197
+ Parameters:
1198
+ sort (str): Ranking to query (e.g., "trending", "hot", "created").
1199
+ tag (str): Optional tag/category to filter by.
1200
+ observer (str): Optional observer account used by the bridge API (affects personalized results).
1201
+ limit (int): Maximum number of posts to return.
1202
+ start_author (str): Author to start paging from (inclusive/exclusive depends on the API).
1203
+ start_permlink (str): Permlink to start paging from.
1204
+ lazy (bool): If False, wrap results in Comment objects fully; if True, create Comment objects in lazy mode.
1205
+ full (bool): If True, request full Comment initialization when wrapping results.
1206
+ raw_data (bool): If True, return raw post dictionaries instead of Comment objects.
1207
+ """
1090
1208
  self.blockchain = blockchain_instance or shared_blockchain_instance()
1091
1209
  if not self.blockchain.is_connected():
1092
1210
  return None
@@ -1151,7 +1269,7 @@ class AccountPosts(list):
1151
1269
  :param int limit: limits the number of returns comments
1152
1270
  :param str start_author: start author
1153
1271
  :param str start_permlink: start permlink
1154
- :param Hive blockchain_instance: Hive() instance to use when accesing a RPC
1272
+ :param Blockchain blockchain_instance: Blockchain instance to use when accessing the RPC
1155
1273
  """
1156
1274
 
1157
1275
  def __init__(
@@ -1166,13 +1284,30 @@ class AccountPosts(list):
1166
1284
  full=True,
1167
1285
  raw_data=False,
1168
1286
  blockchain_instance=None,
1169
- **kwargs,
1170
1287
  ):
1171
- if blockchain_instance is None:
1172
- if kwargs.get("steem_instance"):
1173
- blockchain_instance = kwargs["steem_instance"]
1174
- elif kwargs.get("hive_instance"):
1175
- blockchain_instance = kwargs["hive_instance"]
1288
+ """
1289
+ Initialize an AccountPosts list by fetching posts for a given account (paginated).
1290
+
1291
+ This constructor populates the list with posts returned by the bridge.get_account_posts RPC call,
1292
+ respecting paging (start_author/start_permlink) and the requested limit. Each item is either the
1293
+ raw post dict (when raw_data=True) or a Comment object constructed with the same blockchain instance.
1294
+
1295
+ Parameters:
1296
+ sort (str): The post list type to fetch (e.g., "blog", "comments", "replies", "feed").
1297
+ account (str): Account name whose posts are requested.
1298
+ observer (str): Optional observer account name used by the API (affects visibility/context).
1299
+ limit (int): Maximum number of posts to collect.
1300
+ start_author (str): Author to start paging from (inclusive/exclusive depends on API).
1301
+ start_permlink (str): Permlink to start paging from.
1302
+ lazy (bool): If False, Comment objects are fully loaded; if True, they are initialized lazily.
1303
+ full (bool): If True, Comment objects include full data; otherwise minimal fields.
1304
+ raw_data (bool): If True, return raw post dicts instead of Comment objects.
1305
+
1306
+ Behavior notes:
1307
+ - If the blockchain instance is not connected, initialization returns early (no posts are fetched).
1308
+ - On an RPC error, if some posts have already been collected, the constructor returns those partial results;
1309
+ if no posts were collected, the exception is propagated.
1310
+ """
1176
1311
  self.blockchain = blockchain_instance or shared_blockchain_instance()
1177
1312
  if not self.blockchain.is_connected():
1178
1313
  return None