1
+ import { Commitment , Connection , PublicKey } from "@solana/web3.js" ;
2
+ import { Product , PriceData , parseProductData , parsePriceData , parseBaseData , AccountType } from "." ;
3
+
4
+ export interface PythHttpClientResult {
5
+ assetTypes : string [ ] ;
6
+ symbols : string [ ] ;
7
+ products : Product [ ] ;
8
+ productFromSymbol : Map < string , Product > ;
9
+ productPrice : Map < string , PriceData > ;
10
+ prices : PriceData [ ] ;
11
+ }
12
+
13
+ /**
14
+ * Reads Pyth price data from a solana web3 connection. This class uses a single HTTP call.
15
+ * Use the method getData() to get updated prices values.
16
+ */
17
+ export class PythHttpClient {
18
+ connection : Connection ;
19
+ pythProgramKey : PublicKey ;
20
+ commitment : Commitment ;
21
+
22
+ constructor ( connection : Connection , pythProgramKey : PublicKey , commitment : Commitment = 'finalized' ) {
23
+ this . connection = connection ;
24
+ this . pythProgramKey = pythProgramKey ;
25
+ this . commitment = commitment ;
26
+ }
27
+
28
+ /*
29
+ * Get Pyth Network account information and return actual price state.
30
+ * The result contains lists of asset types, product symbols and their prices.
31
+ */
32
+ public async getData ( ) : Promise < PythHttpClientResult > {
33
+ const assetTypes = new Set < string > ( ) ;
34
+ const productSymbols = new Set < string > ( ) ;
35
+ const products = new Set < Product > ( )
36
+ const productFromSymbol = new Map < string , Product > ( )
37
+ const productPrice = new Map < string , PriceData > ( )
38
+ const prices = new Array < PriceData > ( ) ;
39
+
40
+ // Retrieve data from blockchain
41
+ const accountList = await this . connection . getProgramAccounts ( this . pythProgramKey , this . commitment ) ;
42
+
43
+ // Popolate producs and prices
44
+ const priceDataQueue = new Array < PriceData > ( ) ;
45
+ const productAccountKeyToProduct = new Map < string , Product > ( ) ;
46
+
47
+ accountList . forEach ( singleAccount => {
48
+ const base = parseBaseData ( singleAccount . account . data ) ;
49
+ if ( base ) {
50
+ switch ( AccountType [ base . type ] ) {
51
+ case 'Mapping' :
52
+ // We can skip these because we're going to get every account owned by this program anyway.
53
+ break ;
54
+ case 'Product' :
55
+ const productData = parseProductData ( singleAccount . account . data )
56
+
57
+ productAccountKeyToProduct . set ( singleAccount . pubkey . toBase58 ( ) , productData . product )
58
+ assetTypes . add ( productData . product . asset_type ) ;
59
+ productSymbols . add ( productData . product . symbol ) ;
60
+ products . add ( productData . product ) ;
61
+ productFromSymbol . set ( productData . product . symbol , productData . product ) ;
62
+ break ;
63
+ case 'Price' :
64
+ const priceData = parsePriceData ( singleAccount . account . data )
65
+ priceDataQueue . push ( priceData )
66
+ break ;
67
+ case 'Test' :
68
+ break ;
69
+ default :
70
+ throw new Error ( `Unknown account type: ${ base . type } . Try upgrading pyth-client.` )
71
+ }
72
+ }
73
+ } ) ;
74
+
75
+ priceDataQueue . forEach ( priceData => {
76
+ const product = productAccountKeyToProduct . get ( priceData . productAccountKey . toBase58 ( ) )
77
+
78
+ if ( product ) {
79
+ productPrice . set ( product . symbol , priceData ) ;
80
+ prices . push ( priceData ) ;
81
+ }
82
+ } ) ;
83
+
84
+ const result : PythHttpClientResult = {
85
+ assetTypes : Array . from ( assetTypes ) ,
86
+ symbols : Array . from ( productSymbols ) ,
87
+ products : Array . from ( products ) ,
88
+ productFromSymbol,
89
+ productPrice,
90
+ prices
91
+ } ;
92
+
93
+ return result ;
94
+ }
95
+ }
0 commit comments