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

View File

@ -47,8 +47,10 @@ export let sbOnDemandProgram;
let pythSolanaReceiverProgram;
export enum OracleProvider {
Pyth,
Switchboard,
Pyth, // V1
PythV2, // V2
Switchboard, // V1+V2
SwitchboardOnDemand, // On Demand
Stub,
}
@ -97,6 +99,7 @@ export function parseSwitchboardOracleV1(accountInfo: AccountInfo<Buffer>): {
price: number;
lastUpdatedSlot: number;
uiDeviation: number;
provider: OracleProvider;
} {
const price = accountInfo.data.readDoubleLE(1 + 32 + 4 + 4);
const lastUpdatedSlot = parseInt(
@ -106,7 +109,12 @@ export function parseSwitchboardOracleV1(accountInfo: AccountInfo<Buffer>): {
const maxResponse = accountInfo.data.readDoubleLE(
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: {
@ -126,7 +134,12 @@ export function parseSwitchboardOracleV2(
program: SwitchboardProgram,
accountInfo: AccountInfo<Buffer>,
oracle: PublicKey,
): { price: number; lastUpdatedSlot: number; uiDeviation: number } {
): {
price: number;
lastUpdatedSlot: number;
uiDeviation: number;
provider: OracleProvider;
} {
try {
//
const price = program.decodeLatestAggregatorValue(accountInfo)!.toNumber();
@ -137,12 +150,22 @@ export function parseSwitchboardOracleV2(
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
// decodeLatestAggregatorValue can throw (0 switchboard rounds).
} catch (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,
accountInfo: AccountInfo<Buffer>,
oracle: PublicKey,
): { price: number; lastUpdatedSlot: number; uiDeviation: number } {
): {
price: number;
lastUpdatedSlot: number;
uiDeviation: number;
provider: OracleProvider;
} {
try {
const decodedPullFeed = program.coder.accounts.decode(
'pullFeedAccountData',
@ -182,7 +210,12 @@ export function parseSwitchboardOnDemandOracle(
let values = submissions.slice(0, decodedPullFeed.minSampleSize);
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));
const feedValue = values[Math.floor(values.length / 2)];
@ -193,7 +226,12 @@ export function parseSwitchboardOnDemandOracle(
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
// 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}`,
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,
accountInfo: AccountInfo<Buffer>,
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 (!sbOnDemandProgram) {
const options = AnchorProvider.defaultOptions();
@ -309,6 +357,7 @@ export function parsePythOracle(
price: number;
lastUpdatedSlot: number;
uiDeviation: number;
provider: OracleProvider;
} {
if (accountInfo.owner.equals(DEFAULT_RECEIVER_PROGRAM_ID)) {
if (!pythSolanaReceiverProgram) {
@ -337,6 +386,7 @@ export function parsePythOracle(
decoded.priceMessage.conf.toNumber(),
-decoded.priceMessage.exponent,
),
provider: OracleProvider.PythV2,
} as any;
}
@ -346,6 +396,7 @@ export function parsePythOracle(
price: priceData.previousPrice,
lastUpdatedSlot: parseInt(priceData.lastSlot.toString()),
uiDeviation: priceData.previousConfidence,
provider: OracleProvider.Pyth,
};
}