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/market.py CHANGED
@@ -29,9 +29,9 @@ log = logging.getLogger(__name__)
29
29
 
30
30
 
31
31
  class Market(dict):
32
- """This class allows to easily access Markets on the blockchain for trading, etc.
32
+ """This class allows access to the internal market for trading, etc. (Hive-only).
33
33
 
34
- :param Steem blockchain_instance: Steem instance
34
+ :param Hive blockchain_instance: Hive instance
35
35
  :param Asset base: Base asset
36
36
  :param Asset quote: Quote asset
37
37
  :returns: Blockchain Market
@@ -50,7 +50,7 @@ class Market(dict):
50
50
  * ``base-quote`` separated with ``-``
51
51
 
52
52
  .. note:: Throughout this library, the ``quote`` symbol will be
53
- presented first (e.g. ``STEEM:SBD`` with ``STEEM`` being the
53
+ presented first (e.g. ``HIVE:HBD`` with ``HIVE`` being the
54
54
  quote), while the ``base`` only refers to a secondary asset
55
55
  for a trade. This means, if you call
56
56
  :func:`nectar.market.Market.sell` or
@@ -61,17 +61,18 @@ class Market(dict):
61
61
 
62
62
  def __init__(self, base=None, quote=None, blockchain_instance=None, **kwargs):
63
63
  """
64
- Init Market
64
+ Create a Market mapping with "base" and "quote" Asset objects.
65
65
 
66
- :param nectar.steem.Steem blockchain_instance: Steem instance
67
- :param nectar.asset.Asset base: Base asset
68
- :param nectar.asset.Asset quote: Quote asset
66
+ Supports three initialization modes:
67
+ - Single-string market identifier (e.g., "HBD:HIVE" or "HIVE:HBD"): parsed into quote and base symbols and converted to Asset objects.
68
+ - Explicit base and quote (either Asset instances or values accepted by Asset): each converted to an Asset.
69
+ - No arguments: uses the blockchain instance's default token symbols (token_symbol as base, backed_token_symbol as quote).
70
+
71
+ The resolved Asset objects are stored in the instance as entries "base" and "quote". The blockchain instance used is the provided one or the shared global instance.
72
+
73
+ Raises:
74
+ ValueError: if the combination of arguments does not match any supported initialization mode.
69
75
  """
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
76
  self.blockchain = blockchain_instance or shared_blockchain_instance()
76
77
 
77
78
  if quote is None and isinstance(base, str):
@@ -97,9 +98,14 @@ class Market(dict):
97
98
  raise ValueError("Unknown Market config")
98
99
 
99
100
  def get_string(self, separator=":"):
100
- """Return a formated string that identifies the market, e.g. ``STEEM:SBD``
101
+ """
102
+ Return the market identifier as "QUOTE{separator}BASE" (e.g. "HIVE:HBD").
103
+
104
+ Parameters:
105
+ separator (str): Token placed between quote and base symbols. Defaults to ":".
101
106
 
102
- :param str separator: The separator of the assets (defaults to ``:``)
107
+ Returns:
108
+ str: Formatted market string in the form "<quote><separator><base>".
103
109
  """
104
110
  return "%s%s%s" % (self["quote"]["symbol"], separator, self["base"]["symbol"])
105
111
 
@@ -116,35 +122,21 @@ class Market(dict):
116
122
  )
117
123
 
118
124
  def ticker(self, raw_data=False):
119
- """Returns the ticker for all markets.
120
-
121
- Output Parameters:
122
-
123
- * ``latest``: Price of the order last filled
124
- * ``lowest_ask``: Price of the lowest ask
125
- * ``highest_bid``: Price of the highest bid
126
- * ``sbd_volume``: Volume of SBD
127
- * ``steem_volume``: Volume of STEEM
128
- * ``hbd_volume``: Volume of HBD
129
- * ``hive_volume``: Volume of HIVE
130
- * ``percent_change``: 24h change percentage (in %)
125
+ """
126
+ Return the market ticker for this Market (HIVE:HBD).
131
127
 
132
- .. note::
133
- Market is HIVE:HBD and prices are HBD per HIVE!
128
+ By default returns a dict with Price objects for 'highest_bid', 'latest', and 'lowest_ask',
129
+ a float 'percent_change' (24h), and Amount objects for 'hbd_volume' and 'hive_volume' when present.
130
+ If raw_data is True, returns the unprocessed RPC result.
134
131
 
135
- Sample Output:
132
+ Parameters:
133
+ raw_data (bool): If True, return the raw market_history RPC response instead of mapped objects.
136
134
 
137
- .. code-block:: js
138
-
139
- {
140
- 'highest_bid': 0.30100226633322913,
141
- 'latest': 0.0,
142
- 'lowest_ask': 0.3249636958897082,
143
- 'percent_change': 0.0,
144
- 'sbd_volume': 108329611.0,
145
- 'steem_volume': 355094043.0
146
- }
135
+ Returns:
136
+ dict or Any: Mapped ticker dictionary (prices as Price, volumes as Amount) or raw RPC data.
147
137
 
138
+ Notes:
139
+ Prices are expressed as HBD per HIVE.
148
140
  """
149
141
  data = {}
150
142
  # Core Exchange rate
@@ -173,46 +165,30 @@ class Market(dict):
173
165
  blockchain_instance=self.blockchain,
174
166
  )
