hive-nectar 0.0.11__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.11.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 +313 -181
  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 +115 -81
  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.11.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.11.dist-info → hive_nectar-0.1.0.dist-info}/WHEEL +0 -0
  55. {hive_nectar-0.0.11.dist-info → hive_nectar-0.1.0.dist-info}/entry_points.txt +0 -0
  56. {hive_nectar-0.0.11.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 (
@@ -226,6 +252,19 @@ class Comment(BlockchainObject):
226
252
  )
227
253
 
228
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
+ """
229
268
  output = self.copy()
230
269
  if "authorperm" in output:
231
270
  output.pop("authorperm")
@@ -249,7 +288,7 @@ class Comment(BlockchainObject):
249
288
  output[p] = formatTimeString(p_date)
250
289
  else:
251
290
  output[p] = p_date
252
- sbd_amounts = [
291
+ hbd_amounts = [
253
292
  "total_payout_value",
254
293
  "max_accepted_payout",
255
294
  "pending_payout_value",
@@ -257,7 +296,7 @@ class Comment(BlockchainObject):
257
296
  "total_pending_payout_value",
258
297
  "promoted",
259
298
  ]
260
- for p in sbd_amounts:
299
+ for p in hbd_amounts:
261
300
  if p in output and isinstance(output[p], Amount):
262
301
  output[p] = output[p].json()
263
302
  parse_int = [
@@ -380,7 +419,16 @@ class Comment(BlockchainObject):
380
419
 
381
420
  @property
382
421
  def reward(self):
383
- """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
+ """
384
432
  a_zero = Amount(0, self.blockchain.backed_token_symbol, blockchain_instance=self.blockchain)
385
433
  author = Amount(self.get("total_payout_value", a_zero), blockchain_instance=self.blockchain)
386
434
  curator = Amount(
@@ -401,52 +449,74 @@ class Comment(BlockchainObject):
401
449
  return post_age_days < 7.0 and float(total) == 0
402
450
 
403
451
  def time_elapsed(self):
404
- """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
+ """
405
458
  return datetime.now(timezone.utc) - self["created"]
406
459
 
407
- def curation_penalty_compensation_SBD(self):
408
- """Returns The required post payout amount after 15 minutes
409
- 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.
410
468
  """
411
469
  self.refresh()
412
- if self.blockchain.hardfork >= 21:
413
- reverse_auction_window_seconds = STEEM_REVERSE_AUCTION_WINDOW_SECONDS_HF21
414
- elif self.blockchain.hardfork >= 20:
415
- 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
416
474
  else:
417
- reverse_auction_window_seconds = STEEM_REVERSE_AUCTION_WINDOW_SECONDS_HF6
418
- return (
419
- self.reward
420
- * reverse_auction_window_seconds
421
- / ((self.time_elapsed()).total_seconds() / 60) ** 2
422
- )
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.
423
484
 
424
- def estimate_curation_SBD(self, vote_value_SBD, estimated_value_SBD=None):
425
- """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.
426
488
 
427
- :param float vote_value_SBD: The vote value in SBD for which the curation
428
- should be calculated
429
- :param float estimated_value_SBD: When set, this value is used for calculate
430
- 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.
431
491
  """
432
492
  self.refresh()
433
- if estimated_value_SBD is None:
434
- estimated_value_SBD = float(self.reward)
493
+ if estimated_value_hbd is None:
494
+ estimated_value_hbd = float(self.reward)
435
495
  t = 1.0 - self.get_curation_penalty()
436
- k = vote_value_SBD / (vote_value_SBD + float(self.reward))
496
+ k = vote_value_hbd / (vote_value_hbd + float(self.reward))
437
497
  K = (1 - math.sqrt(1 - k)) / 4 / k
438
- return K * vote_value_SBD * t * math.sqrt(estimated_value_SBD)
498
+ return K * vote_value_hbd * t * math.sqrt(estimated_value_hbd)
439
499
 
440
500
  def get_curation_penalty(self, vote_time=None):
441
- """If post is less than 5 minutes old, it will incur a curation
442
- 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.
443
514
 
444
- :param datetime vote_time: A vote time can be given and the curation
445
- penalty is calculated regarding the given time (default is None)
446
- When set to None, the current date is used.
447
- :returns: Float number between 0 and 1 (0.0 -> no penalty, 1.0 -> 100 % curation penalty)
448
- :rtype: float
515
+ Returns:
516
+ float: Penalty fraction in the range [0.0, 1.0].
449
517
 
518
+ Raises:
519
+ ValueError: If vote_time is not None and not a datetime, date, or parseable string.
450
520
  """
451
521
  if vote_time is None:
452
522
  elapsed_seconds = self.time_elapsed().total_seconds()
@@ -456,25 +526,33 @@ class Comment(BlockchainObject):
456
526
  elapsed_seconds = (vote_time - self["created"]).total_seconds()
457
527
  else:
458
528
  raise ValueError("vote_time must be a string or a datetime")
459
- if self.blockchain.hardfork >= 21:
460
- reward = elapsed_seconds / STEEM_REVERSE_AUCTION_WINDOW_SECONDS_HF21
461
- elif self.blockchain.hardfork >= 20:
462
- 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
463
533
  else:
464
- reward = elapsed_seconds / STEEM_REVERSE_AUCTION_WINDOW_SECONDS_HF6
534
+ reward = elapsed_seconds / HIVE_REVERSE_AUCTION_WINDOW_SECONDS_HF6
465
535
  if reward > 1:
466
536
  reward = 1.0
467
537
  return 1.0 - reward
468
538
 
469
539
  def get_vote_with_curation(self, voter=None, raw_data=False, pending_payout_value=None):
470
- """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
471
548
 
472
- :param str voter: Voter for which the vote should be returned
473
- :param bool raw_data: If True, the raw data are returned
474
- :param pending_payout_SBD: When not None this value instead of the current
475
- value is used for calculating the rewards
476
- :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.
477
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.
478
556
  """
479
557
  specific_vote = None
480
558
  if voter is None:
@@ -494,12 +572,16 @@ class Comment(BlockchainObject):
494
572
  return specific_vote
495
573
  elif specific_vote is not None:
496
574
  curation_reward = self.get_curation_rewards(
497
- pending_payout_SBD=True, pending_payout_value=pending_payout_value
575
+ pending_payout_hbd=True, pending_payout_value=pending_payout_value
498
576
  )
499
577
  specific_vote["curation_reward"] = curation_reward["active_votes"][voter["name"]]
500
578
  specific_vote["ROI"] = (
501
579
  float(curation_reward["active_votes"][voter["name"]])
502
- / 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
+ )
503
585
  * 100
504
586
  )
505
587
  return specific_vote
@@ -507,32 +589,35 @@ class Comment(BlockchainObject):
507
589
  return None
508
590
 
509
591
  def get_beneficiaries_pct(self):
510
- """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
+ """
511
597
  beneficiaries = self["beneficiaries"]
512
598
  weight = 0
513
599
  for b in beneficiaries:
514
600
  weight += b["weight"]
515
- return weight / 100.0
601
+ return weight / HIVE_100_PERCENT
516
602
 
517
603
  def get_rewards(self):
518
- """Returns the total_payout, author_payout and the curator payout in SBD.
519
- 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).
520
606
 
