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