175
167
  data["percent_change"] = float(ticker["percent_change"])
176
- if "sbd_volume" in ticker:
177
- data["sbd_volume"] = Amount(ticker["sbd_volume"], blockchain_instance=self.blockchain)
178
- elif "hbd_volume" in ticker:
168
+ if "hbd_volume" in ticker:
179
169
  data["hbd_volume"] = Amount(ticker["hbd_volume"], blockchain_instance=self.blockchain)
180
- if "steem_volume" in ticker:
181
- data["steem_volume"] = Amount(
182
- ticker["steem_volume"], blockchain_instance=self.blockchain
183
- )
184
- elif "hive_volume" in ticker:
170
+ if "hive_volume" in ticker:
185
171
  data["hive_volume"] = Amount(ticker["hive_volume"], blockchain_instance=self.blockchain)
186
172
 
187
173
  return data
188
174
 
189
175
  def volume24h(self, raw_data=False):
190
- """Returns the 24-hour volume for all markets, plus totals for primary currencies.
191
-
192
- Sample output:
193
-
194
- .. code-block:: js
176
+ """
177
+ Return 24-hour trading volume for this market.
195
178
 
196
- {
197
- "STEEM": 361666.63617,
198
- "SBD": 1087.0
199
- }
179
+ If raw_data is True, returns the raw result from the blockchain `market_history` RPC.
180
+ Otherwise, if the RPC result contains 'hbd_volume' and 'hive_volume', returns a dict mapping
181
+ asset symbols to Amount objects, e.g. { "HBD": Amount(...), "HIVE": Amount(...) }.
182
+ If the expected volume keys are not present, returns None.
200
183
 
