Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>
This commit is contained in:
microwavedcola1 2024-07-03 10:34:49 +02:00
parent 6540ef31c3
commit eeeb336bbc
2 changed files with 41 additions and 77 deletions

View File

@ -40,6 +40,16 @@ const SLEEP_MS = Number(process.env.SLEEP_MS) || 5_000;
// TODO use mangolana to send txs
interface OracleInterface {
oracle: {
oraclePk: PublicKey;
oracleConfig: OracleConfig;
name: string;
};
decodedPullFeed: any;
ai: AccountInfo<Buffer> | null;
}
(async function main(): Promise<never> {
const { group, client, connection, user } = await setupMango();
@ -134,15 +144,9 @@ async function preparePullIx(
new PublicKey(oracle.oracle.oraclePk),
);
const decodedPullFeed = sbOnDemandProgram.coder.accounts.decode(
'pullFeedAccountData',
oracle.ai.data,
);
const conf = {
queue: queue,
numSignatures: 3,
feedHash: decodedPullFeed.feedHash,
feed: oracle.oraclePk,
};
// TODO use fetchUpdateMany
const [pullIx, responses, success] = await pullFeed.fetchUpdateIx(conf);
@ -167,30 +171,11 @@ async function preparePullIx(
}
async function filterForVarianceThresholdOracles(
filteredOracles: {
oracle: { oraclePk: PublicKey; oracleConfig: OracleConfig; name: string };
decodedPullFeed: any;
ai: AccountInfo<Buffer> | null;
}[],
filteredOracles: OracleInterface[],
client: MangoClient,
crossbarClient: CrossbarClient,
): Promise<
{
oracle: {
oraclePk: PublicKey;
oracleConfig: OracleConfig;
};
ai: AccountInfo<Buffer> | null;
}[]
> {
const varianceThresholdCrossedOracles = new Array<{
oracle: {
oraclePk: PublicKey;
oracleConfig: OracleConfig;
};
decodedPullFeed: any;
ai: AccountInfo<Buffer> | null;
}>();
): Promise<OracleInterface[]> {
const varianceThresholdCrossedOracles = new Array<OracleInterface>();
for (const item of filteredOracles) {
const res = await parseSwitchboardOracle(
item.oracle.oraclePk,
@ -206,24 +191,16 @@ async function filterForVarianceThresholdOracles(
crossBarSim[0].results.reduce((a, b) => a + b, 0) /
crossBarSim[0].results.length;
if (Math.abs(res.price - simPrice) / res.price > 0.01) {
const changePct = (Math.abs(res.price - simPrice) * 100) / res.price;
const changeBps = changePct * 100;
if (changePct > item.decodedPullFeed.maxVariance) {
console.log(
`- Variance threshold crossed oracle, candidate ${
item.oracle.name
} ${simPrice} ${res.price} ${(
(Math.abs(res.price - simPrice) * 10000) /
res.price
).toFixed()} bps`,
`- ${item.oracle.name}, variance threshold, candidate ${simPrice} ${res.price} ${changeBps} bps`,
);
varianceThresholdCrossedOracles.push(item);
} else {
console.log(
`- Variance threshold crossed oracle, non candidate ${
item.oracle.name
} ${simPrice} ${res.price} ${(
(Math.abs(res.price - simPrice) * 10000) /
res.price
).toFixed()} bps`,
`- ${item.oracle.name}, variance threshold, non-candidate ${simPrice} ${res.price} ${changeBps} bps`,
);
}
}
@ -231,11 +208,7 @@ async function filterForVarianceThresholdOracles(
}
async function filterForStaleOracles(
filteredOracles: {
oracle: { oraclePk: PublicKey; oracleConfig: OracleConfig; name: string };
decodedPullFeed: any;
ai: AccountInfo<Buffer> | null;
}[],
filteredOracles: OracleInterface[],
client: MangoClient,
slot: number,
): Promise<
@ -247,13 +220,7 @@ async function filterForStaleOracles(
ai: AccountInfo<Buffer> | null;
}[]
> {
const staleOracles = new Array<{
oracle: {
oraclePk: PublicKey;
oracleConfig: OracleConfig;
};
ai: AccountInfo<Buffer> | null;
}>();
const staleOracles = new Array<OracleInterface>();
for (const item of filteredOracles) {
const res = await parseSwitchboardOracle(
item.oracle.oraclePk,
@ -261,21 +228,18 @@ async function filterForStaleOracles(
client.connection,
);
const diff = slot - res.lastUpdatedSlot;
if (
slot > res.lastUpdatedSlot &&
slot - res.lastUpdatedSlot > item.decodedPullFeed.maxStaleness
) {
console.log(
`- Stale oracle, candidate ${item.oracle.name} ${slot} ${
item.decodedPullFeed.maxStaleness
} ${res.lastUpdatedSlot} ${slot - res.lastUpdatedSlot}`,
`- ${item.oracle.name}, stale oracle, candidate ${item.decodedPullFeed.maxStaleness} ${slot} ${res.lastUpdatedSlot} ${diff}`,
);
staleOracles.push(item);
} else {
console.log(
`- Stale oracle, non candidate ${item.oracle.name} ${slot} ${
res.lastUpdatedSlot
} ${res.lastUpdatedSlot} ${slot - res.lastUpdatedSlot}`,
`- ${item.oracle.name}, stale oracle, non-candidate ${item.decodedPullFeed.maxStaleness} ${slot} ${res.lastUpdatedSlot} ${diff}`,
);
}
}
@ -285,13 +249,7 @@ async function filterForStaleOracles(
async function prepareCandidateOracles(
group: Group,
client: MangoClient,
): Promise<
{
oracle: { oraclePk: PublicKey; oracleConfig: OracleConfig; name: string };
decodedPullFeed: any;
ai: AccountInfo<Buffer> | null;
}[]
> {
): Promise<OracleInterface[]> {
const oracles = getOraclesForMangoGroup(group);
oracles.push(...extendOraclesManually(CLUSTER));
@ -325,14 +283,18 @@ async function prepareCandidateOracles(
const filteredOracles = oracles
.map((o, i) => {
return { oracle: o, ai: ais[i] };
return { oracle: o, ai: ais[i], decodedPullFeed: undefined };
})
.filter((item) => item.ai?.owner.equals(SB_ON_DEMAND_PID));
return filteredOracles;
}
function extendOraclesManually(cluster: Cluster) {
function extendOraclesManually(cluster: Cluster): {
oraclePk: PublicKey;
oracleConfig: { confFilter: I80F48; maxStalenessSlots: BN };
name: string;
}[] {
if (cluster == 'devnet') {
return [
{
@ -389,7 +351,9 @@ async function setupMango(): Promise<{
return { group, client, connection, user };
}
function getOraclesForMangoGroup(group: Group) {
function getOraclesForMangoGroup(
group: Group,
): { oraclePk: PublicKey; oracleConfig: OracleConfig; name: string }[] {
// oracles for tokens
const oracles1 = Array.from(group.banksMapByName.values())
.filter(
@ -439,7 +403,11 @@ function getOraclesForMangoGroup(group: Group) {
return oracles;
}
async function setupSwitchboard(client: MangoClient) {
async function setupSwitchboard(client: MangoClient): Promise<{
sbOnDemandProgram: Anchor30Program<Idl>;
crossbarClient: CrossbarClient;
queue: PublicKey;
}> {
const idl = await Anchor30Program.fetchIdl(
SB_ON_DEMAND_PID,
client.program.provider,
@ -459,11 +427,7 @@ async function setupSwitchboard(client: MangoClient) {
async function updateFilteredOraclesAis(
connection: Connection,
sbOnDemandProgram: Anchor30Program<Idl>,
filteredOracles: {
decodedPullFeed: any;
oracle: { oraclePk: PublicKey; oracleConfig: OracleConfig; name: string };
ai: AccountInfo<Buffer> | null;
}[],
filteredOracles: OracleInterface[],
): Promise<void> {
const ais = (
await Promise.all(

View File

@ -108,7 +108,7 @@ async function setupSwitchboard(userProvider: AnchorProvider) {
numSignatures: 3, // number of signatures to fetch per update
minSampleSize: 2, // minimum number of responses to sample
maxStaleness:
tier!.maxStalenessSlots == -1 ? 10000 : tier!.maxStalenessSlots, // maximum staleness of responses in seconds to sample
tier!.maxStalenessSlots == -1 ? 10000 : tier!.maxStalenessSlots!, // maximum staleness of responses in seconds to sample
};
console.log('Initializing new data feed');