Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 70 additions & 26 deletions src/PythConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ export class PythConnection {
connection: Connection
pythProgramKey: PublicKey
commitment: Commitment
feedIds?: PublicKey[]
feedIds: PublicKey[]
productIds: PublicKey[]

productAccountKeyToProduct: Record<string, AccountUpdate<ProductData>> = {}
priceAccountKeyToProductAccountKey: Record<string, string> = {}
Expand Down Expand Up @@ -109,53 +110,96 @@ export class PythConnection {
connection: Connection,
pythProgramKey: PublicKey,
commitment: Commitment = 'finalized',
feedIds?: PublicKey[],
feedIds: PublicKey[],
productIds: PublicKey[],
) {
this.connection = connection
this.pythProgramKey = pythProgramKey
this.commitment = commitment
this.feedIds = feedIds
this.productIds = productIds
}

// public async start() {
// const accSlotProm = await Promise.all([
// this.connection.getProgramAccounts(this.pythProgramKey, this.commitment),
// this.connection.getSlot(this.commitment),
// ])
// let accounts = accSlotProm[0]
// const currentSlot = accSlotProm[1]
// // 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)
// }

// 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()))

// console.log('ACCOUNTS', accounts);


// 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,
// )
// }
// }

/** 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 accSlotProm = await Promise.all([
this.connection.getProgramAccounts(this.pythProgramKey, this.commitment),
this.connection.getMultipleAccountsInfo([...this.feedIds, ...this.productIds], this.commitment),
this.connection.getSlot(this.commitment),
])

let accounts = accSlotProm[0]
const currentSlot = accSlotProm[1]

// Register products accounts
this.productIds.forEach((productId, i) => {
const acc = accounts[i + this.feedIds.length];

if (acc === null) return;

this.handleAccount(productId, acc, true, currentSlot)
});

// 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.feedIds.forEach((accountId, i) => {
const acc = accounts[i];

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)
if (acc === null) return;

this.handleAccount(accountId, acc, true, currentSlot)

this.connection.onAccountChange(
accountId,
(accountInfo, context) => {
this.handleAccount(accountId, accountInfo, false, context.slot)
},
this.commitment,
)
}
});
}

/** Register callback to receive price updates. */
Expand Down
2 changes: 1 addition & 1 deletion src/example_ws_single_feed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const pythPublicKey = getPythProgramKeyForCluster(PYTHNET_CLUSTER_NAME)
// This example shows Crypto.SOL/USD
const feeds = [new PublicKey('H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG')]

const pythConnection = new PythConnection(connection, pythPublicKey, 'confirmed', feeds)
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
Expand Down
2 changes: 1 addition & 1 deletion src/example_ws_usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const PYTHNET_CLUSTER_NAME: PythCluster = 'pythnet'
const connection = new Connection(getPythClusterApiUrl(PYTHNET_CLUSTER_NAME))
const pythPublicKey = getPythProgramKeyForCluster(PYTHNET_CLUSTER_NAME)

const pythConnection = new PythConnection(connection, pythPublicKey)
const pythConnection = new PythConnection(connection, pythPublicKey, "finalized", [], [])
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
Expand Down