184
+ Parameters:
185
+ raw_data (bool): If True, return the unprocessed RPC response.
201
186
  """
202
187
  self.blockchain.rpc.set_next_node_on_empty_reply(True)
203
188
  volume = self.blockchain.rpc.get_volume(api="market_history")
204
189
  if raw_data:
205
190
  return volume
206
- if "sbd_volume" in volume and "steem_volume" in volume:
207
- return {
208
- self["base"]["symbol"]: Amount(
209
- volume["sbd_volume"], blockchain_instance=self.blockchain
210
- ),
211
- self["quote"]["symbol"]: Amount(
212
- volume["steem_volume"], blockchain_instance=self.blockchain
213
- ),
214
- }
215
- elif "hbd_volume" in volume and "hive_volume" in volume:
191
+ if "hbd_volume" in volume and "hive_volume" in volume:
216
192
  return {
217
193
  self["base"]["symbol"]: Amount(
218
194
  volume["hbd_volume"], blockchain_instance=self.blockchain
@@ -223,7 +199,7 @@ class Market(dict):
223
199
  }
224
200
 
225
201
  def orderbook(self, limit=25, raw_data=False):
226
- """Returns the order book for SBD/STEEM market.
202
+ """Returns the order book for the HBD/HIVE market.
227
203
 
228
204
  :param int limit: Limit the amount of orders (default: 25)
229
205
 
@@ -233,12 +209,12 @@ class Market(dict):
233
209
 
234
210
  {
235
211
  'asks': [
236
- 380.510 STEEM 460.291 SBD @ 1.209669 SBD/STEEM,
237
- 53.785 STEEM 65.063 SBD @ 1.209687 SBD/STEEM
212
+ 380.510 HIVE 460.291 HBD @ 1.209669 HBD/HIVE,
213
+ 53.785 HIVE 65.063 HBD @ 1.209687 HBD/HIVE
238
214
  ],
239
215
  'bids': [
240
- 0.292 STEEM 0.353 SBD @ 1.208904 SBD/STEEM,
241
- 8.498 STEEM 10.262 SBD @ 1.207578 SBD/STEEM
216
+ 0.292 HIVE 0.353 HBD @ 1.208904 HBD/HIVE,
217
+ 8.498 HIVE 10.262 HBD @ 1.207578 HBD/HIVE
242
218
  ],
243
219
  'asks_date': [
244
220
  datetime.datetime(2018, 4, 30, 21, 7, 24, tzinfo=<UTC>),
@@ -257,19 +233,19 @@ class Market(dict):
257
233
  {
258
234
  'asks': [
259
235
  {
260
- 'order_price': {'base': '8.000 STEEM', 'quote': '9.618 SBD'},
236
+ 'order_price': {'base': '8.000 HIVE', 'quote': '9.618 HBD'},
261
237
  'real_price': '1.20225000000000004',
262
- 'steem': 4565,
263
- 'sbd': 5488,
238
+ 'hive': 4565,
239
+ 'hbd': 5488,
264
240
  'created': '2018-04-30T21:12:45'
265
241
  }
266
242
  ],
267
243
  'bids': [
268
244
  {
269
- 'order_price': {'base': '10.000 SBD', 'quote': '8.333 STEEM'},
245
+ 'order_price': {'base': '10.000 HBD', 'quote': '8.333 HIVE'},
270
246
  'real_price': '1.20004800192007677',
271
- 'steem': 8333,
272
- 'sbd': 10000,
247
+ 'hive': 8333,
248
+ 'hbd': 10000,
273
249
  'created': '2018-04-30T20:29:33'
274
250
  }
275
251
  ]
@@ -314,42 +290,17 @@ class Market(dict):
314
290
  return data
315
291
 
316
292
  def recent_trades(self, limit=25, raw_data=False):
317
- """Returns the order book for a given market. You may also
318
- specify "all" to get the orderbooks of all markets.
319
-
320
- :param int limit: Limit the amount of orders (default: 25)
321
- :param bool raw_data: when False, FilledOrder objects will be
322
- returned
323
-
324
- Sample output (raw_data=False):
325
-
326
- .. code-block:: none
327
-
328
- [
329
- (2018-04-30 21:00:54+00:00) 0.267 STEEM 0.323 SBD @ 1.209738 SBD/STEEM,
330
- (2018-04-30 20:59:30+00:00) 0.131 STEEM 0.159 SBD @ 1.213740 SBD/STEEM,
331
- (2018-04-30 20:55:45+00:00) 0.093 STEEM 0.113 SBD @ 1.215054 SBD/STEEM,
332
- (2018-04-30 20:55:30+00:00) 26.501 STEEM 32.058 SBD @ 1.209690 SBD/STEEM,
333
- (2018-04-30 20:55:18+00:00) 2.108 STEEM 2.550 SBD @ 1.209677 SBD/STEEM,
334
- ]
335
-
336
- Sample output (raw_data=True):
337
-
338
- .. code-block:: js
293
+ """
294
+ Return recent trades for this market.
339
295
 
340
- [
341
- {'date': '2018-04-30T21:02:45', 'current_pays': '0.235 SBD', 'open_pays': '0.194 STEEM'},
342
- {'date': '2018-04-30T21:02:03', 'current_pays': '24.494 SBD', 'open_pays': '20.248 STEEM'},
343
- {'date': '2018-04-30T20:48:30', 'current_pays': '175.464 STEEM', 'open_pays': '211.955 SBD'},
344
- {'date': '2018-04-30T20:48:30', 'current_pays': '0.999 STEEM', 'open_pays': '1.207 SBD'},
345
- {'date': '2018-04-30T20:47:54', 'current_pays': '0.273 SBD', 'open_pays': '0.225 STEEM'},
346
- ]
296
+ By default returns up to `limit` most recent trades wrapped as FilledOrder objects; if `raw_data` is True the raw trade dictionaries from the market_history API are returned instead.
347
297
 
348
- .. note:: Each bid is an instance of
349
- :class:`nectar.price.Order` and thus carries the keys
350
- ``base``, ``quote`` and ``price``. From those you can
351
- obtain the actual amounts for sale
298
+ Parameters:
299
+ limit (int): Maximum number of trades to retrieve (default: 25).
300
+ raw_data (bool): If True, return raw API trade entries; if False, return a list of FilledOrder instances constructed with this market's blockchain instance.
352
301
 
302
+ Returns:
303
+ list: A list of FilledOrder objects when `raw_data` is False, or a list of raw trade dicts as returned by the market_history API when `raw_data` is True.
353
304
  """
