extend providers

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>
This commit is contained in:
microwavedcola1 2024-08-08 15:27:46 +02:00
parent ea5158175d
commit 687c50c496
2 changed files with 65 additions and 13 deletions

View File

@ -155,6 +155,7 @@ export class Group {
this.reloadBanks(client, ids).then(() => this.reloadBanks(client, ids).then(() =>
Promise.all([ Promise.all([
this.reloadBankOraclePrices(client), this.reloadBankOraclePrices(client),
// TODO: load fallback oracles
this.reloadVaults(client), this.reloadVaults(client),
this.reloadPerpMarkets(client, ids).then(() => this.reloadPerpMarkets(client, ids).then(() =>
this.reloadPerpMarketOraclePrices(client), this.reloadPerpMarketOraclePrices(client),
@ -521,7 +522,7 @@ export class Group {
priceData.uiDeviation !== undefined priceData.uiDeviation !== undefined
? this.toNativePrice(priceData.uiDeviation, baseDecimals) ? this.toNativePrice(priceData.uiDeviation, baseDecimals)
: undefined; : undefined;
provider = OracleProvider.Pyth; provider = priceData.provider;
} else if (isSwitchboardOracle(ai)) { } else if (isSwitchboardOracle(ai)) {
const priceData = await parseSwitchboardOracle( const priceData = await parseSwitchboardOracle(
oracle, oracle,
@ -532,7 +533,7 @@ export class Group {
price = this.toNativePrice(uiPrice, baseDecimals); price = this.toNativePrice(uiPrice, baseDecimals);
lastUpdatedSlot = priceData.lastUpdatedSlot; lastUpdatedSlot = priceData.lastUpdatedSlot;
deviation = this.toNativePrice(priceData.uiDeviation, baseDecimals); deviation = this.toNativePrice(priceData.uiDeviation, baseDecimals);
provider = OracleProvider.Switchboard; provider = priceData.provider;
} else { } else {
throw new Error( throw new Error(
`Unknown oracle provider (parsing not implemented) for oracle ${oracle}, with owner ${ai.owner}!`, `Unknown oracle provider (parsing not implemented) for oracle ${oracle}, with owner ${ai.owner}!`,

View File

@ -47,8 +47,10 @@ export let sbOnDemandProgram;
let pythSolanaReceiverProgram; let pythSolanaReceiverProgram;
export enum OracleProvider { export enum OracleProvider {
Pyth, Pyth, // V1
Switchboard, PythV2, // V2
Switchboard, // V1+V2
SwitchboardOnDemand, // On Demand
Stub, Stub,
} }
@ -97,6 +99,7 @@ export function parseSwitchboardOracleV1(accountInfo: AccountInfo<Buffer>): {
price: number; price: number;
lastUpdatedSlot: number; lastUpdatedSlot: number;
uiDeviation: number; uiDeviation: number;
provider: OracleProvider;
} { } {
const price = accountInfo.data.readDoubleLE(1 + 32 + 4 + 4); const price = accountInfo.data.readDoubleLE(1 + 32 + 4 + 4);
const lastUpdatedSlot = parseInt( const lastUpdatedSlot = parseInt(
@ -106,7 +109,12 @@ export function parseSwitchboardOracleV1(accountInfo: AccountInfo<Buffer>): {
const maxResponse = accountInfo.data.readDoubleLE( const maxResponse = accountInfo.data.readDoubleLE(
1 + 32 + 4 + 4 + 8 + 8 + 8 + 8, 1 + 32 + 4 + 4 + 8 + 8 + 8 + 8,
); );
return { price, lastUpdatedSlot, uiDeviation: maxResponse - minResponse }; return {
price,
lastUpdatedSlot,
uiDeviation: maxResponse - minResponse,
provider: OracleProvider.Switchboard,
};
} }
export function switchboardDecimalToBig(sbDecimal: { export function switchboardDecimalToBig(sbDecimal: {
@ -126,7 +134,12 @@ export function parseSwitchboardOracleV2(
program: SwitchboardProgram, program: SwitchboardProgram,
accountInfo: AccountInfo<Buffer>, accountInfo: AccountInfo<Buffer>,
oracle: PublicKey, oracle: PublicKey,
): { price: number; lastUpdatedSlot: number; uiDeviation: number } { ): {
price: number;
lastUpdatedSlot: number;
uiDeviation: number;
provider: OracleProvider;
} {
try { try {
// //
const price = program.decodeLatestAggregatorValue(accountInfo)!.toNumber(); const price = program.decodeLatestAggregatorValue(accountInfo)!.toNumber();
@ -137,12 +150,22 @@ export function parseSwitchboardOracleV2(
program.decodeAggregator(accountInfo).latestConfirmedRound.stdDeviation, program.decodeAggregator(accountInfo).latestConfirmedRound.stdDeviation,
); );
return { price, lastUpdatedSlot, uiDeviation: stdDeviation.toNumber() }; return {
price,
lastUpdatedSlot,
uiDeviation: stdDeviation.toNumber(),
provider: OracleProvider.Switchboard,
};
// if oracle is badly configured or didn't publish price at least once // if oracle is badly configured or didn't publish price at least once
// decodeLatestAggregatorValue can throw (0 switchboard rounds). // decodeLatestAggregatorValue can throw (0 switchboard rounds).
} catch (e) { } catch (e) {
console.log(`Unable to parse Switchboard Oracle V2: ${oracle}`, e); console.log(`Unable to parse Switchboard Oracle V2: ${oracle}`, e);
return { price: 0, lastUpdatedSlot: 0, uiDeviation: 0 }; return {
price: 0,
lastUpdatedSlot: 0,
uiDeviation: 0,
provider: OracleProvider.Switchboard,
};
} }
} }
@ -158,7 +181,12 @@ export function parseSwitchboardOnDemandOracle(
program: any, program: any,
accountInfo: AccountInfo<Buffer>, accountInfo: AccountInfo<Buffer>,
oracle: PublicKey, oracle: PublicKey,
): { price: number; lastUpdatedSlot: number; uiDeviation: number } { ): {
price: number;
lastUpdatedSlot: number;
uiDeviation: number;
provider: OracleProvider;
} {
try { try {
const decodedPullFeed = program.coder.accounts.decode( const decodedPullFeed = program.coder.accounts.decode(
'pullFeedAccountData', 'pullFeedAccountData',
@ -182,7 +210,12 @@ export function parseSwitchboardOnDemandOracle(
let values = submissions.slice(0, decodedPullFeed.minSampleSize); let values = submissions.slice(0, decodedPullFeed.minSampleSize);
if (values.length === 0) { if (values.length === 0) {
return { price: 0, lastUpdatedSlot: 0, uiDeviation: 0 }; return {
price: 0,
lastUpdatedSlot: 0,
uiDeviation: 0,
provider: OracleProvider.SwitchboardOnDemand,
};
} }
values = values.sort((x, y) => (x.value.lt(y.value) ? -1 : 1)); values = values.sort((x, y) => (x.value.lt(y.value) ? -1 : 1));
const feedValue = values[Math.floor(values.length / 2)]; const feedValue = values[Math.floor(values.length / 2)];
@ -193,7 +226,12 @@ export function parseSwitchboardOnDemandOracle(
new Big(val.value.toString()).div(1e18).toNumber(), new Big(val.value.toString()).div(1e18).toNumber(),
), ),
); );
return { price, lastUpdatedSlot, uiDeviation: stdDeviation }; return {
price,
lastUpdatedSlot,
uiDeviation: stdDeviation,
provider: OracleProvider.SwitchboardOnDemand,
};
// old block, we prefer above block since we want raw data, .result is often empty // old block, we prefer above block since we want raw data, .result is often empty
// const price = new Big(decodedPullFeed.result.value.toString()).div(1e18); // const price = new Big(decodedPullFeed.result.value.toString()).div(1e18);
@ -205,7 +243,12 @@ export function parseSwitchboardOnDemandOracle(
`Unable to parse Switchboard On-Demand Oracle V2: ${oracle}`, `Unable to parse Switchboard On-Demand Oracle V2: ${oracle}`,
e, e,
); );
return { price: 0, lastUpdatedSlot: 0, uiDeviation: 0 }; return {
price: 0,
lastUpdatedSlot: 0,
uiDeviation: 0,
provider: OracleProvider.SwitchboardOnDemand,
};
} }
} }
@ -213,7 +256,12 @@ export async function parseSwitchboardOracle(
oracle: PublicKey, oracle: PublicKey,
accountInfo: AccountInfo<Buffer>, accountInfo: AccountInfo<Buffer>,
connection: Connection, connection: Connection,
): Promise<{ price: number; lastUpdatedSlot: number; uiDeviation: number }> { ): Promise<{
price: number;
lastUpdatedSlot: number;
uiDeviation: number;
provider: OracleProvider;
}> {
if (accountInfo.owner.equals(SB_ON_DEMAND_PID)) { if (accountInfo.owner.equals(SB_ON_DEMAND_PID)) {
if (!sbOnDemandProgram) { if (!sbOnDemandProgram) {
const options = AnchorProvider.defaultOptions(); const options = AnchorProvider.defaultOptions();
@ -309,6 +357,7 @@ export function parsePythOracle(
price: number; price: number;
lastUpdatedSlot: number; lastUpdatedSlot: number;
uiDeviation: number; uiDeviation: number;
provider: OracleProvider;
} { } {
if (accountInfo.owner.equals(DEFAULT_RECEIVER_PROGRAM_ID)) { if (accountInfo.owner.equals(DEFAULT_RECEIVER_PROGRAM_ID)) {
if (!pythSolanaReceiverProgram) { if (!pythSolanaReceiverProgram) {
@ -337,6 +386,7 @@ export function parsePythOracle(
decoded.priceMessage.conf.toNumber(), decoded.priceMessage.conf.toNumber(),
-decoded.priceMessage.exponent, -decoded.priceMessage.exponent,
), ),
provider: OracleProvider.PythV2,
} as any; } as any;
} }
@ -346,6 +396,7 @@ export function parsePythOracle(
price: priceData.previousPrice, price: priceData.previousPrice,
lastUpdatedSlot: parseInt(priceData.lastSlot.toString()), lastUpdatedSlot: parseInt(priceData.lastSlot.toString()),
uiDeviation: priceData.previousConfidence, uiDeviation: priceData.previousConfidence,
provider: OracleProvider.Pyth,
}; };
} }