UNPKG

@symmetry-hq/baskets-v2-sdk

Version:

Symmetry Baskets V2 SDK

112 lines (98 loc) 3.77 kB
// Core dependencies import { BN, Program } from "@coral-xyz/anchor"; import { PublicKey, TransactionInstruction } from "@solana/web3.js"; // Local imports import { BasketsProgram } from "../../idl/types"; import { fetchBasketState } from "../../state/basket"; import { MAX_PRICE_UPDATES_PER_TX, PYTHNET_CUSTODY_PRICE_SOL_ACCOUNT, PYTHNET_CUSTODY_PRICE_USDC_ACCOUNT, UPDATE_PRICES_AUTHORITY } from "../../utils/constants"; async function getJupPrices( mints: PublicKey[], ): Promise<number[]> { let batchSize = 100; let prices: number[] = []; for (let i = 0; i < mints.length; i += batchSize) { const batch = mints.slice(i, i + batchSize); let str = batch.map(mint => mint.toBase58()).join(","); let result = await fetch(`https://api.jup.ag/price/v2?ids=${str}`); let data = (await result.json()).data; for (let j = 0; j < batch.length; j++) { if (data[batch[j].toBase58()]) prices.push(data[batch[j].toBase58()].price); else { throw new Error("Price not found for " + batch[j].toBase58()); } } } return prices; } // Helper function to create update prices instruction async function createUpdatePricesIx( program: Program<BasketsProgram>, basket: PublicKey, accounts: { pubkey: PublicKey; isSigner: boolean; isWritable: boolean; }[], tokenPrices: BN[], ): Promise<TransactionInstruction> { while (tokenPrices.length < 25) tokenPrices.push(new BN(0)); return program.methods .updateTokenPrices(tokenPrices) .accountsStrict({ authority: UPDATE_PRICES_AUTHORITY, basket, usdcPriceOracle: PYTHNET_CUSTODY_PRICE_USDC_ACCOUNT, solPriceOracle: PYTHNET_CUSTODY_PRICE_SOL_ACCOUNT, }) .remainingAccounts(accounts) .instruction(); }; // Update token prices instructions export async function updateTokenPricesIxs(params: { program: Program<BasketsProgram>; basket: PublicKey; }): Promise<{ ixs: TransactionInstruction[], luts: PublicKey[], }> { // Destructure params and get basket state const { program, basket } = params; const basketState = await fetchBasketState(program, basket); let jupPrices = await getJupPrices(basketState.compositionMints.slice(0, basketState.numTokens)); // Initialize arrays to store instructions and remaining accounts const ixs: TransactionInstruction[] = []; let remainingAccounts = []; let tokenPrices = []; // Process each token's oracle accounts for (let i = 0; i < basketState.numTokens; i++) { let num = Math.floor(jupPrices[i] * 10 ** 10); tokenPrices.push(new BN(num).mul(new BN(100))); // Add primary oracle remainingAccounts.push({ pubkey: basketState.compositionOracle1[i], isSigner: false, isWritable: false, }); remainingAccounts.push({ pubkey: basketState.compositionOracle2[i], isSigner: false, isWritable: false, }); // Create instruction if we've hit the max accounts limit if (remainingAccounts.length + 1 >= MAX_PRICE_UPDATES_PER_TX) { ixs.push(await createUpdatePricesIx(program, basket, remainingAccounts, tokenPrices)); remainingAccounts = []; tokenPrices = []; } } // Create final instruction if there are remaining accounts if (remainingAccounts.length > 0) { ixs.push(await createUpdatePricesIx(program, basket, remainingAccounts, tokenPrices)); } return { ixs, luts: [basketState.lookupTable1, basketState.lookupTable2], }; }