521
- .. note:: Potential beneficiary rewards were already deducted from the
522
- `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.
523
608
 
524
- Example:::
609
+ Note: beneficiary rewards (if any) are already deducted from the returned author_payout and total_payout.
525
610
 
526
- {
527
- 'total_payout': 9.956 SBD,
528
- 'author_payout': 7.166 SBD,
529
- 'curator_payout': 2.790 SBD
611
+ Returns:
612
+ dict: {
613
+ "total_payout": Amount,
614
+ "author_payout": Amount,
615
+ "curator_payout": Amount,
530
616
  }
531
-
532
617
  """
533
618
  if self.is_pending():
534
619
  total_payout = Amount(self["pending_payout_value"], blockchain_instance=self.blockchain)
535
- author_payout = self.get_author_rewards()["total_payout_SBD"]
620
+ author_payout = self.get_author_rewards()["total_payout_HBD"]
536
621
  curator_payout = total_payout - author_payout
537
622
  else:
538
623
  author_payout = Amount(self["total_payout_value"], blockchain_instance=self.blockchain)
@@ -547,30 +632,38 @@ class Comment(BlockchainObject):
547
632
  }
548
633
 
549
634
  def get_author_rewards(self):
550
- """Returns the author rewards.
551
-
635
+ """
636
+ Return the computed author-side rewards for this post.
552
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.
553
639
 
554
- 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.
555
648
 
649
+ Example:
556
650
  {
557
- 'pending_rewards': True,
558
- 'payout_SP': 0.912 STEEM,
559
- 'payout_SBD': 3.583 SBD,
560
- '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
561
655
  }
562
-
563
656
  """
564
657
  if not self.is_pending():
565
658
  return {
566
659
  "pending_rewards": False,
567
- "payout_SP": Amount(
660
+ "payout_HP": Amount(
568
661
  0, self.blockchain.token_symbol, blockchain_instance=self.blockchain
569
662
  ),
570
- "payout_SBD": Amount(
663
+ "payout_HBD": Amount(
571
664
  0, self.blockchain.backed_token_symbol, blockchain_instance=self.blockchain
572
665
  ),
573
- "total_payout_SBD": Amount(
666
+ "total_payout_HBD": Amount(
574
667
  self["total_payout_value"], blockchain_instance=self.blockchain
575
668
  ),
576
669
  }
@@ -582,70 +675,52 @@ class Comment(BlockchainObject):
582
675
  curation_tokens = self.reward * author_reward_factor
583
676
  author_tokens = self.reward - curation_tokens
584
677
  curation_rewards = self.get_curation_rewards()
585
- if self.blockchain.hardfork >= 20 and median_hist is not None:
678
+ if self.blockchain.hardfork() >= 20 and median_hist is not None:
586
679
  author_tokens += median_price * curation_rewards["unclaimed_rewards"]
587
-
588
- benefactor_tokens = author_tokens * beneficiaries_pct / 100.0
680
+ benefactor_tokens = author_tokens * beneficiaries_pct / HIVE_100_PERCENT
589
681
  author_tokens -= benefactor_tokens
590
682
 
591
- if median_hist is not None and "percent_steem_dollars" in self:
592
- sbd_steem = author_tokens * self["percent_steem_dollars"] / 20000.0
593
- vesting_steem = median_price.as_base(self.blockchain.token_symbol) * (
594
- 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
595
687
  )
596
688
  return {
597
689
  "pending_rewards": True,
598
- "payout_SP": vesting_steem,
599
- "payout_SBD": sbd_steem,
600
- "total_payout_SBD": author_tokens,
601
- }
602
- elif median_hist is not None and "percent_hbd" in self:
603
- sbd_steem = author_tokens * self["percent_hbd"] / 20000.0
604
- vesting_steem = median_price.as_base(self.blockchain.token_symbol) * (
605
- author_tokens - sbd_steem
606
- )
607
- return {
608
- "pending_rewards": True,
609
- "payout_SP": vesting_steem,
610
- "payout_SBD": sbd_steem,
611
- "total_payout_SBD": author_tokens,
690
+ "payout_HP": hp_payout,
691
+ "payout_HBD": hbd_payout,
692
+ "total_payout_HBD": author_tokens,
612
693
  }
613
694
  else:
614
695
  return {
615
696
  "pending_rewards": True,
616
697
  "total_payout": author_tokens,
617
- "payout_SBD": None,
618
- "total_payout_SBD": None,
698
+ # HBD/HP primary fields
699
+ "total_payout_HBD": author_tokens,
700
+ "payout_HBD": None,
701
+ "payout_HP": None,
619
702
  }
620
703
 
621
- def get_curation_rewards(self, pending_payout_SBD=False, pending_payout_value=None):
622
- """Returns the curation rewards. The split between creator/curator is currently 50%/50%.
623
-
624
- :param bool pending_payout_SBD: If True, the rewards are returned in SBD and not in STEEM (default is False)
625
- :param pending_payout_value: When not None this value instead of the current
626
- value is used for calculating the rewards
627
- :type pending_payout_value: float, str
628
-
629
- `pending_rewards` is True when
630
- the post is younger than 7 days. `unclaimed_rewards` is the
631
- amount of curation_rewards that goes to the author (self-vote or votes within
632
- the first 30 minutes). `active_votes` contains all voter with their curation reward.
633
-
634
- Example::
635
-
636
- {
637
- 'pending_rewards': True, 'unclaimed_rewards': 0.245 STEEM,
638
- 'active_votes': {
639
- 'leprechaun': 0.006 STEEM, 'timcliff': 0.186 STEEM,
640
- 'st3llar': 0.000 STEEM, 'crokkon': 0.015 STEEM, 'feedyourminnows': 0.003 STEEM,
641
- 'isnochys': 0.003 STEEM, 'loshcat': 0.001 STEEM, 'greenorange': 0.000 STEEM,
642
- 'qustodian': 0.123 STEEM, 'jpphotography': 0.002 STEEM, 'thinkingmind': 0.001 STEEM,
643
- 'oups': 0.006 STEEM, 'mattockfs': 0.001 STEEM, 'thecrazygm': 0.003 STEEM, 'michaelizer': 0.004 STEEM,
644
- 'flugschwein': 0.010 STEEM, 'ulisessabeque': 0.000 STEEM, 'hakancelik': 0.002 STEEM, 'sbi2': 0.008 STEEM,
645
- 'zcool': 0.000 STEEM, 'steemhq': 0.002 STEEM, 'rowdiya': 0.000 STEEM, 'qurator-tier-1-2': 0.012 STEEM
646
- }
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
647
719
  }
648
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.
649
724
  """
650
725
  median_hist = self.blockchain.get_current_median_history()
651
726
  if median_hist is not None:
@@ -669,7 +744,7 @@ class Comment(BlockchainObject):
669
744
  total_vote_weight += vote["weight"]
670
745
 
671
746
  if not self.is_pending():
672
- if pending_payout_SBD or median_hist is None:
747
+ if pending_payout_hbd or median_hist is None:
673
748
  max_rewards = Amount(
674
749
  self["curator_payout_value"], blockchain_instance=self.blockchain
675
750
  )
@@ -697,7 +772,7 @@ class Comment(BlockchainObject):
697
772
  pending_payout_value = Amount(
698
773
  pending_payout_value, blockchain_instance=self.blockchain
699
774
  )
700
- if pending_payout_SBD or median_hist is None:
775
+ if pending_payout_hbd or median_hist is None:
701
776
  max_rewards = pending_payout_value * curator_reward_factor
702
777
  else:
703
778
  max_rewards = median_price.as_base(self.blockchain.token_symbol) * (
@@ -924,19 +999,22 @@ class Comment(BlockchainObject):
924
999
  )
925
1000
 
926
1001
  def delete(self, account=None, identifier=None):
927
- """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.
928
1006
 
929
- :param str account: (optional) Account to use for deletion. If
930
- ``account`` is not defined, the ``default_account`` will be
931
- 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.
932
1008
 
933
- :param str identifier: (optional) Identifier for the post to delete.
934
- Takes the form ``@author/permlink``. By default the current post
935
- 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.
936
1012
 
937
- .. note:: A post/comment can only be deleted as long as it has no
938
- replies and no positive rshares on it.
1013
+ Returns:
1014
+ dict: Result of the blockchain finalizeOp / transaction broadcast.
939
1015
 
1016
+ Raises:
1017
+ ValueError: If no account is provided and no default_account is configured.
940
1018
  """
941
1019
  if not account:
942
1020
  if "default_account" in self.blockchain.config:
@@ -952,13 +1030,19 @@ class Comment(BlockchainObject):
952
1030
  op = operations.Delete_comment(**{"author": post_author, "permlink": post_permlink})
953
1031
  return self.blockchain.finalizeOp(op, account, "posting")
954
1032
 
955
- def resteem(self, identifier=None, account=None):
956
- """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.
957
1040
 
958
- :param str identifier: post identifier (@<account>/<permlink>)
959
- :param str account: (optional) the account to allow access
960
- to (defaults to ``default_account``)
1041
+ Returns:
1042
+ dict: Result from the blockchain custom_json operation.
961
1043
 
1044
+ Raises:
1045
+ ValueError: If no account is provided and no `default_account` is configured.
962
1046
  """
963
1047
  if not account:
964
1048
  account = self.blockchain.configStorage.get("default_account")
@@ -980,7 +1064,7 @@ class RecentReplies(list):
980
1064
  :param str author: author
981
1065
  :param bool skip_own: (optional) Skip replies of the author to him/herself.
982
1066
  Default: True
983
- :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
984
1068
  """
985
1069
 
986
1070
  def __init__(
@@ -992,13 +1076,24 @@ class RecentReplies(list):
992
1076
  lazy=False,
993
1077
  full=True,
994
1078
  blockchain_instance=None,
995
- **kwargs,
996
1079
  ):
997
- if blockchain_instance is None:
998
- if kwargs.get("steem_instance"):
999
- blockchain_instance = kwargs["steem_instance"]
1000
- elif kwargs.get("hive_instance"):
1001
- 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
+ """
1002
1097
  self.blockchain = blockchain_instance or shared_blockchain_instance()
1003
1098
  if not self.blockchain.is_connected():
1004
1099
  return None
@@ -1023,7 +1118,7 @@ class RecentByPath(list):
1023
1118
  :param str path: path
1024
1119
  :param str tag: tag
1025
1120
  :param str observer: observer
1026
- :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
1027
1122
  """
1028
1123
 
1029
1124
  def __init__(
@@ -1035,13 +1130,18 @@ class RecentByPath(list):
1035
1130
  full=True,
1036
1131
  limit=20,
1037
1132
  blockchain_instance=None,
1038
- **kwargs,
1039
1133
  ):
1040
- if blockchain_instance is None:
1041
- if kwargs.get("steem_instance"):
1042
- blockchain_instance = kwargs["steem_instance"]
1043
- elif kwargs.get("hive_instance"):
1044
- 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
+ """
1045
1145
  self.blockchain = blockchain_instance or shared_blockchain_instance()
1046
1146
 
1047
1147
  # Create RankedPosts with proper parameters
@@ -1053,7 +1153,6 @@ class RecentByPath(list):
1053
1153
  lazy=lazy,
1054
1154
  full=full,
1055
1155
  blockchain_instance=self.blockchain,
1056
- **kwargs,
1057
1156
  )
1058
1157
 
1059
1158
  super(RecentByPath, self).__init__(ranked_posts)
@@ -1068,7 +1167,7 @@ class RankedPosts(list):
1068
1167
  :param int limit: limits the number of returns comments
1069
1168
  :param str start_author: start author
1070
1169
  :param str start_permlink: start permlink
1071
- :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
1072
1171
  """
1073
1172
 
1074
1173
  def __init__(
@@ -1083,13 +1182,29 @@ class RankedPosts(list):
1083
1182
  full=True,
1084
1183
  raw_data=False,
1085
1184
  blockchain_instance=None,
1086
- **kwargs,
1087
1185
  ):
1088
- if blockchain_instance is None:
1089
- if kwargs.get("steem_instance"):
1090
- blockchain_instance = kwargs["steem_instance"]
1091
- elif kwargs.get("hive_instance"):
1092
- 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
+ """
1093
1208
  self.blockchain = blockchain_instance or shared_blockchain_instance()
1094
1209
  if not self.blockchain.is_connected():
1095
1210
  return None
@@ -1154,7 +1269,7 @@ class AccountPosts(list):
1154
1269
  :param int limit: limits the number of returns comments
1155
1270
  :param str start_author: start author
1156
1271
  :param str start_permlink: start permlink
1157
- :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
1158
1273
  """
1159
1274
 
1160
1275
  def __init__(
@@ -1169,13 +1284,30 @@ class AccountPosts(list):
1169
1284
  full=True,
1170
1285
  raw_data=False,
1171
1286
  blockchain_instance=None,
1172
- **kwargs,
1173
1287
  ):
1174
- if blockchain_instance is None:
1175
- if kwargs.get("steem_instance"):
1176
- blockchain_instance = kwargs["steem_instance"]
1177
- elif kwargs.get("hive_instance"):
1178
- 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
+ """
1179
1311
  self.blockchain = blockchain_instance or shared_blockchain_instance()
1180
1312
  if not self.blockchain.is_connected():
1181
1313
  return None