@indigo-labs/indigo-sdk
Version:
Indigo SDK for interacting with Indigo endpoints via lucid-evolution
59 lines (57 loc) • 2.19 kB
text/typescript
import { match, P } from 'ts-pattern';
import { Rational } from '../../types/rational';
import { decodePriceUpdate, decodePythMessage } from '../../utils/pyth';
import {
DerivedPythPrice,
fromDataDerivedPythPrice,
PythConfiguration,
} from './types';
import { ParsedFeedPayload } from '@pythnetwork/pyth-lazer-sdk';
import { fromHex } from '@lucid-evolution/lucid';
/** Rational form { num, den } so we can do exact division (e.g. 1/0.00001 = 100000). */
export function derivePythPrice(
derivedPythPrice: DerivedPythPrice,
messageHex: string,
): Rational {
const decodedMessage = decodePythMessage(fromHex(messageHex));
const pricePayload = decodePriceUpdate(decodedMessage.payload);
return match(derivedPythPrice)
.with(
{ Value: P.select() },
(value: { configuration: PythConfiguration }) => {
const payload = pricePayload.priceFeeds.find(
(p: ParsedFeedPayload) =>
p.priceFeedId === Number(value.configuration.priceFeedId),
);
if (!payload)
throw new Error(
`Pyth payload not found for feed ID: ${value.configuration.priceFeedId}`,
);
const priceStr = payload.price;
if (priceStr === undefined)
throw new Error(`Pyth feed ${payload.priceFeedId} has no price`);
const price = BigInt(priceStr);
const exp = payload.exponent ?? 0;
if (exp >= 0) {
return { numerator: price * 10n ** BigInt(exp), denominator: 1n };
}
return { numerator: price, denominator: 10n ** BigInt(-exp) };
},
)
.with({ Inverse: P.select() }, (inverse) => {
const inner = derivePythPrice(
fromDataDerivedPythPrice(inverse.value),
messageHex,
);
return { numerator: inner.denominator, denominator: inner.numerator };
})
.with({ Divide: P.select() }, (divide) => {
const x = derivePythPrice(fromDataDerivedPythPrice(divide.x), messageHex);
const y = derivePythPrice(fromDataDerivedPythPrice(divide.y), messageHex);
return {
numerator: x.numerator * y.denominator,
denominator: x.denominator * y.numerator,
};
})
.exhaustive();
}