import { PublicKey, TransactionInstruction } from '@solana/web3.js'; import { BASKETS_V3_PROGRAM_ID, PYTHNET_CUSTODY_PRICE_USDC_ACCOUNT, PYTHNET_CUSTODY_PRICE_WSOL_ACCOUNT } from '../../constants'; import { OraclePriceLayout, OraclePriceOnChain } from '../../layouts/oracle'; import { getAta, getBasketFeesPda, getGlobalConfigPda, getRebalanceIntentPda } from '../pda'; import BN from 'bn.js'; import { TOKEN_PROGRAM_ID } from '@solana/spl-token'; const UPDATE_TOKEN_PRICES_DISCRIMINATOR = Buffer.from([147, 87, 140, 33, 214, 189, 181, 242]); const UPDATE_TOKEN_PRICES_CUSTOM_DISCRIMINATOR = Buffer.from([71, 100, 35, 136, 116, 239, 54, 126]); export function updateTokenPricesIx(params: { keeper: PublicKey, basket: PublicKey, rebalanceIntent: PublicKey, basketRebalanceIntent?: PublicKey, lookupTable0: PublicKey, lookupTable1: PublicKey, tokenIndices: number[], // length 20 additionalOracleAccounts: PublicKey[], basketMint?: PublicKey, }): TransactionInstruction { let globalConfig = getGlobalConfigPda(); const tokenIndices = params.tokenIndices.slice(0, 20); while (tokenIndices.length < 20) { tokenIndices.push(0); } const data = Buffer.concat([ Buffer.from(UPDATE_TOKEN_PRICES_DISCRIMINATOR), // 8 bytes Buffer.from(tokenIndices) ]); const keys = [ { pubkey: params.keeper, isSigner: true, isWritable: true }, { pubkey: params.basket, isSigner: false, isWritable: true }, { pubkey: params.rebalanceIntent, isSigner: false, isWritable: true }, { pubkey: globalConfig, isSigner: false, isWritable: false }, { pubkey: PYTHNET_CUSTODY_PRICE_WSOL_ACCOUNT, isSigner: false, isWritable: true }, { pubkey: PYTHNET_CUSTODY_PRICE_USDC_ACCOUNT, isSigner: false, isWritable: true }, { pubkey: params.lookupTable0, isSigner: false, isWritable: true }, { pubkey: params.lookupTable1, isSigner: false, isWritable: true }, { pubkey: params.basketRebalanceIntent ?? BASKETS_V3_PROGRAM_ID, isSigner: false, isWritable: params.basketRebalanceIntent ? true : false }, ]; // remaining accounts keys.push(...params.additionalOracleAccounts.map((pubkey) => ({ pubkey, isSigner: false, isWritable: false }))); if (params.basketMint) { let basketFeesWallet = getBasketFeesPda(params.basket); let basketFeesTokenAccount = getAta(basketFeesWallet, params.basketMint); keys.push({ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }); keys.push({ pubkey: params.basketMint, isSigner: false, isWritable: true }); keys.push({ pubkey: basketFeesTokenAccount, isSigner: false, isWritable: true }); } return new TransactionInstruction({ keys, programId: BASKETS_V3_PROGRAM_ID, data }); } export function updateTokenPricesCustomIx(params: { manager: PublicKey, basket: PublicKey, tokenIndices: number[], // length 10 tokenPrices: OraclePriceOnChain[] // length 10 }): TransactionInstruction { const { manager, basket } = params; const globalConfig = getGlobalConfigPda(); const rebalanceIntent = getRebalanceIntentPda(basket, manager); const tokenIndices = params.tokenIndices.slice(0, 10); while (tokenIndices.length < 10) tokenIndices.push(0); const tokenPrices = params.tokenPrices.slice(0, 10); while (tokenPrices.length < 10) { tokenPrices.push({ price: { high: new BN(0), low: new BN(0) }, conf: { high: new BN(0), low: new BN(0) }, updateTime: new BN(0), }); } const pricesBufs = tokenPrices.map((p) => { const buf = Buffer.alloc(OraclePriceLayout.span); OraclePriceLayout.encode(p, buf); return buf; }); const data = Buffer.concat([ Buffer.from(UPDATE_TOKEN_PRICES_CUSTOM_DISCRIMINATOR), Buffer.from(tokenIndices), ...pricesBufs, ]); const keys = [ { pubkey: manager, isSigner: true, isWritable: true }, { pubkey: basket, isSigner: false, isWritable: true }, { pubkey: rebalanceIntent, isSigner: false, isWritable: true }, { pubkey: globalConfig, isSigner: false, isWritable: false }, ]; return new TransactionInstruction({ keys, programId: BASKETS_V3_PROGRAM_ID, data, }); }