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/snapshot.py CHANGED
@@ -2,12 +2,13 @@
2
2
  import json
3
3
  import logging
4
4
  import re
5
+ import warnings
5
6
  from bisect import bisect_left
6
7
  from datetime import date, datetime, time, timedelta, timezone
7
8
 
8
9
  from nectar.account import Account
9
10
  from nectar.amount import Amount
10
- from nectar.constants import STEEM_100_PERCENT, STEEM_VOTE_REGENERATION_SECONDS
11
+ from nectar.constants import HIVE_100_PERCENT, HIVE_VOTE_REGENERATION_SECONDS
11
12
  from nectar.instance import shared_blockchain_instance
12
13
  from nectar.utils import (
13
14
  addTzInfo,
@@ -24,30 +25,53 @@ class AccountSnapshot(list):
24
25
  """This class allows to easily access Account history
25
26
 
26
27
  :param str account_name: Name of the account
27
- :param Steem blockchain_instance: Steem
28
- instance
28
+ :param Hive blockchain_instance: Hive instance
29
29
  """
30
30
 
31
- def __init__(self, account, account_history=[], blockchain_instance=None, **kwargs):
32
- if blockchain_instance is None:
33
- if kwargs.get("steem_instance"):
34
- blockchain_instance = kwargs["steem_instance"]
35
- elif kwargs.get("hive_instance"):
36
- blockchain_instance = kwargs["hive_instance"]
31
+ def __init__(self, account, account_history=None, blockchain_instance=None, **kwargs):
32
+ super(AccountSnapshot, self).__init__(account_history or [])
33
+ # Warn about any unused kwargs to maintain backward compatibility
34
+ """
35
+ Initialize an AccountSnapshot for the given account.
36
+
37
+ Creates an Account object for the target account (using the provided blockchain instance or the shared instance), resets internal snapshot state, and populates the snapshot list with any provided account_history. Any unexpected keyword arguments are accepted but ignored; a DeprecationWarning is emitted for each.
38
+
39
+ Parameters:
40
+ account (str or Account): Account identifier or existing Account object to build the snapshot for.
41
+ account_history (iterable, optional): Pre-fetched sequence of account operations to initialize the snapshot with. Defaults to an empty list.
42
+
43
+ Notes:
44
+ - blockchain_instance is accepted but not documented here as a service-like parameter; if provided it overrides the shared blockchain instance used to construct the Account.
45
+ - This initializer mutates internal state (calls reset) and appends account_history into the snapshot's underlying list.
46
+ """
47
+ if kwargs:
48
+ for key in kwargs:
49
+ warnings.warn(
50
+ f"Unexpected keyword argument '{key}' passed to AccountSnapshot.__init__. "
51
+ "This may be a deprecated parameter and will be ignored.",
52
+ DeprecationWarning,
53
+ stacklevel=2,
54
+ )
37
55
  self.blockchain = blockchain_instance or shared_blockchain_instance()
38
56
  self.account = Account(account, blockchain_instance=self.blockchain)
39
57
  self.reset()
40
58
  super(AccountSnapshot, self).__init__(account_history)
41
59
 
42
60
  def reset(self):
43
- """Resets the arrays not the stored account history"""
61
+ """
62
+ Reset internal time-series and aggregation arrays while preserving the stored account history.
63
+
64
+ Reinitializes per-timestamp state used to build derived metrics (vesting, Hive/HBD balances, delegations,
65
+ operation statistics, reward and vote timelines, reputation and voting-power arrays). Does not modify
66
+ the list contents (the stored raw account history).
67
+ """
44
68
  self.own_vests = [
45
69
  Amount(0, self.blockchain.vest_token_symbol, blockchain_instance=self.blockchain)
46
70
  ]
47
- self.own_steem = [
71
+ self.own_hive = [
48
72
  Amount(0, self.blockchain.token_symbol, blockchain_instance=self.blockchain)
49
73
  ]
50
- self.own_sbd = [
74
+ self.own_hbd = [
51
75
  Amount(0, self.blockchain.backed_token_symbol, blockchain_instance=self.blockchain)
52
76
  ]
53
77
  self.delegated_vests_in = [{}]
@@ -59,8 +83,8 @@ class AccountSnapshot(list):
59
83
  self.reward_timestamps = []
60
84
  self.author_rewards = []
61
85
  self.curation_rewards = []
62
- self.curation_per_1000_SP_timestamp = []
63
- self.curation_per_1000_SP = []
86
+ self.curation_per_1000_HP_timestamp = []
87
+ self.curation_per_1000_HP = []
64
88
  self.out_vote_timestamp = []
65
89
  self.out_vote_weight = []
66
90
  self.in_vote_timestamp = []
@@ -136,7 +160,22 @@ class AccountSnapshot(list):
136
160
  yield op
137
161
 
138
162
  def get_data(self, timestamp=None, index=0):
139
- """Returns snapshot for given timestamp"""
163
+ """
164
+ Return a dictionary snapshot of the account state at or immediately before the given timestamp.
165
+
166
+ If timestamp is None the current UTC time is used. The timestamp is normalized to a timezone-aware UTC value. The method finds the most recent stored tick whose timestamp is <= the requested time and returns a dict with the corresponding state:
167
+ - "timestamp": stored timestamp used
168
+ - "vests": own vesting shares at that tick
169
+ - "delegated_vests_in": mapping of incoming delegations at that tick
170
+ - "delegated_vests_out": mapping of outgoing delegations at that tick
171
+ - "sp_own": Hive Power equivalent of own vests at that tick
172
+ - "sp_eff": effective Hive Power (own + delegated_in - delegated_out) at that tick
173
+ - "hive": liquid HIVE balance at that tick
174
+ - "hbd": liquid HBD balance at that tick
175
+ - "index": index into the internal arrays for that tick
176
+
177
+ Returns an empty dict if the requested timestamp is earlier than the earliest stored timestamp.
178
+ """
140
179
  if timestamp is None:
141
180
  timestamp = datetime.now(timezone.utc)
142
181
  timestamp = addTzInfo(timestamp)
@@ -150,20 +189,13 @@ class AccountSnapshot(list):
150
189
  own = self.own_vests[index]
151
190
  din = self.delegated_vests_in[index]
152
191
  dout = self.delegated_vests_out[index]
153
- steem = self.own_steem[index]
154
- sbd = self.own_sbd[index]
192
+ hive = self.own_hive[index]
193
+ hbd = self.own_hbd[index]
155
194
  sum_in = sum([din[key].amount for key in din])
156
195
  sum_out = sum([dout[key].amount for key in dout])
157
- from nectar import Steem
158
-
159
- if isinstance(self.blockchain, Steem):
160
- sp_in = self.blockchain.vests_to_sp(sum_in, timestamp=ts)
161
- sp_out = self.blockchain.vests_to_sp(sum_out, timestamp=ts)
162
- sp_own = self.blockchain.vests_to_sp(own, timestamp=ts)
163
- else:
164
- sp_in = self.blockchain.vests_to_hp(sum_in, timestamp=ts)
165
- sp_out = self.blockchain.vests_to_hp(sum_out, timestamp=ts)
166
- sp_own = self.blockchain.vests_to_hp(own, timestamp=ts)
196
+ sp_in = self.blockchain.vests_to_hp(sum_in, timestamp=ts)
197
+ sp_out = self.blockchain.vests_to_hp(sum_out, timestamp=ts)
198
+ sp_own = self.blockchain.vests_to_hp(own, timestamp=ts)
167
199
  sp_eff = sp_own + sp_in - sp_out
168
200
  return {
169
201
  "timestamp": ts,
@@ -172,40 +204,76 @@ class AccountSnapshot(list):
172
204
  "delegated_vests_out": dout,
173
205
  "sp_own": sp_own,
174
206
  "sp_eff": sp_eff,
175
- "steem": steem,
176
- "sbd": sbd,
207
+ "hive": hive,
208
+ "hbd": hbd,
177
209
  "index": index,
178
210
  }
179
211
 
180
212
  def get_account_history(self, start=None, stop=None, use_block_num=True):
181
- """Uses account history to fetch all related ops
182
-
183
- :param start: start number/date of transactions to
184
- return (*optional*)
185
- :type start: int, datetime
186
- :param stop: stop number/date of transactions to
187
- return (*optional*)
188
- :type stop: int, datetime
189
- :param bool use_block_num: if true, start and stop are block numbers,
190
- otherwise virtual OP count numbers.
213
+ """
214
+ Populate the snapshot with the account's history between start and stop.
191
215
 
216
+ Fetches operations from the underlying Account.history iterator and replaces the snapshot's contents with those operations. If start/stop are provided they may be block numbers or datetimes; set use_block_num=False to interpret them as virtual operation indices/timestamps instead of block numbers.
192
217
  """
193
218
  super(AccountSnapshot, self).__init__(
194
219
  [h for h in self.account.history(start=start, stop=stop, use_block_num=use_block_num)]
195
220
  )
196
221
 
197
- def update_rewards(self, timestamp, curation_reward, author_vests, author_steem, author_sbd):
222
+ def update_rewards(self, timestamp, curation_reward, author_vests, author_hive, author_hbd):
223
+ """
224
+ Record a reward event at a given timestamp.
225
+
226
+ Appends the reward timestamp, the curation portion, and the author's reward components (vests, hive, hbd)
227
+ to the snapshot's internal reward arrays so they can be used by later aggregation and analysis.
228
+
229
+ Parameters:
230
+ timestamp (datetime or int): Event time (timezone-aware datetime or block/time integer) for the reward.
231
+ curation_reward (Amount or number): Curation reward amount (in vests or numeric representation used by the codebase).
232
+ author_vests (Amount or number): Author reward in vesting shares.
233
+ author_hive (Amount or number): Author reward in liquid HIVE.
234
+ author_hbd (Amount or number): Author reward in HBD.
235
+
236
+ Returns:
237
+ None
238
+ """
198
239
  self.reward_timestamps.append(timestamp)
199
240
  self.curation_rewards.append(curation_reward)
200
- self.author_rewards.append(
201
- {"vests": author_vests, "steem": author_steem, "sbd": author_sbd}
202
- )
241
+ self.author_rewards.append({"vests": author_vests, "hive": author_hive, "hbd": author_hbd})
203
242
 
204
243
  def update_out_vote(self, timestamp, weight):
244
+ """
245
+ Record an outbound vote event.
246
+
247
+ Appends the vote timestamp and weight to the snapshot's outbound-vote arrays for later voting-power and history calculations.
248
+
249
+ Parameters:
250
+ timestamp (datetime | int): Time of the vote (timezone-aware datetime or block timestamp).
251
+ weight (int): Vote weight as an integer (e.g., range -10000..10000).
252
+ """
205
253
  self.out_vote_timestamp.append(timestamp)
206
254
  self.out_vote_weight.append(weight)
207
255
 
208
256
  def update_in_vote(self, timestamp, weight, op):
257
+ """
258
+ Record an incoming vote event by parsing a Vote operation and appending its data to the snapshot's in-vote arrays.
259
+
260
+ Parses the provided operation into a Vote, refreshes it, and on success appends:
261
+ - timestamp to in_vote_timestamp
262
+ - weight to in_vote_weight
263
+ - the voter's reputation to in_vote_rep (as int)
264
+ - the vote's rshares to in_vote_rshares (as int)
265
+
266
+ Parameters:
267
+ timestamp: datetime
268
+ Time of the vote event (should be timezone-aware).
269
+ weight: int
270
+ Vote weight as provided by the operation.
271
+ op:
272
+ Raw operation data used to construct the Vote.
273
+
274
+ Notes:
275
+ If the operation cannot be parsed into a valid Vote, the function prints an error message and returns without modifying the snapshot.
276
+ """
209
277
  v = Vote(op)
210
278
  try:
211
279
  v.refresh()
@@ -217,31 +285,38 @@ class AccountSnapshot(list):
217
285
  print("Could not find: %s" % v)
218
286
  return
219
287
 
220
- def update(self, timestamp, own, delegated_in=None, delegated_out=None, steem=0, sbd=0):
221
- """Updates the internal state arrays
222
-
223
- :param datetime timestamp: datetime of the update
224
- :param own: vests
225
- :type own: amount.Amount, float
226
- :param dict delegated_in: Incoming delegation
227
- :param dict delegated_out: Outgoing delegation
228
- :param steem: steem
229
- :type steem: amount.Amount, float
230
- :param sbd: sbd
231
- :type sbd: amount.Amount, float
232
-
288
+ def update(self, timestamp, own, delegated_in=None, delegated_out=None, hive=0, hbd=0):
289
+ """
290
+ Update internal time-series state with a new account event.
291
+
292
+ Appends two timeline entries: a one-second "pre-tick" preserving the previous state at timestamp - 1s, then a tick at timestamp with updated balances and delegation maps. This updates the snapshot's arrays for timestamps, own vests, liquid HIVE/HBD balances, and incoming/outgoing vesting delegations.
293
+
294
+ Parameters:
295
+ timestamp (datetime): Event time (timezone-aware). A "pre-tick" is created at timestamp - 1s.
296
+ own (Amount or float): Change in the account's own vesting shares (vests) to apply at the tick.
297
+ delegated_in (dict or None): Incoming delegation change of form {"account": name, "amount": vests} or None.
298
+ If amount == 0 the delegation entry for that account is removed.
299
+ delegated_out (dict or None): Outgoing delegation change. Typical forms:
300
+ - {"account": name, "amount": vests} to add/update a non-zero outgoing delegation.
301
+ - {"account": None, "amount": vests} indicates a return_vesting_delegation; the matching outgoing entry with the same amount is removed.
302
+ If omitted or empty, outgoing delegations are unchanged.
303
+ hive (Amount or float): Change in liquid HIVE to apply at the tick.
304
+ hbd (Amount or float): Change in liquid HBD to apply at the tick.
305
+
306
+ Returns:
307
+ None
233
308
  """
234
309
  self.timestamps.append(timestamp - timedelta(seconds=1))
235
310
  self.own_vests.append(self.own_vests[-1])
236
- self.own_steem.append(self.own_steem[-1])
237
- self.own_sbd.append(self.own_sbd[-1])
311
+ self.own_hive.append(self.own_hive[-1])
312
+ self.own_hbd.append(self.own_hbd[-1])
238
313
  self.delegated_vests_in.append(self.delegated_vests_in[-1])
239
314
  self.delegated_vests_out.append(self.delegated_vests_out[-1])
240
315
 
241
316
  self.timestamps.append(timestamp)
242
317
  self.own_vests.append(self.own_vests[-1] + own)
243
- self.own_steem.append(self.own_steem[-1] + steem)
244
- self.own_sbd.append(self.own_sbd[-1] + sbd)
318
+ self.own_hive.append(self.own_hive[-1] + hive)
319
+ self.own_hbd.append(self.own_hbd[-1] + hbd)
245
320
 
246
321
  new_deleg = dict(self.delegated_vests_in[-1])
247
322
  if delegated_in is not None and delegated_in:
@@ -309,33 +384,40 @@ class AccountSnapshot(list):
309
384
  def parse_op(
310
385
  self, op, only_ops=[], enable_rewards=False, enable_out_votes=False, enable_in_votes=False
311
386
  ):
312
- """Parse account history operation"""
387
+ """
388
+ Parse a single account-history operation and update the snapshot's internal state.
389
+
390
+ Parses the provided operation dictionary `op` (expects keys like "type" and "timestamp"), converts amounts using the snapshot's blockchain instance, and applies its effect to the snapshot by calling the appropriate update methods (e.g. update, update_rewards, update_out_vote, update_in_vote). Handles Hive-specific operations such as account creation, transfers, vesting/delegation, reward payouts, order fills, conversions, interest, votes, and hardfork-related adjustments. Many other operation types are intentionally ignored.
391
+
392
+ Parameters:
393
+ op (dict): A single operation entry from account history. Must contain a parsable "timestamp" and a "type" key; other required keys depend on the operation type.
394
+ only_ops (list): If non-empty, treat operations listed here as affecting balances/votes even when reward/vote-collection flags are disabled.
395
+ enable_rewards (bool): When True, record reward aggregates via update_rewards in addition to applying balance changes.
396
+ enable_out_votes (bool): When True, record outbound votes (this account as voter) via update_out_vote.
397
+ enable_in_votes (bool): When True, record inbound votes (this account as author/recipient) via update_in_vote.
398
+
399
+ Returns:
400
+ None
401
+ """
313
402
  ts = parse_time(op["timestamp"])
314
403
 
315
404
  if op["type"] == "account_create":
316
- fee_steem = Amount(op["fee"], blockchain_instance=self.blockchain).amount
317
- fee_vests = self.blockchain.sp_to_vests(
405
+ fee_hive = Amount(op["fee"], blockchain_instance=self.blockchain).amount
406
+ fee_vests = self.blockchain.hp_to_vests(
318
407
  Amount(op["fee"], blockchain_instance=self.blockchain).amount, timestamp=ts
319
408
  )
320
409
  if op["new_account_name"] == self.account["name"]:
321
410
  self.update(ts, fee_vests, 0, 0)
322
411
  return
323
412
  if op["creator"] == self.account["name"]:
324
- self.update(ts, 0, 0, 0, fee_steem * (-1), 0)
413
+ self.update(ts, 0, 0, 0, fee_hive * (-1), 0)
325
414
  return
326
415
 
327
- elif op["type"] == "account_create_with_delegation":
328
- fee_steem = Amount(op["fee"], blockchain_instance=self.blockchain).amount
329
- from nectar import Steem
330
-
331
- if isinstance(self.blockchain, Steem):
332
- fee_vests = self.blockchain.sp_to_vests(
333
- Amount(op["fee"], blockchain_instance=self.blockchain).amount, timestamp=ts
334
- )
335
- else:
336
- fee_vests = self.blockchain.hp_to_vests(
337
- Amount(op["fee"], blockchain_instance=self.blockchain).amount, timestamp=ts
338
- )
416
+ if op["type"] == "account_create_with_delegation":
417
+ fee_hive = Amount(op["fee"], blockchain_instance=self.blockchain).amount
418
+ fee_vests = self.blockchain.hp_to_vests(
419
+ Amount(op["fee"], blockchain_instance=self.blockchain).amount, timestamp=ts
420
+ )
339
421
  if op["new_account_name"] == self.account["name"]:
340
422
  if Amount(op["delegation"], blockchain_instance=self.blockchain).amount > 0:
341
423
  delegation = {
@@ -352,7 +434,7 @@ class AccountSnapshot(list):
352
434
  "account": op["new_account_name"],
353
435
  "amount": Amount(op["delegation"], blockchain_instance=self.blockchain),
354
436
  }
355
- self.update(ts, 0, 0, delegation, fee_steem * (-1), 0)
437
+ self.update(ts, 0, 0, delegation, fee_hive * (-1), 0)
356
438
  return
357
439
 
358
440
  elif op["type"] == "delegate_vesting_shares":
@@ -370,14 +452,14 @@ class AccountSnapshot(list):
370
452
  amount = Amount(op["amount"], blockchain_instance=self.blockchain)
371
453
  if op["from"] == self.account["name"]:
372
454
  if amount.symbol == self.blockchain.blockchain_symbol:
373
- self.update(ts, 0, 0, 0, amount * (-1), 0)
455
+ self.update(ts, 0, None, None, hive=amount * (-1), hbd=0)
374
456
  elif amount.symbol == self.blockchain.backed_token_symbol:
375
- self.update(ts, 0, 0, 0, 0, amount * (-1))
457
+ self.update(ts, 0, None, None, hive=0, hbd=amount * (-1))
376
458
  if op["to"] == self.account["name"]:
377
459
  if amount.symbol == self.blockchain.blockchain_symbol:
378
- self.update(ts, 0, 0, 0, amount, 0)
460
+ self.update(ts, 0, None, None, hive=amount, hbd=0)
379
461
  elif amount.symbol == self.blockchain.backed_token_symbol:
380
- self.update(ts, 0, 0, 0, 0, amount)
462
+ self.update(ts, 0, None, None, hive=0, hbd=amount)
381
463
  return
382
464
 
383
465
  elif op["type"] == "fill_order":
@@ -385,35 +467,32 @@ class AccountSnapshot(list):
385
467
  open_pays = Amount(op["open_pays"], blockchain_instance=self.blockchain)
386
468
  if op["current_owner"] == self.account["name"]:
387
469
  if current_pays.symbol == self.blockchain.token_symbol:
388
- self.update(ts, 0, 0, 0, current_pays * (-1), open_pays)
470
+ self.update(ts, 0, None, None, hive=current_pays * (-1), hbd=open_pays)
389
471
  elif current_pays.symbol == self.blockchain.backed_token_symbol:
390
- self.update(ts, 0, 0, 0, open_pays, current_pays * (-1))
472
+ self.update(ts, 0, None, None, hive=open_pays, hbd=current_pays * (-1))
391
473
  if op["open_owner"] == self.account["name"]:
392
474
  if current_pays.symbol == self.blockchain.token_symbol:
393
- self.update(ts, 0, 0, 0, current_pays, open_pays * (-1))
475
+ self.update(ts, 0, None, None, hive=current_pays, hbd=open_pays * (-1))
394
476
  elif current_pays.symbol == self.blockchain.backed_token_symbol:
395
- self.update(ts, 0, 0, 0, open_pays * (-1), current_pays)
477
+ self.update(ts, 0, None, None, hive=open_pays * (-1), hbd=current_pays)
396
478
  return
397
479
 
398
480
  elif op["type"] == "transfer_to_vesting":
399
- steem = Amount(op["amount"], blockchain_instance=self.blockchain)
400
- from nectar import Steem
401
-
402
- if isinstance(self.blockchain, Steem):
403
- vests = self.blockchain.sp_to_vests(steem.amount, timestamp=ts)
404
- else:
405
- vests = self.blockchain.hp_to_vests(steem.amount, timestamp=ts)
481
+ hive_amt = Amount(op["amount"], blockchain_instance=self.blockchain)
482
+ vests = self.blockchain.hp_to_vests(hive_amt.amount, timestamp=ts)
406
483
  if op["from"] == self.account["name"] and op["to"] == self.account["name"]:
407
- self.update(ts, vests, 0, 0, steem * (-1), 0) # power up from and to given account
484
+ self.update(
485
+ ts, vests, 0, 0, hive_amt * (-1), 0
486
+ ) # power up from and to given account
408
487
  elif op["from"] != self.account["name"] and op["to"] == self.account["name"]:
409
488
  self.update(ts, vests, 0, 0, 0, 0) # power up from another account
410
489
  else: # op['from'] == self.account["name"] and op['to'] != self.account["name"]
411
- self.update(ts, 0, 0, 0, steem * (-1), 0) # power up to another account
490
+ self.update(ts, 0, 0, 0, hive_amt * (-1), 0) # power up to another account
412
491
  return
413
492
 
414
493
  elif op["type"] == "fill_vesting_withdraw":
415
494
  vests = Amount(op["withdrawn"], blockchain_instance=self.blockchain)
416
- self.update(ts, vests * (-1), 0, 0)
495
+ self.update(ts, vests * (-1), None, None, hive=0, hbd=0)
417
496
  return
418
497
 
419
498
  elif op["type"] == "return_vesting_delegation":
@@ -421,21 +500,21 @@ class AccountSnapshot(list):
421
500
  "account": None,
422
501
  "amount": Amount(op["vesting_shares"], blockchain_instance=self.blockchain),
423
502
  }
424
- self.update(ts, 0, 0, delegation)
503
+ self.update(ts, 0, None, delegated_out=delegation)
425
504
  return
426
505
 
427
506
  elif op["type"] == "claim_reward_balance":
428
507
  vests = Amount(op["reward_vests"], blockchain_instance=self.blockchain)
429
- steem = Amount(op["reward_steem"], blockchain_instance=self.blockchain)
430
- sbd = Amount(op["reward_sbd"], blockchain_instance=self.blockchain)
431
- self.update(ts, vests, 0, 0, steem, sbd)
508
+ hive = Amount(op["reward_hive"], blockchain_instance=self.blockchain)
509
+ hbd = Amount(op["reward_hbd"], blockchain_instance=self.blockchain)
510
+ self.update(ts, vests, None, None, hive=hive, hbd=hbd)
432
511
  return
433
512
 
434
513
  elif op["type"] == "curation_reward":
435
514
  if "curation_reward" in only_ops or enable_rewards:
436
515
  vests = Amount(op["reward"], blockchain_instance=self.blockchain)
437
516
  if "curation_reward" in only_ops:
438
- self.update(ts, vests, 0, 0)
517
+ self.update(ts, vests, None, None, hive=0, hbd=0)
439
518
  if enable_rewards:
440
519
  self.update_rewards(ts, vests, 0, 0, 0)
441
520
  return
@@ -443,29 +522,29 @@ class AccountSnapshot(list):
443
522
  elif op["type"] == "author_reward":
444
523
  if "author_reward" in only_ops or enable_rewards:
445
524
  vests = Amount(op["vesting_payout"], blockchain_instance=self.blockchain)
446
- steem = Amount(op["steem_payout"], blockchain_instance=self.blockchain)
447
- sbd = Amount(op["sbd_payout"], blockchain_instance=self.blockchain)
525
+ hive = Amount(op["hive_payout"], blockchain_instance=self.blockchain)
526
+ hbd = Amount(op["hbd_payout"], blockchain_instance=self.blockchain)
448
527
  if "author_reward" in only_ops:
449
- self.update(ts, vests, 0, 0, steem, sbd)
528
+ self.update(ts, vests, None, None, hive=hive, hbd=hbd)
450
529
  if enable_rewards:
451
- self.update_rewards(ts, 0, vests, steem, sbd)
530
+ self.update_rewards(ts, 0, vests, hive, hbd)
452
531
  return
453
532
 
454
533
  elif op["type"] == "producer_reward":
455
534
  vests = Amount(op["vesting_shares"], blockchain_instance=self.blockchain)
456
- self.update(ts, vests, 0, 0)
535
+ self.update(ts, vests, None, None, hive=0, hbd=0)
457
536
  return
458
537
 
459
538
  elif op["type"] == "comment_benefactor_reward":
460
539
  if op["benefactor"] == self.account["name"]:
461
540
  if "reward" in op:
462
541
  vests = Amount(op["reward"], blockchain_instance=self.blockchain)
463
- self.update(ts, vests, 0, 0)
542
+ self.update(ts, vests, None, None, hive=0, hbd=0)
464
543
  else:
465
544
  vests = Amount(op["vesting_payout"], blockchain_instance=self.blockchain)
466
- steem = Amount(op["steem_payout"], blockchain_instance=self.blockchain)
467
- sbd = Amount(op["sbd_payout"], blockchain_instance=self.blockchain)
468
- self.update(ts, vests, 0, 0, steem, sbd)
545
+ hive = Amount(op["hive_payout"], blockchain_instance=self.blockchain)
546
+ hbd = Amount(op["hbd_payout"], blockchain_instance=self.blockchain)
547
+ self.update(ts, vests, None, None, hive=hive, hbd=hbd)
469
548
  return
470
549
  else:
471
550
  return
@@ -474,12 +553,12 @@ class AccountSnapshot(list):
474
553
  amount_in = Amount(op["amount_in"], blockchain_instance=self.blockchain)
475
554
  amount_out = Amount(op["amount_out"], blockchain_instance=self.blockchain)
476
555
  if op["owner"] == self.account["name"]:
477
- self.update(ts, 0, 0, 0, amount_out, amount_in * (-1))
556
+ self.update(ts, 0, None, None, hive=amount_out, hbd=amount_in * (-1))
478
557
  return
479
558
 
480
559
  elif op["type"] == "interest":
481
560
  interest = Amount(op["interest"], blockchain_instance=self.blockchain)
482
- self.update(ts, 0, 0, 0, 0, interest)
561
+ self.update(ts, 0, None, None, hive=0, hbd=interest)
483
562
  return
484
563
 
485
564
  elif op["type"] == "vote":
@@ -494,9 +573,9 @@ class AccountSnapshot(list):
494
573
 
495
574
  elif op["type"] == "hardfork_hive":
496
575
  vests = Amount(op["vests_converted"])
497
- hbd = Amount(op["steem_transferred"])
498
- hive = Amount(op["sbd_transferred"])
499
- self.update(ts, vests * (-1), 0, 0, hive * (-1), hbd * (-1))
576
+ hbd = Amount(op["hbd_transferred"])
577
+ hive = Amount(op["hive_transferred"])
578
+ self.update(ts, vests * (-1), None, None, hive=hive * (-1), hbd=hbd * (-1))
500
579
 
501
580
  elif op["type"] in [
502
581
  "comment",
@@ -522,7 +601,19 @@ class AccountSnapshot(list):
522
601
  return
523
602
 
524
603
  def build_sp_arrays(self):
525
- """Builds the own_sp and eff_sp array"""
604
+ """
605
+ Build timelines of own and effective Hive Power (HP) for each stored timestamp.
606
+
607
+ For every timestamp in the snapshot, convert the account's own vesting shares and the
608
+ sum of delegated-in/out vesting shares to Hive Power via the blockchain's
609
+ `vests_to_hp` conversion and populate:
610
+ - self.own_sp: HP equivalent of the account's own vesting shares at each timestamp.
611
+ - self.eff_sp: effective HP = own HP + HP delegated in - HP delegated out at each timestamp.
612
+
613
+ This method mutates self.own_sp and self.eff_sp in-place and relies on
614
+ self.timestamps, self.own_vests, self.delegated_vests_in, self.delegated_vests_out,
615
+ and self.blockchain.vests_to_hp(timestamp=...).
616
+ """
526
617
  self.own_sp = []
527
618
  self.eff_sp = []
528
619
  for ts, own, din, dout in zip(
@@ -530,16 +621,9 @@ class AccountSnapshot(list):
530
621
  ):
531
622
  sum_in = sum([din[key].amount for key in din])
532
623
  sum_out = sum([dout[key].amount for key in dout])
533
- from nectar import Steem
534
-
535
- if isinstance(self.blockchain, Steem):
536
- sp_in = self.blockchain.vests_to_sp(sum_in, timestamp=ts)
537
- sp_out = self.blockchain.vests_to_sp(sum_out, timestamp=ts)
538
- sp_own = self.blockchain.vests_to_sp(own, timestamp=ts)
539
- else:
540
- sp_in = self.blockchain.vests_to_hp(sum_in, timestamp=ts)
541
- sp_out = self.blockchain.vests_to_hp(sum_out, timestamp=ts)
542
- sp_own = self.blockchain.vests_to_hp(own, timestamp=ts)
624
+ sp_in = self.blockchain.vests_to_hp(sum_in, timestamp=ts)
625
+ sp_out = self.blockchain.vests_to_hp(sum_out, timestamp=ts)
626
+ sp_own = self.blockchain.vests_to_hp(own, timestamp=ts)
543
627
 
544
628
  sp_eff = sp_own + sp_in - sp_out
545
629
  self.own_sp.append(sp_own)
@@ -558,30 +642,45 @@ class AccountSnapshot(list):
558
642
  self.rep_timestamp.append(ts)
559
643
 
560
644
  def build_vp_arrays(self):
561
- """Build vote power arrays"""
645
+ """
646
+ Build timelines for upvote and downvote voting power.
647
+
648
+ Populates the following instance arrays with parallel timestamps and voting-power values:
649
+ - self.vp_timestamp, self.vp: upvoting power timeline
650
+ - self.downvote_vp_timestamp, self.downvote_vp: downvoting power timeline
651
+
652
+ The method iterates over recorded outgoing votes (self.out_vote_timestamp / self.out_vote_weight),
653
+ applies Hive vote-regeneration rules (using HIVE_VOTE_REGENERATION_SECONDS and HIVE_100_PERCENT),
654
+ accounts for the HF_21 downvote timing change, and models vote drains via the blockchain's
655
+ _vote/resulting calculation and the account's manabar recharge intervals (account.get_manabar_recharge_timedelta).
656
+ Values are stored as integer percentage units where HIVE_100_PERCENT (typically 10000) represents 100.00%.
657
+
658
+ Side effects:
659
+ - Modifies self.vp_timestamp, self.vp, self.downvote_vp_timestamp, and self.downvote_vp in place.
660
+ """
562
661
  self.vp_timestamp = [self.timestamps[1]]
563
- self.vp = [STEEM_100_PERCENT]
662
+ self.vp = [HIVE_100_PERCENT]
564
663
  HF_21 = datetime(2019, 8, 27, 15, tzinfo=timezone.utc)
565
664
  if self.timestamps[1] > HF_21:
566
665
  self.downvote_vp_timestamp = [self.timestamps[1]]
567
666
  else:
568
667
  self.downvote_vp_timestamp = [HF_21]
569
- self.downvote_vp = [STEEM_100_PERCENT]
668
+ self.downvote_vp = [HIVE_100_PERCENT]
570
669
 
571
670
  for ts, weight in zip(self.out_vote_timestamp, self.out_vote_weight):
572
671
  regenerated_vp = 0
573
672
  if ts > HF_21 and weight < 0:
574
673
  self.downvote_vp.append(self.downvote_vp[-1])
575
- if self.downvote_vp[-1] < STEEM_100_PERCENT:
674
+ if self.downvote_vp[-1] < HIVE_100_PERCENT:
576
675
  regenerated_vp = (
577
676
  ((ts - self.downvote_vp_timestamp[-1]).total_seconds())
578
- * STEEM_100_PERCENT
579
- / STEEM_VOTE_REGENERATION_SECONDS
677
+ * HIVE_100_PERCENT
678
+ / HIVE_VOTE_REGENERATION_SECONDS
580
679
  )
581
680
  self.downvote_vp[-1] += int(regenerated_vp)
582
681
 
583
- if self.downvote_vp[-1] > STEEM_100_PERCENT:
584
- self.downvote_vp[-1] = STEEM_100_PERCENT
682
+ if self.downvote_vp[-1] > HIVE_100_PERCENT:
683
+ self.downvote_vp[-1] = HIVE_100_PERCENT
585
684
  recharge_time = self.account.get_manabar_recharge_timedelta(
586
685
  {"current_mana_pct": self.downvote_vp[-2] / 100}
587
686
  )
@@ -589,44 +688,44 @@ class AccountSnapshot(list):
589
688
  self.downvote_vp_timestamp.append(
590
689
  self.downvote_vp_timestamp[-1] + recharge_time
591
690
  )
592
- self.downvote_vp.append(STEEM_100_PERCENT)
691
+ self.downvote_vp.append(HIVE_100_PERCENT)
593
692
 
594
693
  # Add charged downvote VP just before new Vote
595
694
  self.downvote_vp_timestamp.append(ts - timedelta(seconds=1))
596
695
  self.downvote_vp.append(
597
- min([STEEM_100_PERCENT, self.downvote_vp[-1] + regenerated_vp])
696
+ min([HIVE_100_PERCENT, self.downvote_vp[-1] + regenerated_vp])
598
697
  )
599
698
 
600
699
  self.downvote_vp[-1] -= (
601
- self.blockchain._calc_resulting_vote(STEEM_100_PERCENT, weight) * 4
700
+ self.blockchain._calc_resulting_vote(HIVE_100_PERCENT, weight) * 4
602
701
  )
603
702
  # Downvote mana pool is 1/4th of the upvote mana pool, so it gets drained 4 times as quick
604
703
  if self.downvote_vp[-1] < 0:
605
704
  # There's most likely a better solution to this that what I did here
606
705
  self.vp.append(self.vp[-1])
607
706
 
608
- if self.vp[-1] < STEEM_100_PERCENT:
707
+ if self.vp[-1] < HIVE_100_PERCENT:
609
708
  regenerated_vp = (
610
709
  ((ts - self.vp_timestamp[-1]).total_seconds())
611
- * STEEM_100_PERCENT
612
- / STEEM_VOTE_REGENERATION_SECONDS
710
+ * HIVE_100_PERCENT
711
+ / HIVE_VOTE_REGENERATION_SECONDS
613
712
  )
614
713
  self.vp[-1] += int(regenerated_vp)
615
714
 
616
- if self.vp[-1] > STEEM_100_PERCENT:
617
- self.vp[-1] = STEEM_100_PERCENT
715
+ if self.vp[-1] > HIVE_100_PERCENT:
716
+ self.vp[-1] = HIVE_100_PERCENT
618
717
  recharge_time = self.account.get_manabar_recharge_timedelta(
619
718
  {"current_mana_pct": self.vp[-2] / 100}
620
719
  )
621
720
  # Add full VP once fully charged
622
721
  self.vp_timestamp.append(self.vp_timestamp[-1] + recharge_time)
623
- self.vp.append(STEEM_100_PERCENT)
624
- if self.vp[-1] == STEEM_100_PERCENT and ts - self.vp_timestamp[-1] > timedelta(
722
+ self.vp.append(HIVE_100_PERCENT)
723
+ if self.vp[-1] == HIVE_100_PERCENT and ts - self.vp_timestamp[-1] > timedelta(
625
724
  seconds=1
626
725
  ):
627
726
  # Add charged VP just before new Vote
628
727
  self.vp_timestamp.append(ts - timedelta(seconds=1))
629
- self.vp.append(min([STEEM_100_PERCENT, self.vp[-1] + regenerated_vp]))
728
+ self.vp.append(min([HIVE_100_PERCENT, self.vp[-1] + regenerated_vp]))
630
729
  self.vp[-1] += self.downvote_vp[-1] / 4
631
730
  if self.vp[-1] < 0:
632
731
  self.vp[-1] = 0
@@ -638,28 +737,28 @@ class AccountSnapshot(list):
638
737
  else:
639
738
  self.vp.append(self.vp[-1])
640
739
 
641
- if self.vp[-1] < STEEM_100_PERCENT:
740
+ if self.vp[-1] < HIVE_100_PERCENT:
642
741
  regenerated_vp = (
643
742
  ((ts - self.vp_timestamp[-1]).total_seconds())
644
- * STEEM_100_PERCENT
645
- / STEEM_VOTE_REGENERATION_SECONDS
743
+ * HIVE_100_PERCENT
744
+ / HIVE_VOTE_REGENERATION_SECONDS
646
745
  )
647
746
  self.vp[-1] += int(regenerated_vp)
648
747
 
649
- if self.vp[-1] > STEEM_100_PERCENT:
650
- self.vp[-1] = STEEM_100_PERCENT
748
+ if self.vp[-1] > HIVE_100_PERCENT:
749
+ self.vp[-1] = HIVE_100_PERCENT
651
750
  recharge_time = self.account.get_manabar_recharge_timedelta(
652
751
  {"current_mana_pct": self.vp[-2] / 100}
653
752
  )
654
753
  # Add full VP once fully charged
655
754
  self.vp_timestamp.append(self.vp_timestamp[-1] + recharge_time)
656
- self.vp.append(STEEM_100_PERCENT)
657
- if self.vp[-1] == STEEM_100_PERCENT and ts - self.vp_timestamp[-1] > timedelta(
755
+ self.vp.append(HIVE_100_PERCENT)
756
+ if self.vp[-1] == HIVE_100_PERCENT and ts - self.vp_timestamp[-1] > timedelta(
658
757
  seconds=1
659
758
  ):
660
759
  # Add charged VP just before new Vote
661
760
  self.vp_timestamp.append(ts - timedelta(seconds=1))
662
- self.vp.append(min([STEEM_100_PERCENT, self.vp[-1] + regenerated_vp]))
761
+ self.vp.append(min([HIVE_100_PERCENT, self.vp[-1] + regenerated_vp]))
663
762
  self.vp[-1] -= self.blockchain._calc_resulting_vote(self.vp[-1], weight)
664
763
  if self.vp[-1] < 0:
665
764
  self.vp[-1] = 0
@@ -686,9 +785,37 @@ class AccountSnapshot(list):
686
785
  self.vp_timestamp.append(datetime.now(timezone.utc))
687
786
 
688
787
  def build_curation_arrays(self, end_date=None, sum_days=7):
689
- """Build curation arrays"""
690
- self.curation_per_1000_SP_timestamp = []
691
- self.curation_per_1000_SP = []
788
+ """
789
+ Compute curation-per-1000-HP time series and store them in
790
+ self.curation_per_1000_HP_timestamp and self.curation_per_1000_HP.
791
+
792
+ The method walks through recorded reward timestamps and curation rewards, converts
793
+ each curation reward (vests) to HP using the blockchain conversion, and divides
794
+ that reward by the effective stake (sp_eff) at the reward time to produce a
795
+ "curation per 1000 HP" value. Values are aggregated into contiguous windows of
796
+ length `sum_days`. Each window's aggregate is appended to
797
+ self.curation_per_1000_HP with the corresponding window end timestamp in
798
+ self.curation_per_1000_HP_timestamp.
799
+
800
+ Parameters:
801
+ end_date (datetime.datetime | None): End-boundary for the first aggregation
802
+ window. If None, it is set to the last reward timestamp minus the total
803
+ span of full `sum_days` windows that fit into the reward history.
804
+ sum_days (int): Window length in days for aggregation. Must be > 0.
805
+
806
+ Raises:
807
+ ValueError: If sum_days <= 0.
808
+
809
+ Notes:
810
+ - Uses self.blockchain.vests_to_hp(vests, timestamp=ts) to convert vests to HP.
811
+ - Uses self.get_data(timestamp=ts, index=index) to obtain the effective stake
812
+ (`sp_eff`) and to advance a cached index for efficient lookups.
813
+ - The per-window aggregation normalizes values to a "per 1000 HP" basis and
814
+ scales them by (7 / sum_days) so the resulting numbers are comparable to a
815
+ 7-day baseline.
816
+ """
817
+ self.curation_per_1000_HP_timestamp = []
818
+ self.curation_per_1000_HP = []
692
819
  if sum_days <= 0:
693
820
  raise ValueError("sum_days must be greater than 0")
694
821
  index = 0
@@ -699,12 +826,7 @@ class AccountSnapshot(list):
699
826
  for ts, vests in zip(self.reward_timestamps, self.curation_rewards):
700
827
  if vests == 0:
701
828
  continue
702
- from nectar import Steem
703
-
704
- if isinstance(self.blockchain, Steem):
705
- sp = self.blockchain.vests_to_sp(vests, timestamp=ts)
706
- else:
707
- sp = self.blockchain.vests_to_hp(vests, timestamp=ts)
829
+ sp = self.blockchain.vests_to_hp(vests, timestamp=ts)
708
830
  data = self.get_data(timestamp=ts, index=index)
709
831
  index = data["index"]
710
832
  if "sp_eff" in data and data["sp_eff"] > 0:
@@ -714,8 +836,8 @@ class AccountSnapshot(list):
714
836
  if ts < end_date:
715
837
  curation_sum += curation_1k_sp
716
838
  else:
717
- self.curation_per_1000_SP_timestamp.append(end_date)
718
- self.curation_per_1000_SP.append(curation_sum)
839
+ self.curation_per_1000_HP_timestamp.append(end_date)
840
+ self.curation_per_1000_HP.append(curation_sum)
719
841
  end_date = end_date + timedelta(days=sum_days)
720
842
  curation_sum = 0
721
843