354
305
  self.blockchain.rpc.set_next_node_on_empty_reply(limit > 0)
355
306
  if self.blockchain.rpc.get_use_appbase():
@@ -450,36 +401,22 @@ class Market(dict):
450
401
  return ret
451
402
 
452
403
  def market_history(self, bucket_seconds=300, start_age=3600, end_age=0, raw_data=False):
453
- """Return the market history (filled orders).
404
+ """
405
+ Return market history buckets for a time window.
454
406
 
455
- :param int bucket_seconds: Bucket size in seconds (see
456
- `returnMarketHistoryBuckets()`)
457
- :param int start_age: Age (in seconds) of the start of the
458
- window (default: 1h/3600)
459
- :param int end_age: Age (in seconds) of the end of the window
460
- (default: now/0)
461
- :param bool raw_data: (optional) returns raw data if set True
407
+ This fetches aggregated market history buckets (filled orders) for the market over a window defined by start_age and end_age and grouped by bucket_seconds. bucket_seconds may be provided either as a numeric bucket size (seconds) or as an index into available buckets returned by market_history_buckets(). When raw_data is False any bucket "open" timestamp strings are normalized to a consistent formatted datetime string.
462
408
 
463
- Example:
409
+ Parameters:
410
+ bucket_seconds (int): Bucket size in seconds or an index into market_history_buckets().
411
+ start_age (int): Age in seconds from now to the start of the window (default 3600 seconds).
412
+ end_age (int): Age in seconds from now to the end of the window (default 0 = now).
413
+ raw_data (bool): If True, return the raw RPC response without normalizing timestamps.
464
414
 
465
- .. code-block:: js
466
-
467
- {
468
- 'close_sbd': 2493387,
469
- 'close_steem': 7743431,
470
- 'high_sbd': 1943872,
471
- 'high_steem': 5999610,
472
- 'id': '7.1.5252',
473
- 'low_sbd': 534928,
474
- 'low_steem': 1661266,
475
- 'open': '2016-07-08T11:25:00',
476
- 'open_sbd': 534928,
477
- 'open_steem': 1661266,
478
- 'sbd_volume': 9714435,
479
- 'seconds': 300,
480
- 'steem_volume': 30088443
481
- }
415
+ Returns:
416
+ list: A list of bucket dicts (or the raw RPC list when raw_data is True). Each bucket contains fields such as 'open', 'seconds', 'open_hbd', 'close_hbd', 'high_hbd', 'low_hbd', 'hbd_volume', 'open_hive', 'close_hive', 'high_hive', 'low_hive', 'hive_volume', and 'id' when available.
482
417
 
