UNPKG

raydium-sdk-v2-custody

Version:

An SDK for building applications on top of Raydium.

1,509 lines (1,325 loc) 49.6 kB
import { Connection, Keypair, PublicKey, Signer, SystemProgram, TransactionInstruction } from "@solana/web3.js"; import BN from "bn.js"; import { bool, s32, struct, u128, u64, u8 } from "@/marshmallow"; import { ASSOCIATED_TOKEN_PROGRAM_ID, getAssociatedTokenAddressSync, TOKEN_2022_PROGRAM_ID, TOKEN_PROGRAM_ID } from "@solana/spl-token"; import { getATAAddress, InstructionType, MEMO_PROGRAM_ID, RENT_PROGRAM_ID } from "@/common"; import { ReturnTypeMakeInstructions } from "../type"; import { getPdaExBitmapAccount, getPdaPersonalPositionAddress, getPdaProtocolPositionAddress, getPdaTickArrayAddress, getPdaUserState } from "./utils/pda"; import { ApiV3PoolInfoConcentratedItem, ApiV3Token, ClmmKeys } from "@/api"; import { ClosePositionExtInfo, ManipulateLiquidityExtInfo, OpenPositionFromBaseCustodyExtInfo, OpenPositionFromBaseExtInfo } from "./type"; import { TickUtils } from "./utils/tick"; import { PoolUtils } from "./utils/pool"; import { ClmmPositionLayout } from "./layout"; const anchorDataBuf = { initializeUser: [111, 17, 185, 250, 60, 122, 38, 254], deposit: [242, 35, 198, 137, 82, 225, 242, 182], withdraw: [183, 18, 70, 156, 148, 109, 161, 34], openPosition: [135, 128, 47, 77, 15, 152, 240, 49], closePosition: [123, 134, 81, 0, 49, 68, 98, 98], increaseLiquidity: [46, 156, 243, 118, 13, 205, 251, 178], decreaseLiquidity: [160, 38, 208, 111, 104, 91, 44, 1], swap: [248, 198, 158, 145, 225, 117, 135, 200], } interface InitializeUserInstruction { connection: Connection, programId: PublicKey, payer: PublicKey, authority: PublicKey, } export class CustodyInstrument { static initializeUserInstruction( programId: PublicKey, payer: PublicKey, authority: PublicKey, userState: PublicKey, ): TransactionInstruction { const dataLayout = struct([]) const keys = [ { pubkey: payer, isSigner: true, isWritable: true }, { pubkey: authority, isSigner: false, isWritable: false }, { pubkey: userState, isSigner: false, isWritable: true }, { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, ] const data = Buffer.alloc(dataLayout.span) dataLayout.encode({}, data) const aData = Buffer.from([...anchorDataBuf.initializeUser, ...data]) return new TransactionInstruction({ keys, programId, data: aData, }) } static initializeUserInstructions(props: InitializeUserInstruction): ReturnTypeMakeInstructions<{ userState: PublicKey, }> { const { programId, payer, authority } = props const { publicKey: userState } = getPdaUserState(programId, payer) const ins = this.initializeUserInstruction(programId, payer, authority, userState) return { signers: [], instructions: [ins], instructionTypes: [InstructionType.CreateAccount, InstructionType.CustodyInitializeUser], address: { userState }, lookupTableAddress: [], } } static depositInstruction( programId: PublicKey, payer: PublicKey, userState: PublicKey, userTokenAccount: PublicKey, userTokenCustody: PublicKey, mint: PublicKey, amount: BN, ): TransactionInstruction { const dataLayout = struct([u64("amount")]) const keys = [ { pubkey: payer, isSigner: true, isWritable: true }, { pubkey: userState, isSigner: false, isWritable: false }, { pubkey: userTokenAccount, isSigner: false, isWritable: true }, { pubkey: userTokenCustody, isSigner: false, isWritable: true }, { pubkey: mint, isSigner: false, isWritable: false }, { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: TOKEN_2022_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, ] const data = Buffer.alloc(dataLayout.span) dataLayout.encode({ amount }, data) const aData = Buffer.from([...anchorDataBuf.deposit, ...data]) return new TransactionInstruction({ keys, programId, data: aData, }) } static async depositInstructions({ programId, ownerInfo, mint, amount, }: { programId: PublicKey, ownerInfo: { wallet: PublicKey, tokenAccount: PublicKey, }, mint: ApiV3Token, amount: BN, }): Promise<ReturnTypeMakeInstructions> { const { publicKey: userState } = getPdaUserState(programId, ownerInfo.wallet) const userTokenCustody = getAssociatedTokenAddressSync(new PublicKey(mint.address), userState, true, new PublicKey(mint.programId)) const ins = this.depositInstruction( programId, ownerInfo.wallet, userState, ownerInfo.tokenAccount, userTokenCustody, new PublicKey(mint.address), amount, ) return { signers: [], instructions: [ins], instructionTypes: [InstructionType.CustodyDeposit], address: { userState, userTokenCustody }, lookupTableAddress: [], } } static withdrawInstruction( programId: PublicKey, payer: PublicKey, userState: PublicKey, userTokenAccount: PublicKey, userTokenCustody: PublicKey, mint: PublicKey, amount: BN, ): TransactionInstruction { const dataLayout = struct([u64("amount")]) const keys = [ { pubkey: payer, isSigner: true, isWritable: true }, { pubkey: userState, isSigner: false, isWritable: false }, { pubkey: userTokenAccount, isSigner: false, isWritable: true }, { pubkey: userTokenCustody, isSigner: false, isWritable: true }, { pubkey: mint, isSigner: false, isWritable: false }, { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: TOKEN_2022_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, ] const data = Buffer.alloc(dataLayout.span) dataLayout.encode({ amount }, data) const aData = Buffer.from([...anchorDataBuf.withdraw, ...data]) return new TransactionInstruction({ keys, programId, data: aData, }) } static async withdrawInstructions({ programId, ownerInfo, mint, amount, }: { programId: PublicKey, ownerInfo: { wallet: PublicKey, tokenAccount: PublicKey, }, mint: ApiV3Token, amount: BN, }): Promise<ReturnTypeMakeInstructions> { const { publicKey: userState } = getPdaUserState(programId, ownerInfo.wallet) const userTokenCustody = getAssociatedTokenAddressSync(new PublicKey(mint.address), userState, true, new PublicKey(mint.programId)) const ins = this.withdrawInstruction( programId, ownerInfo.wallet, userState, ownerInfo.tokenAccount, userTokenCustody, new PublicKey(mint.address), amount, ) return { signers: [], instructions: [ins], instructionTypes: [InstructionType.CustodyWithdraw], address: { userState, userTokenCustody }, lookupTableAddress: [], } } static openPositionFromLiquidityInstruction( custodyProgramId: PublicKey, remoteProgramId: PublicKey, payer: PublicKey, userState: PublicKey, positionNftMint: PublicKey, positionNftAccount: PublicKey, poolId: PublicKey, protocolPosition: PublicKey, tickArrayLower: PublicKey, tickArrayUpper: PublicKey, personalPosition: PublicKey, userTokenAccountA: PublicKey, userTokenAccountB: PublicKey, tokenCustodyA: PublicKey, tokenCustodyB: PublicKey, tokenVaultA: PublicKey, tokenVaultB: PublicKey, tokenMintA: PublicKey, tokenMintB: PublicKey, tickLowerIndex: number, tickUpperIndex: number, tickArrayLowerStartIndex: number, tickArrayUpperStartIndex: number, liquidity: BN, amountMaxA: BN, amountMaxB: BN, withMetadata: "create" | "no-create", exTickArrayBitmap?: PublicKey, ): TransactionInstruction { const dataLayout = struct([ s32("tickLowerIndex"), s32("tickUpperIndex"), s32("tickArrayLowerStartIndex"), s32("tickArrayUpperStartIndex"), u128("liquidity"), u64("amountMaxA"), u64("amountMaxB"), bool("withMetadata"), u8("optionBaseFlag"), bool("baseFlag"), ]) const remainingAccounts = [ ...(exTickArrayBitmap ? [{ pubkey: exTickArrayBitmap, isSigner: false, isWritable: true }] : []), ] const keys = [ { pubkey: payer, isSigner: true, isWritable: true }, { pubkey: userState, isSigner: false, isWritable: true }, { pubkey: positionNftMint, isSigner: true, isWritable: true }, { pubkey: positionNftAccount, isSigner: false, isWritable: true }, { pubkey: poolId, isSigner: false, isWritable: true }, { pubkey: protocolPosition, isSigner: false, isWritable: true }, { pubkey: tickArrayLower, isSigner: false, isWritable: true }, { pubkey: tickArrayUpper, isSigner: false, isWritable: true }, { pubkey: personalPosition, isSigner: false, isWritable: true }, { pubkey: userTokenAccountA, isSigner: false, isWritable: true }, { pubkey: userTokenAccountB, isSigner: false, isWritable: true }, { pubkey: tokenCustodyA, isSigner: false, isWritable: true }, { pubkey: tokenCustodyB, isSigner: false, isWritable: true }, { pubkey: tokenVaultA, isSigner: false, isWritable: true }, { pubkey: tokenVaultB, isSigner: false, isWritable: true }, { pubkey: RENT_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: TOKEN_2022_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: tokenMintA, isSigner: false, isWritable: false }, { pubkey: tokenMintB, isSigner: false, isWritable: false }, { pubkey: remoteProgramId, isSigner: false, isWritable: false }, ...remainingAccounts, ] const data = Buffer.alloc(dataLayout.span); dataLayout.encode( { tickLowerIndex, tickUpperIndex, tickArrayLowerStartIndex, tickArrayUpperStartIndex, liquidity, amountMaxA, amountMaxB, withMetadata: withMetadata === "create", baseFlag: false, optionBaseFlag: 0, }, data, ) const aData = Buffer.from([...anchorDataBuf.openPosition, ...data]) return new TransactionInstruction({ keys, programId: custodyProgramId, data: aData, }) } static async openPositionFromLiquidityInstructions({ custodyProgramId, poolInfo, poolKeys, ownerInfo, tickLower, tickUpper, liquidity, amountMaxA, amountMaxB, withMetadata, getEphemeralSigners, }: { custodyProgramId: PublicKey, poolInfo: ApiV3PoolInfoConcentratedItem; poolKeys: ClmmKeys; ownerInfo: { feePayer: PublicKey; wallet: PublicKey; tokenAccountA: PublicKey; tokenAccountB: PublicKey; }; tickLower: number; tickUpper: number; liquidity: BN; amountMaxA: BN; amountMaxB: BN; withMetadata: "create" | "no-create"; getEphemeralSigners?: (k: number) => any; }): Promise<ReturnTypeMakeInstructions> { const signers: Signer[] = []; const [programId, id] = [new PublicKey(poolInfo.programId), new PublicKey(poolInfo.id)]; let nftMintAccount; if (getEphemeralSigners) { nftMintAccount = new PublicKey((await getEphemeralSigners(1))[0]); } else { const _k = Keypair.generate(); signers.push(_k); nftMintAccount = _k.publicKey; } const tickArrayLowerStartIndex = TickUtils.getTickArrayStartIndexByTick(tickLower, poolInfo.config.tickSpacing); const tickArrayUpperStartIndex = TickUtils.getTickArrayStartIndexByTick(tickUpper, poolInfo.config.tickSpacing); const { publicKey: tickArrayLower } = getPdaTickArrayAddress(programId, id, tickArrayLowerStartIndex); const { publicKey: tickArrayUpper } = getPdaTickArrayAddress(programId, id, tickArrayUpperStartIndex); const { publicKey: userState } = getPdaUserState(custodyProgramId, ownerInfo.wallet) const { publicKey: tokenCustodyA } = getATAAddress(userState, new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintA.programId)) const { publicKey: tokenCustodyB } = getATAAddress(userState, new PublicKey(poolInfo.mintB.address), new PublicKey(poolInfo.mintB.programId)) const { publicKey: positionNftAccount } = getATAAddress(userState, nftMintAccount, TOKEN_2022_PROGRAM_ID) const { publicKey: personalPosition } = getPdaPersonalPositionAddress(programId, nftMintAccount); const { publicKey: protocolPosition } = getPdaProtocolPositionAddress(programId, id, tickLower, tickUpper); const ins = this.openPositionFromLiquidityInstruction( custodyProgramId, programId, ownerInfo.feePayer, userState, nftMintAccount, positionNftAccount, id, protocolPosition, tickArrayLower, tickArrayUpper, personalPosition, ownerInfo.tokenAccountA, ownerInfo.tokenAccountB, tokenCustodyA, tokenCustodyB, new PublicKey(poolKeys.vault.A), new PublicKey(poolKeys.vault.B), new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintB.address), tickLower, tickUpper, tickArrayLowerStartIndex, tickArrayUpperStartIndex, liquidity, amountMaxA, amountMaxB, withMetadata, PoolUtils.isOverflowDefaultTickarrayBitmap(poolInfo.config.tickSpacing, [ tickArrayLowerStartIndex, tickArrayUpperStartIndex, ]) ? getPdaExBitmapAccount(programId, id).publicKey : undefined, ) return { address: { nftMint: nftMintAccount, tickArrayLower, tickArrayUpper, positionNftAccount, personalPosition, protocolPosition, }, instructions: [ins], signers, instructionTypes: [InstructionType.CustodyOpenPosition], lookupTableAddress: poolKeys.lookupTableAccount ? [poolKeys.lookupTableAccount] : [], } } static openPositionFromBaseInstruction( custodyProgramId: PublicKey, remoteProgramId: PublicKey, payer: PublicKey, userState: PublicKey, positionNftMint: PublicKey, positionNftAccount: PublicKey, poolId: PublicKey, protocolPosition: PublicKey, tickArrayLower: PublicKey, tickArrayUpper: PublicKey, personalPosition: PublicKey, userTokenAccountA: PublicKey, userTokenAccountB: PublicKey, tokenCustodyA: PublicKey, tokenCustodyB: PublicKey, tokenVaultA: PublicKey, tokenVaultB: PublicKey, tokenMintA: PublicKey, tokenMintB: PublicKey, tickLowerIndex: number, tickUpperIndex: number, tickArrayLowerStartIndex: number, tickArrayUpperStartIndex: number, withMetadata: "create" | "no-create", base: "MintA" | "MintB", baseAmount: BN, otherAmountMax: BN, exTickArrayBitmap?: PublicKey, ): TransactionInstruction { const dataLayout = struct([ s32("tickLowerIndex"), s32("tickUpperIndex"), s32("tickArrayLowerStartIndex"), s32("tickArrayUpperStartIndex"), u128("liquidity"), u64("amountMaxA"), u64("amountMaxB"), bool("withMetadata"), u8("optionBaseFlag"), bool("baseFlag"), ]) const remainingAccounts = [ ...(exTickArrayBitmap ? [{ pubkey: exTickArrayBitmap, isSigner: false, isWritable: true }] : []), ] const keys = [ { pubkey: payer, isSigner: true, isWritable: true }, { pubkey: userState, isSigner: false, isWritable: true }, { pubkey: positionNftMint, isSigner: true, isWritable: true }, { pubkey: positionNftAccount, isSigner: false, isWritable: true }, { pubkey: poolId, isSigner: false, isWritable: true }, { pubkey: protocolPosition, isSigner: false, isWritable: true }, { pubkey: tickArrayLower, isSigner: false, isWritable: true }, { pubkey: tickArrayUpper, isSigner: false, isWritable: true }, { pubkey: personalPosition, isSigner: false, isWritable: true }, { pubkey: userTokenAccountA, isSigner: false, isWritable: true }, { pubkey: userTokenAccountB, isSigner: false, isWritable: true }, { pubkey: tokenCustodyA, isSigner: false, isWritable: true }, { pubkey: tokenCustodyB, isSigner: false, isWritable: true }, { pubkey: tokenVaultA, isSigner: false, isWritable: true }, { pubkey: tokenVaultB, isSigner: false, isWritable: true }, { pubkey: RENT_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: TOKEN_2022_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: tokenMintA, isSigner: false, isWritable: false }, { pubkey: tokenMintB, isSigner: false, isWritable: false }, { pubkey: remoteProgramId, isSigner: false, isWritable: false }, ...remainingAccounts, ] const data = Buffer.alloc(dataLayout.span) dataLayout.encode( { tickLowerIndex, tickUpperIndex, tickArrayLowerStartIndex, tickArrayUpperStartIndex, liquidity: new BN(0), amountMaxA: base === "MintA" ? baseAmount : otherAmountMax, amountMaxB: base === "MintA" ? otherAmountMax : baseAmount, withMetadata: withMetadata === "create", baseFlag: base === "MintA", optionBaseFlag: 1, }, data, ) const aData = Buffer.from([...anchorDataBuf.openPosition, ...data]) return new TransactionInstruction({ keys, programId: custodyProgramId, data: aData, }) } static async openPositionFromBaseInstructions({ custodyProgramId, poolInfo, poolKeys, ownerInfo, tickLower, tickUpper, base, baseAmount, otherAmountMax, withMetadata, getEphemeralSigners, }: { custodyProgramId: PublicKey, poolInfo: ApiV3PoolInfoConcentratedItem; poolKeys: ClmmKeys; ownerInfo: { feePayer: PublicKey; wallet: PublicKey; tokenAccountA: PublicKey; tokenAccountB: PublicKey; }; tickLower: number; tickUpper: number; base: "MintA" | "MintB"; baseAmount: BN; otherAmountMax: BN; withMetadata: "create" | "no-create"; getEphemeralSigners?: (k: number) => any; }): Promise<ReturnTypeMakeInstructions> { const signers: Signer[] = [] const [programId, id] = [new PublicKey(poolInfo.programId), new PublicKey(poolInfo.id)] let nftMintAccount: PublicKey; if (getEphemeralSigners) { nftMintAccount = new PublicKey((await getEphemeralSigners(1))[0]); } else { const _k = Keypair.generate(); signers.push(_k); nftMintAccount = _k.publicKey; } const tickArrayLowerStartIndex = TickUtils.getTickArrayStartIndexByTick(tickLower, poolInfo.config.tickSpacing); const tickArrayUpperStartIndex = TickUtils.getTickArrayStartIndexByTick(tickUpper, poolInfo.config.tickSpacing); const { publicKey: tickArrayLower } = getPdaTickArrayAddress(programId, id, tickArrayLowerStartIndex); const { publicKey: tickArrayUpper } = getPdaTickArrayAddress(programId, id, tickArrayUpperStartIndex); const { publicKey: userState } = getPdaUserState(custodyProgramId, ownerInfo.wallet) const { publicKey: tokenCustodyA } = getATAAddress(userState, new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintA.programId)) const { publicKey: tokenCustodyB } = getATAAddress(userState, new PublicKey(poolInfo.mintB.address), new PublicKey(poolInfo.mintB.programId)) const { publicKey: positionNftAccount } = getATAAddress(userState, nftMintAccount, TOKEN_2022_PROGRAM_ID) const { publicKey: personalPosition } = getPdaPersonalPositionAddress(programId, nftMintAccount); const { publicKey: protocolPosition } = getPdaProtocolPositionAddress(programId, id, tickLower, tickUpper); const ins = this.openPositionFromBaseInstruction( custodyProgramId, programId, ownerInfo.feePayer, userState, nftMintAccount, positionNftAccount, id, protocolPosition, tickArrayLower, tickArrayUpper, personalPosition, ownerInfo.tokenAccountA, ownerInfo.tokenAccountB, tokenCustodyA, tokenCustodyB, new PublicKey(poolKeys.vault.A), new PublicKey(poolKeys.vault.B), new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintB.address), tickLower, tickUpper, tickArrayLowerStartIndex, tickArrayUpperStartIndex, withMetadata, base, baseAmount, otherAmountMax, PoolUtils.isOverflowDefaultTickarrayBitmap(poolInfo.config.tickSpacing, [ tickArrayLowerStartIndex, tickArrayUpperStartIndex, ]) ? getPdaExBitmapAccount(programId, id).publicKey : undefined, ) return { address: { nftMint: nftMintAccount, tickArrayLower, tickArrayUpper, positionNftAccount, personalPosition, protocolPosition, }, instructions: [ins], signers, instructionTypes: [InstructionType.CustodyOpenPosition], lookupTableAddress: poolKeys.lookupTableAccount ? [poolKeys.lookupTableAccount] : [], } } static closePositionInstruction( custodyProgramId: PublicKey, remoteProgramId: PublicKey, payer: PublicKey, userState: PublicKey, positionNftMint: PublicKey, positionNftAccount: PublicKey, personalPosition: PublicKey, ): TransactionInstruction { const dataLayout = struct([]) const keys = [ { pubkey: payer, isSigner: true, isWritable: true }, { pubkey: userState, isSigner: false, isWritable: true }, { pubkey: positionNftMint, isSigner: false, isWritable: true }, { pubkey: positionNftAccount, isSigner: false, isWritable: true }, { pubkey: personalPosition, isSigner: false, isWritable: true }, { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, { pubkey: TOKEN_2022_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: remoteProgramId, isSigner: false, isWritable: false }, ] const data = Buffer.alloc(dataLayout.span) const aData = Buffer.from([...anchorDataBuf.closePosition, ...data]) return new TransactionInstruction({ keys, programId: custodyProgramId, data: aData, }) } static closePositionInstructions({ custodyProgramId, poolInfo, poolKeys, ownerInfo, ownerPosition, }: { custodyProgramId: PublicKey, poolInfo: ApiV3PoolInfoConcentratedItem poolKeys: ClmmKeys ownerInfo: { feePayer: PublicKey; wallet: PublicKey; } ownerPosition: ClmmPositionLayout }): ReturnTypeMakeInstructions<ClosePositionExtInfo["address"]> { const programId = new PublicKey(poolInfo.programId); const { publicKey: userState } = getPdaUserState(custodyProgramId, ownerInfo.wallet) const positionNftAccount = getATAAddress(userState, ownerPosition.nftMint, TOKEN_2022_PROGRAM_ID).publicKey const { publicKey: personalPosition } = getPdaPersonalPositionAddress(programId, ownerPosition.nftMint); const ins = this.closePositionInstruction( custodyProgramId, programId, ownerInfo.feePayer, userState, ownerPosition.nftMint, positionNftAccount, personalPosition, ) return { address: { positionNftAccount, personalPosition, }, signers: [], instructions: [ins], instructionTypes: [InstructionType.CustodyClosePosition], lookupTableAddress: poolKeys.lookupTableAccount ? [poolKeys.lookupTableAccount] : [], } } static increasePositionFromLiquidityInstruction( custodyProgramId: PublicKey, remoteProgramId: PublicKey, payer: PublicKey, userState: PublicKey, positionNftAccount: PublicKey, personalPosition: PublicKey, poolId: PublicKey, protocolPosition: PublicKey, tickArrayLower: PublicKey, tickArrayUpper: PublicKey, tokenCustodyA: PublicKey, tokenCustodyB: PublicKey, tokenVaultA: PublicKey, tokenVaultB: PublicKey, tokenMintA: PublicKey, tokenMintB: PublicKey, liquidity: BN, amountMaxA: BN, amountMaxB: BN, exTickArrayBitmap?: PublicKey, ): TransactionInstruction { const dataLayout = struct([ u128("liquidity"), u64("amountMaxA"), u64("amountMaxB"), u8("optionBaseFlag"), bool("baseFlag"), ]) const remainingAccounts = [ ...(exTickArrayBitmap ? [{ pubkey: exTickArrayBitmap, isSigner: false, isWritable: true }] : []), ] const keys = [ { pubkey: payer, isSigner: true, isWritable: true }, { pubkey: userState, isSigner: false, isWritable: false }, { pubkey: positionNftAccount, isSigner: false, isWritable: false }, { pubkey: poolId, isSigner: false, isWritable: true }, { pubkey: protocolPosition, isSigner: false, isWritable: true }, { pubkey: personalPosition, isSigner: false, isWritable: true }, { pubkey: tickArrayLower, isSigner: false, isWritable: true }, { pubkey: tickArrayUpper, isSigner: false, isWritable: true }, { pubkey: tokenCustodyA, isSigner: false, isWritable: true }, { pubkey: tokenCustodyB, isSigner: false, isWritable: true }, { pubkey: tokenVaultA, isSigner: false, isWritable: true }, { pubkey: tokenVaultB, isSigner: false, isWritable: true }, { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: TOKEN_2022_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: tokenMintA, isSigner: false, isWritable: false }, { pubkey: tokenMintB, isSigner: false, isWritable: false }, { pubkey: remoteProgramId, isSigner: false, isWritable: false }, ...remainingAccounts, ] const data = Buffer.alloc(dataLayout.span); dataLayout.encode( { liquidity, amountMaxA, amountMaxB, optionBaseFlag: 0, baseFlag: false, }, data, ); const aData = Buffer.from([...anchorDataBuf.increaseLiquidity, ...data]); return new TransactionInstruction({ keys, programId: custodyProgramId, data: aData, }) } static increasePositionFromLiquidityInstructions({ custodyProgramId, poolInfo, poolKeys, ownerPosition, ownerInfo, liquidity, amountMaxA, amountMaxB, }: { custodyProgramId: PublicKey, poolInfo: ApiV3PoolInfoConcentratedItem, poolKeys: ClmmKeys, ownerPosition: ClmmPositionLayout; ownerInfo: { wallet: PublicKey; feePayer: PublicKey; }; liquidity: BN; amountMaxA: BN; amountMaxB: BN; }): ReturnTypeMakeInstructions<ManipulateLiquidityExtInfo["address"]> { const [programId, id] = [new PublicKey(poolInfo.programId), new PublicKey(poolInfo.id)]; const tickArrayLowerStartIndex = TickUtils.getTickArrayStartIndexByTick( ownerPosition.tickLower, poolInfo.config.tickSpacing, ); const tickArrayUpperStartIndex = TickUtils.getTickArrayStartIndexByTick( ownerPosition.tickUpper, poolInfo.config.tickSpacing, ); const { publicKey: tickArrayLower } = getPdaTickArrayAddress(programId, id, tickArrayLowerStartIndex); const { publicKey: tickArrayUpper } = getPdaTickArrayAddress(programId, id, tickArrayUpperStartIndex); const { publicKey: userState } = getPdaUserState(custodyProgramId, ownerInfo.wallet) const { publicKey: tokenCustodyA } = getATAAddress(userState, new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintA.programId)) const { publicKey: tokenCustodyB } = getATAAddress(userState, new PublicKey(poolInfo.mintB.address), new PublicKey(poolInfo.mintB.programId)) const { publicKey: positionNftAccount } = getATAAddress(userState, ownerPosition.nftMint, TOKEN_2022_PROGRAM_ID) const { publicKey: personalPosition } = getPdaPersonalPositionAddress(programId, ownerPosition.nftMint); const { publicKey: protocolPosition } = getPdaProtocolPositionAddress( programId, id, ownerPosition.tickLower, ownerPosition.tickUpper, ) const ins = this.increasePositionFromLiquidityInstruction( custodyProgramId, programId, ownerInfo.wallet, userState, positionNftAccount, personalPosition, id, protocolPosition, tickArrayLower, tickArrayUpper, tokenCustodyA, tokenCustodyB, new PublicKey(poolKeys.vault.A), new PublicKey(poolKeys.vault.B), new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintB.address), liquidity, amountMaxA, amountMaxB, PoolUtils.isOverflowDefaultTickarrayBitmap(poolInfo.config.tickSpacing, [ tickArrayLowerStartIndex, tickArrayUpperStartIndex, ]) ? getPdaExBitmapAccount(programId, id).publicKey : undefined, ) return { address: { tickArrayLower, tickArrayUpper, positionNftAccount, personalPosition, protocolPosition, }, instructions: [ins], signers: [], instructionTypes: [InstructionType.CustodyIncreasePosition], lookupTableAddress: poolKeys.lookupTableAccount ? [poolKeys.lookupTableAccount] : [], } } static increasePositionFromBaseInstruction( custodyProgramId: PublicKey, remoteProgramId: PublicKey, payer: PublicKey, userState: PublicKey, positionNftAccount: PublicKey, personalPosition: PublicKey, poolId: PublicKey, protocolPosition: PublicKey, tickArrayLower: PublicKey, tickArrayUpper: PublicKey, tokenCustodyA: PublicKey, tokenCustodyB: PublicKey, tokenVaultA: PublicKey, tokenVaultB: PublicKey, tokenMintA: PublicKey, tokenMintB: PublicKey, base: "MintA" | "MintB", baseAmount: BN, otherAmountMax: BN, exTickArrayBitmap?: PublicKey, ): TransactionInstruction { const dataLayout = struct([ u128("liquidity"), u64("amountMaxA"), u64("amountMaxB"), u8("optionBaseFlag"), bool("baseFlag"), ]) const remainingAccounts = [ ...(exTickArrayBitmap ? [{ pubkey: exTickArrayBitmap, isSigner: false, isWritable: true }] : []), ]; const keys = [ { pubkey: payer, isSigner: true, isWritable: true }, { pubkey: userState, isSigner: false, isWritable: false }, { pubkey: positionNftAccount, isSigner: false, isWritable: false }, { pubkey: poolId, isSigner: false, isWritable: true }, { pubkey: protocolPosition, isSigner: false, isWritable: true }, { pubkey: personalPosition, isSigner: false, isWritable: true }, { pubkey: tickArrayLower, isSigner: false, isWritable: true }, { pubkey: tickArrayUpper, isSigner: false, isWritable: true }, { pubkey: tokenCustodyA, isSigner: false, isWritable: true }, { pubkey: tokenCustodyB, isSigner: false, isWritable: true }, { pubkey: tokenVaultA, isSigner: false, isWritable: true }, { pubkey: tokenVaultB, isSigner: false, isWritable: true }, { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: TOKEN_2022_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: tokenMintA, isSigner: false, isWritable: false }, { pubkey: tokenMintB, isSigner: false, isWritable: false }, { pubkey: remoteProgramId, isSigner: false, isWritable: false }, ...remainingAccounts, ]; const data = Buffer.alloc(dataLayout.span) dataLayout.encode( { liquidity: new BN(0), amountMaxA: base === "MintA" ? baseAmount : otherAmountMax, amountMaxB: base === "MintA" ? otherAmountMax : baseAmount, baseFlag: base === "MintA", optionBaseFlag: 1, }, data, ) const aData = Buffer.from([...anchorDataBuf.increaseLiquidity, ...data]) return new TransactionInstruction({ keys, programId: custodyProgramId, data: aData, }) } static increasePositionFromBaseInstructions({ custodyProgramId, poolInfo, poolKeys, ownerPosition, ownerInfo, base, baseAmount, otherAmountMax, }: { custodyProgramId: PublicKey, poolInfo: ApiV3PoolInfoConcentratedItem; poolKeys: ClmmKeys; ownerPosition: ClmmPositionLayout; ownerInfo: { feePayer: PublicKey; wallet: PublicKey; }; base: "MintA" | "MintB"; baseAmount: BN; otherAmountMax: BN; }): ReturnTypeMakeInstructions<ManipulateLiquidityExtInfo["address"]> { const [programId, id] = [new PublicKey(poolInfo.programId), new PublicKey(poolInfo.id)]; const tickArrayLowerStartIndex = TickUtils.getTickArrayStartIndexByTick( ownerPosition.tickLower, poolInfo.config.tickSpacing, ); const tickArrayUpperStartIndex = TickUtils.getTickArrayStartIndexByTick( ownerPosition.tickUpper, poolInfo.config.tickSpacing, ); const { publicKey: tickArrayLower } = getPdaTickArrayAddress(programId, id, tickArrayLowerStartIndex); const { publicKey: tickArrayUpper } = getPdaTickArrayAddress(programId, id, tickArrayUpperStartIndex); const { publicKey: userState } = getPdaUserState(custodyProgramId, ownerInfo.wallet) const { publicKey: tokenCustodyA } = getATAAddress(userState, new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintA.programId)) const { publicKey: tokenCustodyB } = getATAAddress(userState, new PublicKey(poolInfo.mintB.address), new PublicKey(poolInfo.mintB.programId)) const { publicKey: positionNftAccount } = getATAAddress(userState, ownerPosition.nftMint, TOKEN_2022_PROGRAM_ID) const { publicKey: personalPosition } = getPdaPersonalPositionAddress(programId, ownerPosition.nftMint); const { publicKey: protocolPosition } = getPdaProtocolPositionAddress( programId, id, ownerPosition.tickLower, ownerPosition.tickUpper, ) return { address: { tickArrayLower, tickArrayUpper, positionNftAccount, personalPosition, protocolPosition, }, instructions: [ this.increasePositionFromBaseInstruction( custodyProgramId, programId, ownerInfo.feePayer, userState, positionNftAccount, personalPosition, id, protocolPosition, tickArrayLower, tickArrayUpper, tokenCustodyA, tokenCustodyB, new PublicKey(poolKeys.vault.A), new PublicKey(poolKeys.vault.B), new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintB.address), base, baseAmount, otherAmountMax, PoolUtils.isOverflowDefaultTickarrayBitmap(poolInfo.config.tickSpacing, [ tickArrayLowerStartIndex, tickArrayUpperStartIndex, ]) ? getPdaExBitmapAccount(programId, id).publicKey : undefined, ), ], signers: [], instructionTypes: [InstructionType.CustodyIncreasePosition], lookupTableAddress: poolKeys.lookupTableAccount ? [poolKeys.lookupTableAccount] : [], } } static decreaseLiquidityInstruction( custodyProgramId: PublicKey, remoteProgramId: PublicKey, payer: PublicKey, userState: PublicKey, positionNftAccount: PublicKey, personalPosition: PublicKey, poolId: PublicKey, protocolPosition: PublicKey, tickArrayLower: PublicKey, tickArrayUpper: PublicKey, tokenCustodyA: PublicKey, tokenCustodyB: PublicKey, tokenVaultA: PublicKey, tokenVaultB: PublicKey, tokenMintA: PublicKey, tokenMintB: PublicKey, rewardAccounts: { poolRewardVault: PublicKey; ownerRewardVault: PublicKey; rewardMint: PublicKey; }[], liquidity: BN, amountMinA: BN, amountMinB: BN, exTickArrayBitmap?: PublicKey, ): TransactionInstruction { const dataLayout = struct([u128("liquidity"), u64("amountMinA"), u64("amountMinB")]); const remainingAccounts = [ ...(exTickArrayBitmap ? [{ pubkey: exTickArrayBitmap, isSigner: false, isWritable: true }] : []), ...rewardAccounts .map((i) => [ { pubkey: i.poolRewardVault, isSigner: false, isWritable: true }, { pubkey: i.ownerRewardVault, isSigner: false, isWritable: true }, { pubkey: i.rewardMint, isSigner: false, isWritable: false }, ]) .flat(), ]; const keys = [ { pubkey: payer, isSigner: true, isWritable: true }, { pubkey: userState, isSigner: false, isWritable: false }, { pubkey: positionNftAccount, isSigner: false, isWritable: false }, { pubkey: personalPosition, isSigner: false, isWritable: true }, { pubkey: poolId, isSigner: false, isWritable: true }, { pubkey: protocolPosition, isSigner: false, isWritable: true }, { pubkey: tokenVaultA, isSigner: false, isWritable: true }, { pubkey: tokenVaultB, isSigner: false, isWritable: true }, { pubkey: tickArrayLower, isSigner: false, isWritable: true }, { pubkey: tickArrayUpper, isSigner: false, isWritable: true }, { pubkey: tokenCustodyA, isSigner: false, isWritable: true }, { pubkey: tokenCustodyB, isSigner: false, isWritable: true }, { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: TOKEN_2022_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: MEMO_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: tokenMintA, isSigner: false, isWritable: false }, { pubkey: tokenMintB, isSigner: false, isWritable: false }, { pubkey: remoteProgramId, isSigner: false, isWritable: false }, ...remainingAccounts, ]; const data = Buffer.alloc(dataLayout.span); dataLayout.encode( { liquidity, amountMinA, amountMinB, }, data, ); const aData = Buffer.from([...anchorDataBuf.decreaseLiquidity, ...data]); return new TransactionInstruction({ keys, programId: custodyProgramId, data: aData, }); } static decreaseLiquidityInstructions({ custodyProgramId, poolInfo, poolKeys, ownerPosition, ownerInfo, liquidity, amountMinA, amountMinB, }: { custodyProgramId: PublicKey, poolInfo: ApiV3PoolInfoConcentratedItem; poolKeys: ClmmKeys; ownerPosition: ClmmPositionLayout; ownerInfo: { feePayer: PublicKey; wallet: PublicKey; rewardAccounts: PublicKey[]; }; liquidity: BN; amountMinA: BN; amountMinB: BN; }): ReturnTypeMakeInstructions<ManipulateLiquidityExtInfo["address"]> { const [poolProgramId, id] = [new PublicKey(poolInfo.programId), new PublicKey(poolInfo.id)]; const tickArrayLowerStartIndex = TickUtils.getTickArrayStartIndexByTick( ownerPosition.tickLower, poolInfo.config.tickSpacing, ); const tickArrayUpperStartIndex = TickUtils.getTickArrayStartIndexByTick( ownerPosition.tickUpper, poolInfo.config.tickSpacing, ); const { publicKey: tickArrayLower } = getPdaTickArrayAddress(poolProgramId, id, tickArrayLowerStartIndex); const { publicKey: tickArrayUpper } = getPdaTickArrayAddress(poolProgramId, id, tickArrayUpperStartIndex); const { publicKey: userState } = getPdaUserState(custodyProgramId, ownerInfo.wallet) const { publicKey: tokenCustodyA } = getATAAddress(userState, new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintA.programId)) const { publicKey: tokenCustodyB } = getATAAddress(userState, new PublicKey(poolInfo.mintB.address), new PublicKey(poolInfo.mintB.programId)) const { publicKey: positionNftAccount } = getATAAddress(userState, ownerPosition.nftMint, TOKEN_2022_PROGRAM_ID) const { publicKey: personalPosition } = getPdaPersonalPositionAddress(poolProgramId, ownerPosition.nftMint); const { publicKey: protocolPosition } = getPdaProtocolPositionAddress( poolProgramId, id, ownerPosition.tickLower, ownerPosition.tickUpper, ); const rewardAccounts: { poolRewardVault: PublicKey; ownerRewardVault: PublicKey; rewardMint: PublicKey; }[] = []; for (let i = 0; i < poolKeys.rewardInfos.length; i++) { rewardAccounts.push({ poolRewardVault: new PublicKey(poolKeys.rewardInfos[i].vault), ownerRewardVault: ownerInfo.rewardAccounts[i], rewardMint: new PublicKey(poolKeys.rewardInfos[i].mint.address), }) } const ins = this.decreaseLiquidityInstruction( custodyProgramId, poolProgramId, ownerInfo.feePayer, userState, positionNftAccount, personalPosition, id, protocolPosition, tickArrayLower, tickArrayUpper, tokenCustodyA, tokenCustodyB, new PublicKey(poolKeys.vault.A), new PublicKey(poolKeys.vault.B), new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintB.address), rewardAccounts, liquidity, amountMinA, amountMinB, PoolUtils.isOverflowDefaultTickarrayBitmap(poolInfo.config.tickSpacing, [ tickArrayLowerStartIndex, tickArrayUpperStartIndex, ]) ? getPdaExBitmapAccount(poolProgramId, id).publicKey : undefined, ) return { address: { tickArrayLower, tickArrayUpper, positionNftAccount, personalPosition, protocolPosition, }, signers: [], instructions: [ins], instructionTypes: [InstructionType.CustodyDecreasePosition], lookupTableAddress: poolKeys.lookupTableAccount ? [poolKeys.lookupTableAccount] : [], } } static swapInstruction( custodyProgramId: PublicKey, remoteProgramId: PublicKey, payer: PublicKey, owner: PublicKey, poolId: PublicKey, ammConfigId: PublicKey, inputTokenAccount: PublicKey, outputTokenAccount: PublicKey, inputVault: PublicKey, outputVault: PublicKey, inputMint: PublicKey, outputMint: PublicKey, tickArray: PublicKey[], observationId: PublicKey, amount: BN, otherAmountThreshold: BN, sqrtPriceLimitX64: BN, isBaseInput: boolean, exTickArrayBitmap?: PublicKey, ): TransactionInstruction { const dataLayout = struct([ u64("amount"), u64("otherAmountThreshold"), u128("sqrtPriceLimitX64"), bool("isBaseInput"), ]); const remainingAccounts = [ ...(exTickArrayBitmap ? [{ pubkey: exTickArrayBitmap, isSigner: false, isWritable: true }] : []), ...tickArray.map((i) => ({ pubkey: i, isSigner: false, isWritable: true })), ] const { publicKey: userState } = getPdaUserState(custodyProgramId, owner) const keys = [ { pubkey: payer, isSigner: true, isWritable: true }, { pubkey: userState, isSigner: false, isWritable: true }, { pubkey: ammConfigId, isSigner: false, isWritable: false }, { pubkey: poolId, isSigner: false, isWritable: true }, { pubkey: inputTokenAccount, isSigner: false, isWritable: true }, { pubkey: outputTokenAccount, isSigner: false, isWritable: true }, { pubkey: inputVault, isSigner: false, isWritable: true }, { pubkey: outputVault, isSigner: false, isWritable: true }, { pubkey: observationId, isSigner: false, isWritable: true }, { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: TOKEN_2022_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: MEMO_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: inputMint, isSigner: false, isWritable: false }, { pubkey: outputMint, isSigner: false, isWritable: false }, { pubkey: remoteProgramId, isSigner: false, isWritable: false }, ...remainingAccounts, ]; const data = Buffer.alloc(dataLayout.span) dataLayout.encode( { amount, otherAmountThreshold, sqrtPriceLimitX64, isBaseInput, }, data ) const aData = Buffer.from([...anchorDataBuf.swap, ...data]) return new TransactionInstruction({ keys, programId: custodyProgramId, data: aData, }) } static makeSwapBaseInInstructions({ custodyProgramId, poolInfo, poolKeys, observationId, ownerInfo, inputMint, amountIn, amountOutMin, sqrtPriceLimitX64, remainingAccounts, }: { custodyProgramId: PublicKey, poolInfo: Pick<ApiV3PoolInfoConcentratedItem, "id" | "programId" | "mintA" | "mintB" | "config">; poolKeys: ClmmKeys; observationId: PublicKey; ownerInfo: { feePayer: PublicKey; wallet: PublicKey; }; inputMint: PublicKey; amountIn: BN; amountOutMin: BN; sqrtPriceLimitX64: BN; remainingAccounts: PublicKey[]; }): ReturnTypeMakeInstructions { const [programId, id] = [new PublicKey(poolInfo.programId), new PublicKey(poolInfo.id)]; const [mintAVault, mintBVault] = [new PublicKey(poolKeys.vault.A), new PublicKey(poolKeys.vault.B)]; const [mintA, mintB] = [new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintB.address)]; const isInputMintA = poolInfo.mintA.address === inputMint.toString(); const { publicKey: userState } = getPdaUserState(custodyProgramId, ownerInfo.wallet) const { publicKey: tokenCustodyA } = getATAAddress(userState, new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintA.programId)) const { publicKey: tokenCustodyB } = getATAAddress(userState, new PublicKey(poolInfo.mintB.address), new PublicKey(poolInfo.mintB.programId)) const ins = this.swapInstruction( custodyProgramId, programId, ownerInfo.feePayer, ownerInfo.wallet, id, new PublicKey(poolInfo.config.id), isInputMintA ? tokenCustodyA : tokenCustodyB, isInputMintA ? tokenCustodyB : tokenCustodyA, isInputMintA ? mintAVault : mintBVault, isInputMintA ? mintBVault : mintAVault, isInputMintA ? mintA : mintB, isInputMintA ? mintB : mintA, remainingAccounts, observationId, amountIn, amountOutMin, sqrtPriceLimitX64, true, getPdaExBitmapAccount(programId, id).publicKey, ) return { signers: [], instructions: [ins], instructionTypes: [InstructionType.CustodySwapBaseIn], lookupTableAddress: poolKeys.lookupTableAccount ? [poolKeys.lookupTableAccount] : [], address: {}, } } static makeSwapBaseOutInstructions({ custodyProgramId, poolInfo, poolKeys, observationId, ownerInfo, outputMint, amountOut, amountInMax, sqrtPriceLimitX64, remainingAccounts, }: { custodyProgramId: PublicKey, poolInfo: Pick<ApiV3PoolInfoConcentratedItem, "id" | "programId" | "mintA" | "mintB" | "config">; poolKeys: ClmmKeys; observationId: PublicKey; ownerInfo: { feePayer: PublicKey; wallet: PublicKey; }; outputMint: PublicKey; amountOut: BN; amountInMax: BN; sqrtPriceLimitX64: BN; remainingAccounts: PublicKey[]; }): ReturnTypeMakeInstructions { const [programId, id] = [new PublicKey(poolInfo.programId), new PublicKey(poolInfo.id)]; const [mintAVault, mintBVault] = [new PublicKey(poolKeys.vault.A), new PublicKey(poolKeys.vault.B)]; const [mintA, mintB] = [new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintB.address)]; const isInputMintA = poolInfo.mintA.address === outputMint.toBase58(); const { publicKey: userState } = getPdaUserState(custodyProgramId, ownerInfo.wallet) const { publicKey: tokenCustodyA } = getATAAddress(userState, new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintA.programId)) const { publicKey: tokenCustodyB } = getATAAddress(userState, new PublicKey(poolInfo.mintB.address), new PublicKey(poolInfo.mintB.programId)) const ins = this.swapInstruction( custodyProgramId, programId, ownerInfo.feePayer, ownerInfo.wallet, id, new PublicKey(poolInfo.config.id), isInputMintA ? tokenCustodyB : tokenCustodyA, isInputMintA ? tokenCustodyA : tokenCustodyB, isInputMintA ? mintBVault : mintAVault, isInputMintA ? mintAVault : mintBVault, isInputMintA ? mintB : mintA, isInputMintA ? mintA : mintB, remainingAccounts, observationId, amountOut, amountInMax, sqrtPriceLimitX64, false, getPdaExBitmapAccount(programId, id).publicKey, ) return { signers: [], instructions: [ins], instructionTypes: [InstructionType.CustodySwapBaseOut], lookupTableAddress: poolKeys.lookupTableAccount ? [poolKeys.lookupTableAccount] : [], address: {}, } } }