Skip to content

Commit 6f64b84

Browse files
authored
update PythConnection to subscribe to single accounts and add new ws example with SOL/USDC feed (#64)
1 parent a84f41f commit 6f64b84

4 files changed

+64
-12
lines changed

package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pythnetwork/client",
3-
"version": "2.13.1",
3+
"version": "2.14.0",
44
"description": "Client for consuming Pyth price data",
55
"homepage": "https://pyth.network",
66
"main": "lib/index.js",
@@ -20,6 +20,7 @@
2020
"version": "npm run format && git add -A src",
2121
"postversion": "git push && git push --tags",
2222
"ws_example": "npm run build && node lib/example_ws_usage.js",
23+
"ws_single_example": "npm run build && node lib/example_ws_usage.js",
2324
"http_example": "npm run build && node lib/example_http_usage.js"
2425
},
2526
"keywords": [

src/PythConnection.ts

+30-9
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export class PythConnection {
3030
connection: Connection
3131
pythProgramKey: PublicKey
3232
commitment: Commitment
33+
feedIds?: PublicKey[]
3334

3435
productAccountKeyToProduct: Record<string, AccountUpdate<ProductData>> = {}
3536
priceAccountKeyToProductAccountKey: Record<string, string> = {}
@@ -104,29 +105,49 @@ export class PythConnection {
104105
/** Create a PythConnection that reads its data from an underlying solana web3 connection.
105106
* pythProgramKey is the public key of the Pyth program running on the chosen solana cluster.
106107
*/
107-
constructor(connection: Connection, pythProgramKey: PublicKey, commitment: Commitment = 'finalized') {
108+
constructor(connection: Connection, pythProgramKey: PublicKey, commitment: Commitment = 'finalized', feedIds?: PublicKey[]) {
108109
this.connection = connection
109110
this.pythProgramKey = pythProgramKey
110111
this.commitment = commitment
112+
this.feedIds = feedIds
111113
}
112114

113115
/** Start receiving price updates. Once this method is called, any registered callbacks will be invoked
114116
* each time a Pyth price account is updated.
115117
*/
116118
public async start() {
117-
const accounts = await this.connection.getProgramAccounts(this.pythProgramKey, this.commitment)
119+
let accounts = await this.connection.getProgramAccounts(this.pythProgramKey, this.commitment)
118120
const currentSlot = await this.connection.getSlot(this.commitment)
121+
// Handle all accounts once since we need to handle product accounts
122+
// at least once
119123
for (const account of accounts) {
120124
this.handleAccount(account.pubkey, account.account, true, currentSlot)
121125
}
122126

123-
this.connection.onProgramAccountChange(
124-
this.pythProgramKey,
125-
(keyedAccountInfo, context) => {
126-
this.handleAccount(keyedAccountInfo.accountId, keyedAccountInfo.accountInfo, false, context.slot)
127-
},
128-
this.commitment,
129-
)
127+
if(this.feedIds) {
128+
// Filter down to only the feeds we want
129+
const rawIDs = this.feedIds.map((feed) => feed.toString())
130+
accounts = accounts.filter((feed) => rawIDs.includes(feed.pubkey.toString()))
131+
for (const account of accounts){
132+
this.connection.onAccountChange(
133+
account.pubkey,
134+
135+
(accountInfo, context) => {
136+
this.handleAccount(account.pubkey, accountInfo, false, context.slot)
137+
},
138+
this.commitment,
139+
)
140+
}
141+
142+
} else {
143+
this.connection.onProgramAccountChange(
144+
this.pythProgramKey,
145+
(keyedAccountInfo, context) => {
146+
this.handleAccount(keyedAccountInfo.accountId, keyedAccountInfo.accountInfo, false, context.slot)
147+
},
148+
this.commitment,
149+
)
150+
}
130151
}
131152

132153
/** Register callback to receive price updates. */

src/example_ws_single_feed.ts

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Connection, PublicKey } from '@solana/web3.js'
2+
import { PythConnection } from './PythConnection'
3+
import { getPythClusterApiUrl, getPythProgramKeyForCluster, PythCluster, PriceStatus } from '.'
4+
5+
const PYTHNET_CLUSTER_NAME: PythCluster = 'pythnet'
6+
const connection = new Connection(getPythClusterApiUrl(PYTHNET_CLUSTER_NAME))
7+
const pythPublicKey = getPythProgramKeyForCluster(PYTHNET_CLUSTER_NAME)
8+
// This feed ID comes from this list: https://pyth.network/developers/price-feed-ids#solana-mainnet-beta
9+
// This example shows Crypto.SOL/USD
10+
const feeds = [new PublicKey('H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG')]
11+
12+
const pythConnection = new PythConnection(connection, pythPublicKey, "confirmed", feeds)
13+
pythConnection.onPriceChangeVerbose((productAccount, priceAccount) => {
14+
// The arguments to the callback include solana account information / the update slot if you need it.
15+
const product = productAccount.accountInfo.data.product
16+
const price = priceAccount.accountInfo.data
17+
// sample output:
18+
// SOL/USD: $14.627930000000001 ±$0.01551797
19+
if (price.price && price.confidence) {
20+
// tslint:disable-next-line:no-console
21+
console.log(`${product.symbol}: $${price.price} \xB1$${price.confidence}`)
22+
} else {
23+
// tslint:disable-next-line:no-console
24+
console.log(`${product.symbol}: price currently unavailable. status is ${PriceStatus[price.status]}`)
25+
}
26+
})
27+
28+
// tslint:disable-next-line:no-console
29+
console.log('Reading from Pyth price feed...')
30+
pythConnection.start()

0 commit comments

Comments
 (0)