418
+ Raises:
419
+ ValueError: If bucket_seconds is not a valid bucket size or valid index into available buckets.
483
420
  """
484
421
  buckets = self.market_history_buckets()
485
422
  if bucket_seconds < 5 and bucket_seconds >= 0:
@@ -562,39 +499,29 @@ class Market(dict):
562
499
  orderid=None,
563
500
  returnOrderId=False,
564
501
  ):
565
- """Places a buy order in a given market
566
-
567
- :param float price: price denoted in ``base``/``quote``
568
- :param number amount: Amount of ``quote`` to buy
569
- :param number expiration: (optional) expiration time of the order in seconds (defaults to 7 days)
570
- :param bool killfill: flag that indicates if the order shall be killed if it is not filled (defaults to False)
571
- :param string account: Account name that executes that order
572
- :param string returnOrderId: If set to "head" or "irreversible" the call will wait for the tx to appear in
573
- the head/irreversible block and add the key "orderid" to the tx output
574
-
575
- Prices/Rates are denoted in 'base', i.e. the SBD_STEEM market
576
- is priced in STEEM per SBD.
577
-
578
- **Example:** in the SBD_STEEM market, a price of 300 means
579
- a SBD is worth 300 STEEM
502
+ """
503
+ Place a buy order (limit order) on this market.
580
504
 
581
- .. note::
505
+ Prices are expressed in the market's base/quote orientation (HIVE per HBD in HBD_HIVE). This method submits a limit-order-create operation that effectively places a sell order of the base asset to acquire the requested amount of the quote asset.
582
506
 
583
- All prices returned are in the **reversed** orientation as the
584
- market. I.e. in the STEEM/SBD market, prices are SBD per STEEM.
585
- That way you can multiply prices with `1.05` to get a +5%.
507
+ Parameters:
508
+ price (float or Price): Price expressed in base per quote (e.g., HIVE per HBD).
509
+ amount (number or str or Amount): Amount of the quote asset to buy.
510
+ expiration (int, optional): Order lifetime in seconds (default: configured order-expiration, typically 7 days).
511
+ killfill (bool, optional): If True, set fill_or_kill on the order (defaults to False).
512
+ account (str, optional): Account name that will own and broadcast the order. If omitted, default_account from config is used; a ValueError is raised if none is available.
513
+ orderid (int, optional): Explicit client-side order id. If omitted one is randomly generated.
514
+ returnOrderId (bool or str, optional): If truthy (or set to "head"/"irreversible"), the call will wait for the transaction and attach the assigned order id to the returned transaction under the "orderid" key.
586
515
 
587
- .. warning::
516
+ Returns:
517
+ dict: The finalized broadcast transaction object returned by the blockchain client. If returnOrderId was used, the dict includes an "orderid" field.
588
518
 
589
- Since buy orders are placed as
590
- limit-sell orders for the base asset,
591
- you may end up obtaining more of the
592
- buy asset than you placed the order
593
- for. Example:
519
+ Raises:
520
+ ValueError: If no account can be resolved.
521
+ AssertionError: If an Amount is provided whose asset symbol does not match the market quote.
594
522
 
595
- * You place and order to buy 10 SBD for 100 STEEM/SBD
596
- * This means that you actually place a sell order for 1000 STEEM in order to obtain **at least** 10 SBD
597
- * If an order on the market exists that sells SBD for cheaper, you will end up with more than 10 SBD
523
+ Notes:
524
+ - Because buy orders are implemented as limit-sell orders of the base asset, the trade can result in receiving more of the quote asset than requested if matching orders exist at better prices.
598
525
  """
599
526
  if not expiration:
600
527
  expiration = self.blockchain.config["order-expiration"]
@@ -660,27 +587,26 @@ class Market(dict):
660
587
  orderid=None,
661
588
  returnOrderId=False,
662
589
  ):
663
- """Places a sell order in a given market
664
-
665
- :param float price: price denoted in ``base``/``quote``
666
- :param number amount: Amount of ``quote`` to sell
667
- :param number expiration: (optional) expiration time of the order in seconds (defaults to 7 days)
668
- :param bool killfill: flag that indicates if the order shall be killed if it is not filled (defaults to False)
669
- :param string account: Account name that executes that order
670
- :param string returnOrderId: If set to "head" or "irreversible" the call will wait for the tx to appear in
671
- the head/irreversible block and add the key "orderid" to the tx output
590
+ """
591
+ Place a limit sell order on this market, selling the market's quote asset for its base asset.
672
592
 
