1
1
from __future__ import annotations
2
- from typing import List , Dict , Tuple , Optional , Any
2
+ from typing import List , Dict , Tuple , Optional , Any , ClassVar
3
3
import base64
4
4
from enum import Enum
5
+ from dataclasses import dataclass , field
5
6
import struct
6
7
7
8
from loguru import logger
@@ -205,7 +206,6 @@ class PythProductAccount(PythAccount):
205
206
first_price_account_key (SolanaPublicKey): the public key of the first price account (the price accounts form a linked list)
206
207
attrs (dict): a dictionary of metadata attributes
207
208
"""
208
-
209
209
def __init__ (self , key : SolanaPublicKey , solana : SolanaClient ) -> None :
210
210
super ().__init__ (key , solana )
211
211
self ._prices : Optional [Dict [PythPriceType , PythPriceAccount ]] = None
@@ -229,7 +229,6 @@ def symbol(self) -> str:
229
229
"""
230
230
Gets this account's symbol, or 'Unknown' if there is no 'symbol' attribute.
231
231
"""
232
-
233
232
return self .attrs .get ("symbol" , "Unknown" )
234
233
235
234
async def get_prices (self ) -> Dict [PythPriceType , PythPriceAccount ]:
@@ -258,7 +257,10 @@ async def refresh_prices(self) -> Dict[PythPriceType, PythPriceAccount]:
258
257
self ._prices = prices
259
258
return prices
260
259
261
- async def check_price_changes (self , update_accounts : bool = True ) -> Tuple [List [PythPriceAccount ], List [PythPriceAccount ]]:
260
+ async def check_price_changes (
261
+ self ,
262
+ update_accounts : bool = True
263
+ ) -> Tuple [List [PythPriceAccount ], List [PythPriceAccount ]]:
262
264
"""
263
265
Checks for changes to the list of price accounts of this product.
264
266
@@ -351,6 +353,7 @@ def __iter__(self):
351
353
yield key , val
352
354
353
355
356
+ @dataclass
354
357
class PythPriceInfo :
355
358
"""
356
359
Contains price information.
@@ -365,15 +368,18 @@ class PythPriceInfo:
365
368
exponent (int): the power-of-10 order of the price
366
369
"""
367
370
368
- LENGTH = 32
371
+ LENGTH : ClassVar [ int ] = 32
369
372
370
- def __init__ (self , raw_price : int , raw_confidence_interval : int , price_status : PythPriceStatus , slot : int , exponent : int ) -> None :
371
- self .raw_price = raw_price
372
- self .raw_confidence_interval = raw_confidence_interval
373
- self .price_status = price_status
374
- self .slot = slot
375
- self .exponent = exponent
373
+ raw_price : int
374
+ raw_confidence_interval : int
375
+ price_status : PythPriceStatus
376
+ slot : int
377
+ exponent : int
376
378
379
+ price : float = field (init = False )
380
+ confidence_interval : float = field (init = False )
381
+
382
+ def __post_init__ (self ):
377
383
self .price = self .raw_price * (10 ** self .exponent )
378
384
self .confidence_interval = self .raw_confidence_interval * \
379
385
(10 ** self .exponent )
@@ -401,11 +407,8 @@ def __str__(self) -> str:
401
407
def __repr__ (self ) -> str :
402
408
return str (self )
403
409
404
- def __iter__ (self ):
405
- for key , val in self .__dict__ .items ():
406
- yield key , val
407
-
408
410
411
+ @dataclass
409
412
class PythPriceComponent :
410
413
"""
411
414
Represents a price component. This is the individual prices each
@@ -421,13 +424,12 @@ class PythPriceComponent:
421
424
in this price component
422
425
"""
423
426
424
- LENGTH = SolanaPublicKey .LENGTH + 2 * PythPriceInfo .LENGTH
427
+ LENGTH : ClassVar [ int ] = SolanaPublicKey .LENGTH + 2 * PythPriceInfo .LENGTH
425
428
426
- def __init__ (self , publisher_key : SolanaPublicKey , last_aggregate_price_info : PythPriceInfo , latest_price_info : PythPriceInfo , exponent : int ) -> None :
427
- self .publisher_key = publisher_key
428
- self .last_aggregate_price_info = last_aggregate_price_info
429
- self .latest_price_info = latest_price_info
430
- self .exponent = exponent
429
+ publisher_key : SolanaPublicKey
430
+ last_aggregate_price_info : PythPriceInfo
431
+ latest_price_info : PythPriceInfo
432
+ exponent : int
431
433
432
434
@staticmethod
433
435
def deserialise (buffer : bytes , offset : int = 0 , * , exponent : int ) -> Optional [PythPriceComponent ]:
@@ -449,12 +451,6 @@ def deserialise(buffer: bytes, offset: int = 0, *, exponent: int) -> Optional[Py
449
451
latest_price = PythPriceInfo .deserialise (buffer , offset , exponent = exponent )
450
452
return PythPriceComponent (key , last_aggregate_price , latest_price , exponent )
451
453
452
- def __iter__ (self ):
453
- for key , val in self .__dict__ .items ():
454
- if isinstance (val , PythPriceInfo ):
455
- val = dict (val )
456
- yield key , val
457
-
458
454
459
455
class PythPriceAccount (PythAccount ):
460
456
"""
@@ -528,22 +524,22 @@ def update_from(self, buffer: bytes, *, version: int, offset: int = 0) -> None:
528
524
"""
529
525
if version == _VERSION_2 :
530
526
price_type , exponent , num_components = struct .unpack_from ("<IiI" , buffer , offset )
531
- offset += 16 # struct.calcsize("IiII") (last I is the number of quoters that make up the aggregate)
527
+ offset += 16 # struct.calcsize("IiII") (last I is the number of quoters that make up the aggregate)
532
528
last_slot , valid_slot = struct .unpack_from ("<QQ" , buffer , offset )
533
- offset += 16 # QQ
529
+ offset += 16 # QQ
534
530
derivations = list (struct .unpack_from ("<6q" , buffer , offset ))
535
531
self .derivations = dict ((type_ , derivations [type_ .value - 1 ]) for type_ in [TwEmaType .TWACVALUE , TwEmaType .TWAPVALUE ])
536
- offset += 48 # 6q
532
+ offset += 48 # 6q
537
533
# All drv*_ fields sans min_publishers are currently unused
538
534
_ , min_publishers = struct .unpack_from ("<qQ" , buffer , offset )
539
- offset += 16 # <qQ
535
+ offset += 16 # <qQ
540
536
product_account_key_bytes , next_price_account_key_bytes = struct .unpack_from ("32s32s" , buffer , offset )
541
- offset += 96 # 32s32s32s
537
+ offset += 96 # 32s32s32s
542
538
elif version == _VERSION_1 :
543
539
price_type , exponent , num_components , _ , last_slot , valid_slot , product_account_key_bytes , next_price_account_key_bytes , aggregator_key_bytes = struct .unpack_from (
544
540
"<IiIIQQ32s32s32s" , buffer , offset )
545
541
self .derivations = {}
546
- offset += 128 # struct.calcsize("<IiIIQQ32s32s32s")
542
+ offset += 128 # struct.calcsize("<IiIIQQ32s32s32s")
547
543
else :
548
544
assert False
549
545
0 commit comments