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