673
- Prices/Rates are denoted in 'base', i.e. the SBD_STEEM market
674
- is priced in STEEM per SBD.
593
+ This creates a Limit_order_create operation where `amount_to_sell` is the provided `amount` in the market's quote asset and `min_to_receive` is `amount * price` in the market's base asset.
675
594
 
676
- **Example:** in the SBD_STEEM market, a price of 300 means
677
- a SBD is worth 300 STEEM
595
+ Parameters:
596
+ price (float or Price): Price expressed as base per quote (e.g., in HBD_HIVE market, a price of 3 means 1 HBD = 3 HIVE).
597
+ amount (number or str or Amount): Quantity of the quote asset to sell; may be an Amount instance, a string (e.g., "10.000 HBD"), or a numeric value.
598
+ expiration (int, optional): Order lifetime in seconds; defaults to the node/configured order-expiration (typically 7 days).
599
+ killfill (bool, optional): If True, treat the order as fill-or-kill (cancel if not fully filled). Defaults to False.
600
+ account (str, optional): Account name placing the order. If omitted, the configured default_account is used. Raises ValueError if no account is available.
601
+ orderid (int, optional): Client-provided order identifier; a random 32-bit id is used if not supplied.
602
+ returnOrderId (bool or str, optional): If truthy (or set to "head"/"irreversible"), the call will wait according to the blocking mode and the returned transaction will include an "orderid" field.
678
603
 
679
- .. note::
604
+ Returns:
605
+ dict: The finalized transaction object returned by the blockchain finalizeOp call. If `returnOrderId` is used, the dict will include an "orderid" key.
680
606
 
681
- All prices returned are in the **reversed** orientation as the
682
- market. I.e. in the STEEM/SBD market, prices are SBD per STEEM.
683
- That way you can multiply prices with `1.05` to get a +5%.
607
+ Raises:
608
+ ValueError: If no account is provided or available from configuration.
609
+ AssertionError: If an Amount is provided whose asset symbol does not match the market's quote asset.
684
610
  """
685
611
  if not expiration:
686
612
  expiration = self.blockchain.config["order-expiration"]
@@ -769,8 +695,20 @@ class Market(dict):
769
695
 
770
696
  @staticmethod
771
697
  def btc_usd_ticker(verbose=False):
772
- """Returns the BTC/USD price from bitfinex, gdax, kraken, okcoin and bitstamp. The mean price is
773
- weighted by the exchange volume.
698
+ """
699
+ Return the market-weighted BTC/USD price aggregated from multiple external sources.
700
+
701
+ Queries a set of public endpoints (currently CoinGecko; legacy support for Bitfinex, GDAX, Kraken, OKCoin, Bitstamp is present)
702
+ and computes a volume-weighted average price (VWAP) across successful responses.
703
+
704
+ Parameters:
705
+ verbose (bool): If True, prints the raw price/volume map collected from each source.
706
+
707
+ Returns:
708
+ float: The VWAP of BTC in USD computed from available sources.
709
+
710
+ Raises:
711
+ RuntimeError: If no valid price data could be obtained from any source after several attempts.
774
712
  """
775
713
  prices = {}
776
714
  responses = []
@@ -845,91 +783,17 @@ class Market(dict):
845
783
  )
846
784
 
847
785
  @staticmethod
848
- def steem_btc_ticker():
849
- """Returns the STEEM/BTC price from bittrex, binance, huobi and upbit. The mean price is
850
- weighted by the exchange volume.
786
+ def hive_btc_ticker():
851
787
  """
