Skip to content

Commit

Permalink
update PythConnection to subscribe to single accounts and add new ws …
Browse files Browse the repository at this point in the history
…example with SOL/USDC feed (#64)
  • Loading branch information
jacksturt authored Feb 6, 2023
1 parent a84f41f commit 6f64b84
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 12 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pythnetwork/client",
"version": "2.13.1",
"version": "2.14.0",
"description": "Client for consuming Pyth price data",
"homepage": "https://pyth.network",
"main": "lib/index.js",
Expand All @@ -20,6 +20,7 @@
"version": "npm run format && git add -A src",
"postversion": "git push && git push --tags",
"ws_example": "npm run build && node lib/example_ws_usage.js",
"ws_single_example": "npm run build && node lib/example_ws_usage.js",
"http_example": "npm run build && node lib/example_http_usage.js"
},
"keywords": [
Expand Down
39 changes: 30 additions & 9 deletions src/PythConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export class PythConnection {
connection: Connection
pythProgramKey: PublicKey
commitment: Commitment
feedIds?: PublicKey[]

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

/** Start receiving price updates. Once this method is called, any registered callbacks will be invoked
* each time a Pyth price account is updated.
*/
public async start() {
const accounts = await this.connection.getProgramAccounts(this.pythProgramKey, this.commitment)
let accounts = await this.connection.getProgramAccounts(this.pythProgramKey, this.commitment)
const currentSlot = await this.connection.getSlot(this.commitment)
// Handle all accounts once since we need to handle product accounts
// at least once
for (const account of accounts) {
this.handleAccount(account.pubkey, account.account, true, currentSlot)
}

this.connection.onProgramAccountChange(
this.pythProgramKey,
(keyedAccountInfo, context) => {
this.handleAccount(keyedAccountInfo.accountId, keyedAccountInfo.accountInfo, false, context.slot)
},
this.commitment,
)
if(this.feedIds) {
// Filter down to only the feeds we want
const rawIDs = this.feedIds.map((feed) => feed.toString())
accounts = accounts.filter((feed) => rawIDs.includes(feed.pubkey.toString()))
for (const account of accounts){
this.connection.onAccountChange(
account.pubkey,

(accountInfo, context) => {
this.handleAccount(account.pubkey, accountInfo, false, context.slot)
},
this.commitment,
)
}

} else {
this.connection.onProgramAccountChange(
this.pythProgramKey,
(keyedAccountInfo, context) => {
this.handleAccount(keyedAccountInfo.accountId, keyedAccountInfo.accountInfo, false, context.slot)
},
this.commitment,
)
}
}

/** Register callback to receive price updates. */
Expand Down
30 changes: 30 additions & 0 deletions src/example_ws_single_feed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Connection, PublicKey } from '@solana/web3.js'
import { PythConnection } from './PythConnection'
import { getPythClusterApiUrl, getPythProgramKeyForCluster, PythCluster, PriceStatus } from '.'

const PYTHNET_CLUSTER_NAME: PythCluster = 'pythnet'
const connection = new Connection(getPythClusterApiUrl(PYTHNET_CLUSTER_NAME))
const pythPublicKey = getPythProgramKeyForCluster(PYTHNET_CLUSTER_NAME)
// This feed ID comes from this list: https://pyth.network/developers/price-feed-ids#solana-mainnet-beta
// This example shows Crypto.SOL/USD
const feeds = [new PublicKey('H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG')]

const pythConnection = new PythConnection(connection, pythPublicKey, "confirmed", feeds)
pythConnection.onPriceChangeVerbose((productAccount, priceAccount) => {
// The arguments to the callback include solana account information / the update slot if you need it.
const product = productAccount.accountInfo.data.product
const price = priceAccount.accountInfo.data
// sample output:
// SOL/USD: $14.627930000000001 ±$0.01551797
if (price.price && price.confidence) {
// tslint:disable-next-line:no-console
console.log(`${product.symbol}: $${price.price} \xB1$${price.confidence}`)
} else {
// tslint:disable-next-line:no-console
console.log(`${product.symbol}: price currently unavailable. status is ${PriceStatus[price.status]}`)
}
})

// tslint:disable-next-line:no-console
console.log('Reading from Pyth price feed...')
pythConnection.start()

0 comments on commit 6f64b84

Please sign in to comment.