@symmetry-hq/liquidity-sdk
Version:
Exchange functionality using symmetry funds liquidity
104 lines (96 loc) • 4.12 kB
text/typescript
import { BN, Program } from "@coral-xyz/anchor";
import { AccountInfo, GetProgramAccountsResponse, PublicKey } from "@solana/web3.js";
import { FundsIDL } from "./fundsIDL";
import { CurveChainData, FundStateChainData, OraclePrice, TokenSettings } from "./types";
import { parsePriceData } from "@pythnetwork/client";
export function asciiToString(
coingeckoIdAscii: number[],
): string {
let coingeckoId: string = "";
for(let i=0; i<coingeckoIdAscii.length; i++)
if(coingeckoIdAscii[i] != 0)
coingeckoId += String.fromCharCode(coingeckoIdAscii[i]).toString();
return coingeckoId;
}
export function decodeTokenList(
program: Program<FundsIDL>,
tokenListAccountInfo: AccountInfo<Buffer>,
): TokenSettings[] {
let state = program.coder.accounts.decode("tokenList", tokenListAccountInfo.data);
let numTokens = state.numTokens.toNumber();
let tokens = [];
for (let i = 0; i < numTokens; i++) {
let tokenSettings = state.list[i];
tokens.push({
id: i,
symbol: "",
name: "",
tokenMint: tokenSettings.tokenMint.toBase58(),
decimals: tokenSettings.decimals,
coingeckoId: asciiToString(tokenSettings.coingeckoId),
pdaTokenAccount: tokenSettings.pdaTokenAccount.toBase58(),
oracleType: tokenSettings.oracleType == 0 ? "Pyth" : "Switchboard",
oracleAccount: tokenSettings.oracleAccount.toBase58(),
oracleIndex: tokenSettings.oracleIndex,
oracleConfidencePct: tokenSettings.oracleConfidencePct,
fixedConfidenceBps: tokenSettings.fixedConfidenceBps,
tokenSwapFeeBeforeTwBps: tokenSettings.tokenSwapFeeBeforeTwBps,
tokenSwapFeeAfterTwBps: tokenSettings.tokenSwapFeeAfterTwBps,
isLive: tokenSettings.isLive == 0 ? false : true,
lpOn: tokenSettings.lpOn == 0 ? false : true,
useCurveData: tokenSettings.useCurveData == 0 ? false : true,
additionalData: tokenSettings.additionalData,
});
}
return tokens;
}
export function decodeCurveData(
program: Program<FundsIDL>,
curveDataAccountInfo: AccountInfo<Buffer>,
): CurveChainData {
let state = program.coder.accounts.decode("prismData", curveDataAccountInfo.data);
return state;
}
export function decodeFunds(
program: Program<FundsIDL>,
fundStateAccountInfos: GetProgramAccountsResponse,
): {pubkey: PublicKey, fund: FundStateChainData}[] {
return fundStateAccountInfos.map(account => { return {
pubkey: account.pubkey,
fund: program.coder.accounts.decode("fundState", account.account.data)
}});
}
export function decodeOraclePrices(
oracleDataAccountInfos: Array<AccountInfo<Buffer>>,
tokenListData: TokenSettings[],
): OraclePrice[] {
let oraclePrices = [];
for(let i=0; i<oracleDataAccountInfos.length; i++){
let avgPrice = 0;
let baseConfidence = 0;
if(oracleDataAccountInfos[i] == null) {} else
if (tokenListData[i].oracleType == "Pyth") {
let parsed = parsePriceData(oracleDataAccountInfos[i].data).aggregate;
avgPrice = parsed.price * 10 ** 12;
baseConfidence = parsed.confidence * 10 ** 12 * tokenListData[i].fixedConfidenceBps / 100;
} else {
let price = parseInt(new BN(
oracleDataAccountInfos[i].data.subarray(
tokenListData[i].oracleIndex * 8 + 9,
tokenListData[i].oracleIndex * 8 + 17
),
10,
"le"
).toString());
baseConfidence = price * tokenListData[i].oracleConfidencePct / 10000;
avgPrice = price - baseConfidence;
}
let additionalConfidence = avgPrice * tokenListData[i].fixedConfidenceBps / 10000;
oraclePrices.push({
sell_price: avgPrice - baseConfidence - additionalConfidence,
avg_price: avgPrice,
buy_price: avgPrice + baseConfidence + additionalConfidence,
})
}
return oraclePrices;
}