852
- prices = {}
853
- responses = []
854
- urls = [
855
- # "https://poloniex.com/public?command=returnTicker",
856
- # "https://bittrex.com/api/v1.1/public/getmarketsummary?market=BTC-STEEM",
857
- # "https://api.binance.com/api/v1/ticker/24hr",
858
- # "https://api.huobi.pro/market/history/kline?period=1day&size=1&symbol=steembtc",
859
- # "https://crix-api.upbit.com/v1/crix/trades/ticks?code=CRIX.UPBIT.BTC-STEEM&count=1",
860
- "https://api.coingecko.com/api/v3/simple/price?ids=steem&vs_currencies=btc&include_24hr_vol=true",
861
- ]
862
- headers = {
863
- "Content-type": "application/x-www-form-urlencoded",
864
- "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36",
865
- }
866
- cnt = 0
867
- while len(prices) == 0 and cnt < 5:
868
- cnt += 1
869
- try:
870
- responses = list(requests.get(u, headers=headers, timeout=30) for u in urls)
871
- except Exception as e:
872
- log.debug(str(e))
873
-
874
- for r in [
875
- x
876
- for x in responses
877
- if hasattr(x, "status_code") and x.status_code == 200 and x.json()
878
- ]:
879
- try:
880
- if "poloniex" in r.url:
881
- data = r.json()["BTC_STEEM"]
882
- prices["poloniex"] = {
883
- "price": float(data["last"]),
884
- "volume": float(data["baseVolume"]),
885
- }
886
- elif "bittrex" in r.url:
887
- data = r.json()["result"][0]
888
- price = (data["Bid"] + data["Ask"]) / 2
889
- prices["bittrex"] = {"price": price, "volume": data["BaseVolume"]}
890
- elif "binance" in r.url:
891
- data = [x for x in r.json() if x["symbol"] == "STEEMBTC"][0]
892
- prices["binance"] = {
893
- "price": float(data["lastPrice"]),
894
- "volume": float(data["quoteVolume"]),
895
- }
896
- elif "huobi" in r.url:
897
- data = r.json()["data"][-1]
898
- prices["huobi"] = {
899
- "price": float(data["close"]),
900
- "volume": float(data["vol"]),
901
- }
902
- elif "upbit" in r.url:
903
- data = r.json()[-1]
904
- prices["upbit"] = {
905
- "price": float(data["tradePrice"]),
906
- "volume": float(data["tradeVolume"]),
907
- }
908
- elif "coingecko" in r.url:
909
- data = r.json()["steem"]
910
- if "usd_24h_vol" in data:
911
- volume = float(data["usd_24h_vol"])
912
- else:
913
- volume = 1
914
- prices["coingecko"] = {"price": float(data["btc"]), "volume": volume}
915
- except KeyError as e:
916
- log.info(str(e))
788
+ Return the HIVE/BTC price as a volume-weighted average from multiple public exchanges.
917
789
 
918
- if len(prices) == 0:
919
- raise RuntimeError("Obtaining STEEM/BTC prices has failed from all sources.")
790
+ Queries several public APIs (CoinGecko and others) to collect recent HIVE/BTC prices and 24h volumes, then computes a volume-weighted average price (VWAP). The function retries up to 5 times if no valid responses are obtained.
920
791
 
921
- return Market._weighted_average(
922
- [x["price"] for x in prices.values()], [x["volume"] for x in prices.values()]
923
- )
792
+ Returns:
793
+ float: VWAP price expressed in BTC per 1 HIVE.
924
794
 
925
- def steem_usd_implied(self):
926
- """Returns the current STEEM/USD market price"""
927
- return self.steem_btc_ticker() * self.btc_usd_ticker()
928
-
929
- @staticmethod
930
- def hive_btc_ticker():
931
- """Returns the HIVE/BTC price from bittrex and upbit. The mean price is
932
- weighted by the exchange volume.
795
+ Raises:
796
+ RuntimeError: If no valid price data could be obtained from any source.
933
797
  """
934
798
  prices = {}
935
799
  responses = []
nectar/memo.py CHANGED
@@ -19,7 +19,7 @@ class Memo(object):
19
19
 
20
20
  :param Account from_account: Account that has sent the memo
21
21
  :param Account to_account: Account that has received the memo
22
- :param Steem blockchain_instance: Steem instance
22
+ :param Hive blockchain_instance: Hive instance
23
23
 
24
24
  A memo is encrypted with a shared secret derived from a private key of
25
25
  the sender and a public key of the receiver. Due to the underlying
@@ -51,7 +51,7 @@ class Memo(object):
51
51
 
52
52
  Memo Keys
53
53
 
54
- In Steem, memos are AES-256 encrypted with a shared secret between sender and
54
+ In Hive, memos are AES-256 encrypted with a shared secret between sender and
55
55
  receiver. It is derived from the memo private key of the sender and the memo
56
56
  public key of the receiver.
57
57
 
@@ -136,11 +136,23 @@ class Memo(object):
136
136
  """
137
137
 
138
138
  def __init__(self, from_account=None, to_account=None, blockchain_instance=None, **kwargs):
139
- if blockchain_instance is None:
140
- if kwargs.get("steem_instance"):
141
- blockchain_instance = kwargs["steem_instance"]
142
- elif kwargs.get("hive_instance"):
143
- blockchain_instance = kwargs["hive_instance"]
139
+ """
140
+ Initialize a Memo helper that resolves sender/recipient identifiers into Account/Key objects.
141
+
142
+ If `from_account`/`to_account` are provided as strings shorter than 51 characters they are treated as account names and resolved to Account(...) using the selected blockchain instance. Strings with length >= 51 are treated as raw keys and converted to PrivateKey (for `from_account`) or PublicKey (for `to_account`). If an input is omitted, the corresponding attribute is set to None.
143
+
144
+ Also sets self.blockchain to the provided blockchain_instance or, if None, the shared blockchain instance.
145
+
146
+ Parameters:
147
+ from_account (str|Account|PrivateKey|None): Sender identity — an account name (resolved to Account) or a private key string (resolved to PrivateKey). If already an Account/PrivateKey object, it will be assigned as-is by calling the appropriate constructor above.
148
+ to_account (str|Account|PublicKey|None): Recipient identity — an account name (resolved to Account) or a public key string (resolved to PublicKey).
149
+ blockchain_instance (optional): Blockchain client/instance to use for Account resolution; if omitted the shared blockchain instance is used.
150
+
151
+ Attributes set:
152
+ self.blockchain: blockchain instance used for key/account resolution.
153
+ self.from_account: Account or PrivateKey instance (or None).
154
+ self.to_account: Account or PublicKey instance (or None).
155
+ """
144
156
  self.blockchain = blockchain_instance or shared_blockchain_instance()
145
157
 
146
158
  if to_account and len(to_account) < 51:
@@ -272,20 +284,35 @@ class Memo(object):
272
284
  return from_key, to_key, nonce
273
285
 
274
286
  def decrypt(self, memo):
275
- """Decrypt a memo
287
+ """
288
+ Decrypt a memo message produced for a transfer.
276
289
 
277
- :param str memo: encrypted memo message
278
- :returns: encrypted memo
279
- :rtype: str
290
+ Accepts either a raw memo string or a transfer-style dict with keys "from", "to", and "memo" or "message". If provided, the memo dict may also contain a "nonce". The function will locate an appropriate private memo key from the local wallet (or use a provided PrivateKey), derive the shared secret with the counterparty public key, and return the decrypted plaintext.
291
+
292
+ Parameters:
293
+ memo (str or dict): Encrypted memo as a string, or a dict in transfer form:
294
+ {"from": <account|key>, "to": <account|key>, "memo"/"message": <str>, "nonce"?: <int|str>}.
295
+ - "from"/"to" entries may be account names, account dicts, PublicKey/PrivateKey objects, or omitted.
296
+
297
+ Returns:
298
+ str: Decrypted memo plaintext, or None if `memo` is falsy.
299
+
300
+ Raises:
301
+ MissingKeyError: If no installed private memo key can be found for decrypting the message.
280
302
  """
281
303
  if not memo:
282
304
  return None
283
305
  memo_wif = None
284
306
  # We first try to decode assuming we received the memo
285
- if isinstance(memo, dict) and "to" in memo and "from" in memo and "memo" in memo:
307
+ if (
308
+ isinstance(memo, dict)
309
+ and "to" in memo
310
+ and "from" in memo
311
+ and ("memo" in memo or "message" in memo)
312
+ ):
286
313
  memo_to = Account(memo["to"], blockchain_instance=self.blockchain)
287
314
  memo_from = Account(memo["from"], blockchain_instance=self.blockchain)
288
- message = memo["memo"]
315
+ message = memo.get("memo") or memo.get("message")
289
316
  else:
290
317
  memo_to = self.to_account
291
318
  memo_from = self.from_account