UNPKG

@raydium-io/raydium-sdk-v2

Version:

An SDK for building applications on top of Raydium.

1,461 lines (1,317 loc) 81.3 kB
import { ApiV3PoolInfoConcentratedItem, ApiV3Token, ClmmKeys } from "@/api/type"; import { InstructionType, MEMO_PROGRAM_ID, METADATA_PROGRAM_ID, RENT_PROGRAM_ID, getATAAddress } from "@/common"; import { createLogger } from "@/common/logger"; import { bool, s32, struct, u128, u64, u8 } from "@/marshmallow"; import { ReturnTypeMakeInstructions } from "@/raydium/type"; import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, TOKEN_PROGRAM_ID } from "@solana/spl-token"; import { Connection, Keypair, PublicKey, Signer, SystemProgram, TransactionInstruction } from "@solana/web3.js"; import BN from "bn.js"; import { ObservationLayout, PersonalPositionLayout } from "./layout"; import { getPdaExBitmapAccount, getPdaLockClPositionIdV2, getPdaLockPositionId, getPdaMetadataKey, getPdaObservationAccount, getPdaOperationAccount, getPdaPersonalPositionAddress, getPdaPoolId, getPdaPoolRewardVaultId, getPdaPoolVaultId, getPdaProtocolPositionAddress, getPdaTickArrayAddress, } from "./libraries/pda"; import { ClmmLockAddress, ClmmPoolPersonalPosition, ClosePositionExtInfo, InitRewardExtInfo, ManipulateLiquidityExtInfo, OpenPositionFromBaseExtInfo, OpenPositionFromLiquidityExtInfo, SimpleClmmPoolInfo, } from "./type"; import { sha256 } from "js-sha256"; import { PoolUtil } from "./libraries"; import { BN_ZERO } from "./libraries/constants"; import { TickArrayUtil } from "./libraries/tickArrayUtil"; function getAnchorByte(ixName: string): Buffer { const preimage = `global:${ixName}`; return Buffer.from(sha256.digest(preimage)).slice(0, 8); } ObservationLayout.span; // do not delete this line const logger = createLogger("Raydium_Clmm"); const insId = { createPool: getAnchorByte("create_pool"), createCustomizablePool: getAnchorByte("create_customizable_pool"), // todo openPositionV2: getAnchorByte("open_position_v2"), openPositionWithToken22Nft: getAnchorByte("open_position_with_token22_nft"), closePosition: getAnchorByte("close_position"), increaseLiquidityV2: getAnchorByte("increase_liquidity_v2"), decreaseLiquidityV2: getAnchorByte("decrease_liquidity_v2"), initializeReward: getAnchorByte("initialize_reward"), setRewardParams: getAnchorByte("set_reward_params"), updateRewardInfos: getAnchorByte("update_reward_infos"), collectRemainingRewards: getAnchorByte("collect_remaining_rewards"), swapV2: getAnchorByte("swap_v2"), openLimitOrder: getAnchorByte("open_limit_order"), // todo increaseLimitOrder: getAnchorByte("increase_limit_order"), // todo decreaseLimitOrder: getAnchorByte("decrease_limit_order"), // todo settleLimitOrder: getAnchorByte("settle_limit_order"), // todo closeLimitOrder: getAnchorByte("close_limit_order"), // todo }; const lockInsDataBuf = [188, 37, 179, 131, 82, 150, 84, 73]; const lockHarvestInsDataBuf = [16, 72, 250, 198, 14, 162, 212, 19]; interface CreatePoolInstruction { connection: Connection; programId: PublicKey; owner: PublicKey; mintA: ApiV3Token; mintB: ApiV3Token; ammConfigId: PublicKey; initialPriceX64: BN; forerunCreate?: boolean; extendMintAccount?: PublicKey[]; } export class ClmmInstrument { static createPoolInstruction( programId: PublicKey, poolId: PublicKey, poolCreator: PublicKey, ammConfigId: PublicKey, observationId: PublicKey, mintA: PublicKey, vaultA: PublicKey, mintProgramIdA: PublicKey, mintB: PublicKey, vaultB: PublicKey, mintProgramIdB: PublicKey, tickArrayBitmap: PublicKey, sqrtPriceX64: BN, supperMintEx: PublicKey[] | undefined, ): TransactionInstruction { const dataLayout = struct([u128("sqrtPriceX64"), u64("startTime")]); const keys = [ { pubkey: poolCreator, isSigner: true, isWritable: true }, { pubkey: ammConfigId, isSigner: false, isWritable: false }, { pubkey: poolId, isSigner: false, isWritable: true }, { pubkey: mintA, isSigner: false, isWritable: false }, { pubkey: mintB, isSigner: false, isWritable: false }, { pubkey: vaultA, isSigner: false, isWritable: true }, { pubkey: vaultB, isSigner: false, isWritable: true }, { pubkey: observationId, isSigner: false, isWritable: true }, { pubkey: tickArrayBitmap, isSigner: false, isWritable: true }, { pubkey: mintProgramIdA, isSigner: false, isWritable: false }, { pubkey: mintProgramIdB, isSigner: false, isWritable: false }, { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, { pubkey: RENT_PROGRAM_ID, isSigner: false, isWritable: false }, ...(supperMintEx ?? []).map((i) => ({ pubkey: i, isSigner: false, isWritable: false })), ]; const data = Buffer.alloc(dataLayout.span); dataLayout.encode({ sqrtPriceX64, startTime: BN_ZERO }, data); const aData = Buffer.from([...insId.createPool, ...data]); return new TransactionInstruction({ keys, programId, data: aData, }); } static createCustomizablePoolInstruction( programId: PublicKey, poolId: PublicKey, poolCreator: PublicKey, ammConfig: PublicKey, mintA: PublicKey, mintB: PublicKey, vaultA: PublicKey, vaultB: PublicKey, observationId: PublicKey, tickArrayBitmap: PublicKey, mintProgramIdA: PublicKey, mintProgramIdB: PublicKey, sqrtPriceX64: BN, collectFeeOn: number, // new supperMintEx: PublicKey[], dynamicFeeConfig?: PublicKey, // new ): TransactionInstruction { const dataLayout = struct([u128("sqrtPriceX64"), u8("collectFeeOn"), bool("enableDynamicFee")]); const keys = [ { pubkey: poolCreator, isSigner: true, isWritable: true }, { pubkey: ammConfig, isSigner: false, isWritable: false }, { pubkey: poolId, isSigner: false, isWritable: true }, { pubkey: mintA, isSigner: false, isWritable: false }, { pubkey: mintB, isSigner: false, isWritable: false }, { pubkey: vaultA, isSigner: false, isWritable: true }, { pubkey: vaultB, isSigner: false, isWritable: true }, { pubkey: observationId, isSigner: false, isWritable: true }, { pubkey: tickArrayBitmap, isSigner: false, isWritable: true }, { pubkey: mintProgramIdA, isSigner: false, isWritable: false }, { pubkey: mintProgramIdB, isSigner: false, isWritable: false }, { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, { pubkey: RENT_PROGRAM_ID, isSigner: false, isWritable: false }, ...supperMintEx.map((i) => ({ pubkey: i, isSigner: false, isWritable: false })), ...(dynamicFeeConfig ? [{ pubkey: dynamicFeeConfig, isSigner: false, isWritable: false }] : []), ]; const data = Buffer.alloc(dataLayout.span); dataLayout.encode({ sqrtPriceX64, collectFeeOn, enableDynamicFee: dynamicFeeConfig !== undefined }, data); const aData = Buffer.from([...insId.createCustomizablePool, ...data]); return new TransactionInstruction({ keys, programId, data: aData, }); } static initializeRewardInstruction( programId: PublicKey, rewardFunder: PublicKey, poolId: PublicKey, operationId: PublicKey, ammConfigId: PublicKey, funderTokenAccount: PublicKey, tokenProgramId: PublicKey, rewardTokenMint: PublicKey, rewardTokenVault: PublicKey, openTime: BN, endTime: BN, emissionsPerSecondX64: BN, ): TransactionInstruction { const dataLayout = struct([u64("openTime"), u64("endTime"), u128("emissionsPerSecondX64")]); const keys = [ { pubkey: rewardFunder, isSigner: true, isWritable: true }, { pubkey: funderTokenAccount, isSigner: false, isWritable: true }, { pubkey: ammConfigId, isSigner: false, isWritable: false }, { pubkey: poolId, isSigner: false, isWritable: true }, { pubkey: operationId, isSigner: false, isWritable: false }, { pubkey: rewardTokenMint, isSigner: false, isWritable: false }, { pubkey: rewardTokenVault, isSigner: false, isWritable: true }, { pubkey: tokenProgramId, isSigner: false, isWritable: false }, { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, { pubkey: RENT_PROGRAM_ID, isSigner: false, isWritable: false }, ]; const data = Buffer.alloc(dataLayout.span); dataLayout.encode({ openTime, endTime, emissionsPerSecondX64 }, data); const aData = Buffer.from([...insId.initializeReward, ...data]); return new TransactionInstruction({ keys, programId, data: aData, }); } static updateRewardInfosInstruction(programId: PublicKey, poolId: PublicKey): TransactionInstruction { const keys = [{ pubkey: poolId, isSigner: false, isWritable: true }]; const aData = Buffer.from([...insId.updateRewardInfos]); return new TransactionInstruction({ keys, programId, data: aData, }); } static setRewardParamsInstruction( programId: PublicKey, authority: PublicKey, poolId: PublicKey, operationId: PublicKey, ammConfigId: PublicKey, ownerTokenAccount: PublicKey, rewardVault: PublicKey, rewardMint: PublicKey, rewardIndex: number, openTime: BN, endTime: BN, emissionsPerSecondX64: BN, ): TransactionInstruction { const dataLayout = struct([u8("rewardIndex"), u128("emissionsPerSecondX64"), u64("openTime"), u64("endTime")]); const keys = [ { pubkey: authority, isSigner: true, isWritable: false }, { pubkey: ammConfigId, isSigner: false, isWritable: false }, { pubkey: poolId, isSigner: false, isWritable: true }, { pubkey: operationId, isSigner: false, isWritable: false }, { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: TOKEN_2022_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: rewardVault, isSigner: false, isWritable: true }, { pubkey: ownerTokenAccount, isSigner: false, isWritable: true }, { pubkey: rewardMint, isSigner: false, isWritable: true }, ]; const data = Buffer.alloc(dataLayout.span); dataLayout.encode({ rewardIndex, emissionsPerSecondX64, openTime, endTime }, data); const aData = Buffer.from([...insId.setRewardParams, ...data]); return new TransactionInstruction({ keys, programId, data: aData, }); } static closePositionInstruction( programId: PublicKey, nftOwner: PublicKey, positionNftMint: PublicKey, positionNftAccount: PublicKey, personalPosition: PublicKey, nft2022?: boolean, ): TransactionInstruction { const keys = [ { pubkey: nftOwner, isSigner: true, 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: nft2022 ? TOKEN_2022_PROGRAM_ID : TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, ]; const aData = Buffer.from([...insId.closePosition]); return new TransactionInstruction({ keys, programId, data: aData, }); } static openPositionV2Instruction( programId: PublicKey, payer: PublicKey, poolId: PublicKey, positionNftOwner: PublicKey, positionNftMint: PublicKey, positionNftAccount: PublicKey, metadataAccount: PublicKey, protocolPosition: PublicKey, tickArrayLower: PublicKey, tickArrayUpper: PublicKey, personalPosition: PublicKey, ownerVaultA: PublicKey, ownerVaultB: PublicKey, vaultA: PublicKey, vaultB: PublicKey, mintA: PublicKey, mintB: PublicKey, tickLower: number, tickUpper: number, tickArrayLowerStart: number, tickArrayUpperStart: number, liquidity: BN, amountMaxA: BN, amountMaxB: BN, withMetadata: boolean, baseFlag: boolean | null, exTickArrayBitmap?: PublicKey, ): TransactionInstruction { const dataLayout = struct([ s32("tickLower"), s32("tickUpper"), s32("tickArrayLowerStart"), s32("tickArrayUpperStart"), u128("liquidity"), u64("amountMaxA"), u64("amountMaxB"), bool("withMetadata"), u8("optionBaseFlag"), bool("baseFlag"), ]); const keys = [ { pubkey: payer, isSigner: true, isWritable: true }, { pubkey: positionNftOwner, isSigner: false, isWritable: false }, { pubkey: positionNftMint, isSigner: true, isWritable: true }, { pubkey: positionNftAccount, isSigner: false, isWritable: true }, { pubkey: metadataAccount, isSigner: false, isWritable: true }, { pubkey: poolId, isSigner: false, isWritable: true }, { pubkey: protocolPosition, isSigner: false, isWritable: false }, { pubkey: tickArrayLower, isSigner: false, isWritable: true }, { pubkey: tickArrayUpper, isSigner: false, isWritable: true }, { pubkey: personalPosition, isSigner: false, isWritable: true }, { pubkey: ownerVaultA, isSigner: false, isWritable: true }, { pubkey: ownerVaultB, isSigner: false, isWritable: true }, { pubkey: vaultA, isSigner: false, isWritable: true }, { pubkey: vaultB, 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: METADATA_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: TOKEN_2022_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: mintA, isSigner: false, isWritable: false }, { pubkey: mintB, isSigner: false, isWritable: false }, ...(exTickArrayBitmap ? [{ pubkey: exTickArrayBitmap, isSigner: false, isWritable: true }] : []), ]; const data = Buffer.alloc(dataLayout.span); dataLayout.encode( { tickLower, tickUpper, tickArrayLowerStart, tickArrayUpperStart, liquidity, amountMaxA, amountMaxB, withMetadata, optionBaseFlag: baseFlag !== null ? 1 : 0, baseFlag: baseFlag ?? false, }, data, ); const aData = Buffer.from([...insId.openPositionV2, ...data]); return new TransactionInstruction({ keys, programId, data: aData, }); } static increaseLiquidityV2Instruction( programId: PublicKey, nftOwner: PublicKey, nftAccount: PublicKey, personalPosition: PublicKey, poolId: PublicKey, protocolPosition: PublicKey, tickArrayLower: PublicKey, tickArrayUpper: PublicKey, ownerVaultA: PublicKey, ownerVaultB: PublicKey, vaultA: PublicKey, vaultB: PublicKey, mintA: PublicKey, mintB: PublicKey, liquidity: BN, amountMaxA: BN, amountMaxB: BN, baseFlag: boolean | null, exTickArrayBitmap?: PublicKey, ): TransactionInstruction { const dataLayout = struct([ u128("liquidity"), u64("amountMaxA"), u64("amountMaxB"), u8("optionBaseFlag"), bool("baseFlag"), ]); const keys = [ { pubkey: nftOwner, isSigner: true, isWritable: false }, { pubkey: nftAccount, isSigner: false, isWritable: false }, { pubkey: poolId, isSigner: false, isWritable: true }, { pubkey: protocolPosition, isSigner: false, isWritable: false }, { pubkey: personalPosition, isSigner: false, isWritable: true }, { pubkey: tickArrayLower, isSigner: false, isWritable: true }, { pubkey: tickArrayUpper, isSigner: false, isWritable: true }, { pubkey: ownerVaultA, isSigner: false, isWritable: true }, { pubkey: ownerVaultB, isSigner: false, isWritable: true }, { pubkey: vaultA, isSigner: false, isWritable: true }, { pubkey: vaultB, isSigner: false, isWritable: true }, { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: TOKEN_2022_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: mintA, isSigner: false, isWritable: false }, { pubkey: mintB, isSigner: false, isWritable: false }, ...(exTickArrayBitmap ? [{ pubkey: exTickArrayBitmap, isSigner: false, isWritable: true }] : []), ]; const data = Buffer.alloc(dataLayout.span); dataLayout.encode( { liquidity, amountMaxA, amountMaxB, optionBaseFlag: baseFlag !== null ? 1 : 0, baseFlag: baseFlag ?? false, }, data, ); const aData = Buffer.from([...insId.increaseLiquidityV2, ...data]); return new TransactionInstruction({ keys, programId, data: aData, }); } static decreaseLiquidityV2Instruction( programId: PublicKey, nftOwner: PublicKey, nftAccount: PublicKey, personalPosition: PublicKey, poolId: PublicKey, protocolPosition: PublicKey, tickArrayLower: PublicKey, tickArrayUpper: PublicKey, ownerVaultA: PublicKey, ownerVaultB: PublicKey, vaultA: PublicKey, vaultB: PublicKey, mintA: PublicKey, mintB: 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 keys = [ { pubkey: nftOwner, isSigner: true, isWritable: false }, { pubkey: nftAccount, isSigner: false, isWritable: false }, { pubkey: personalPosition, isSigner: false, isWritable: true }, { pubkey: poolId, isSigner: false, isWritable: true }, { pubkey: protocolPosition, isSigner: false, isWritable: false }, { pubkey: vaultA, isSigner: false, isWritable: true }, { pubkey: vaultB, isSigner: false, isWritable: true }, { pubkey: tickArrayLower, isSigner: false, isWritable: true }, { pubkey: tickArrayUpper, isSigner: false, isWritable: true }, { pubkey: ownerVaultA, isSigner: false, isWritable: true }, { pubkey: ownerVaultB, 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: mintA, isSigner: false, isWritable: false }, { pubkey: mintB, isSigner: false, isWritable: false }, ...(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 data = Buffer.alloc(dataLayout.span); dataLayout.encode({ liquidity, amountMinA, amountMinB }, data); const aData = Buffer.from([...insId.decreaseLiquidityV2, ...data]); return new TransactionInstruction({ keys, programId, data: aData, }); } static swapV2Instruction( programId: PublicKey, payer: PublicKey, poolId: PublicKey, ammConfig: PublicKey, inputTokenAccount: PublicKey, outputTokenAccount: PublicKey, inputVault: PublicKey, outputVault: PublicKey, inputTokenMint: PublicKey, outputTokenMint: PublicKey, tickArray: PublicKey[], observationId: PublicKey, amount: BN, otherAmountThreshold: BN, sqrtPriceLimitX64: BN, isBaseInput: boolean, tickArrayBitmapExtension?: PublicKey, ): TransactionInstruction { const dataLayout = struct([ u64("amount"), u64("otherAmountThreshold"), u128("sqrtPriceLimitX64"), bool("isBaseInput"), ]); const keys = [ { pubkey: payer, isSigner: true, isWritable: false }, { pubkey: ammConfig, 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: inputTokenMint, isSigner: false, isWritable: false }, { pubkey: outputTokenMint, isSigner: false, isWritable: false }, ...(tickArrayBitmapExtension ? [{ pubkey: tickArrayBitmapExtension, isSigner: false, isWritable: true }] : []), ...tickArray.map((i) => ({ pubkey: i, isSigner: false, isWritable: true })), ]; const data = Buffer.alloc(dataLayout.span); dataLayout.encode({ amount, otherAmountThreshold, sqrtPriceLimitX64, isBaseInput }, data); const aData = Buffer.from([...insId.swapV2, ...data]); return new TransactionInstruction({ keys, programId, data: aData, }); } static collectRemainingRewardsInstruction( programId: PublicKey, rewardFunder: PublicKey, poolId: PublicKey, funderTokenAccount: PublicKey, rewardTokenVault: PublicKey, rewardMint: PublicKey, rewardIndex: number, ): TransactionInstruction { const dataLayout = struct([u8("rewardIndex")]); const keys = [ { pubkey: rewardFunder, isSigner: true, isWritable: false }, { pubkey: funderTokenAccount, isSigner: false, isWritable: true }, { pubkey: poolId, isSigner: false, isWritable: true }, { pubkey: rewardTokenVault, isSigner: false, isWritable: true }, { pubkey: rewardMint, isSigner: false, isWritable: false }, { 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 }, ]; const data = Buffer.alloc(dataLayout.span); dataLayout.encode({ rewardIndex }, data); const aData = Buffer.from([...insId.collectRemainingRewards, ...data]); return new TransactionInstruction({ keys, programId, data: aData, }); } static openPositionWithToken22NftInstruction( programId: PublicKey, payer: PublicKey, poolId: PublicKey, positionNftOwner: PublicKey, positionNftMint: PublicKey, positionNftAccount: PublicKey, protocolPosition: PublicKey, tickArrayLower: PublicKey, tickArrayUpper: PublicKey, personalPosition: PublicKey, ownerVaultA: PublicKey, ownerVaultB: PublicKey, vaultA: PublicKey, vaultB: PublicKey, mintA: PublicKey, mintB: PublicKey, tickLower: number, tickUpper: number, tickArrayLowerStart: number, tickArrayUpperStart: number, liquidity: BN, amountMaxA: BN, amountMaxB: BN, withMetadata: boolean, baseFlag: boolean | null, exTickArrayBitmap?: PublicKey, ): TransactionInstruction { const dataLayout = struct([ s32("tickLower"), s32("tickUpper"), s32("tickArrayLowerStart"), s32("tickArrayUpperStart"), u128("liquidity"), u64("amountMaxA"), u64("amountMaxB"), bool("withMetadata"), u8("optionBaseFlag"), bool("baseFlag"), ]); const keys = [ { pubkey: payer, isSigner: true, isWritable: true }, { pubkey: positionNftOwner, isSigner: false, isWritable: false }, { pubkey: positionNftMint, isSigner: true, isWritable: true }, { pubkey: positionNftAccount, isSigner: false, isWritable: true }, { pubkey: poolId, isSigner: false, isWritable: true }, { pubkey: protocolPosition, isSigner: false, isWritable: false }, { pubkey: tickArrayLower, isSigner: false, isWritable: true }, { pubkey: tickArrayUpper, isSigner: false, isWritable: true }, { pubkey: personalPosition, isSigner: false, isWritable: true }, { pubkey: ownerVaultA, isSigner: false, isWritable: true }, { pubkey: ownerVaultB, isSigner: false, isWritable: true }, { pubkey: vaultA, isSigner: false, isWritable: true }, { pubkey: vaultB, 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: mintA, isSigner: false, isWritable: false }, { pubkey: mintB, isSigner: false, isWritable: false }, ...(exTickArrayBitmap ? [{ pubkey: exTickArrayBitmap, isSigner: false, isWritable: true }] : []), ]; const data = Buffer.alloc(dataLayout.span); dataLayout.encode( { tickLower, tickUpper, tickArrayLowerStart, tickArrayUpperStart, liquidity, amountMaxA, amountMaxB, withMetadata, optionBaseFlag: baseFlag !== null ? 1 : 0, baseFlag: baseFlag ?? false, }, data, ); const aData = Buffer.from([...insId.openPositionWithToken22Nft, ...data]); return new TransactionInstruction({ keys, programId, data: aData, }); } static openLimitOrderInstruction( programId: PublicKey, payer: PublicKey, poolId: PublicKey, tickArray: PublicKey, limitOrderNonce: PublicKey, limitOrder: PublicKey, inputTokenAccount: PublicKey, inputVault: PublicKey, inputVaultMint: PublicKey, inputTokenProgram: PublicKey, nonceIndex: number, zeroForOne: boolean, tickIndex: number, amount: BN, tickArrayBitmap?: PublicKey, ): TransactionInstruction { const dataLayout = struct([u8("nonceIndex"), bool("zeroForOne"), s32("tickIndex"), u64("amount")]); const keys = [ { pubkey: payer, isSigner: true, isWritable: true }, { pubkey: poolId, isSigner: false, isWritable: true }, { pubkey: tickArray, isSigner: false, isWritable: true }, { pubkey: limitOrderNonce, isSigner: false, isWritable: true }, { pubkey: limitOrder, isSigner: false, isWritable: true }, { pubkey: inputTokenAccount, isSigner: false, isWritable: true }, { pubkey: inputVault, isSigner: false, isWritable: true }, { pubkey: inputVaultMint, isSigner: false, isWritable: false }, { pubkey: inputTokenProgram, isSigner: false, isWritable: false }, { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, ...(tickArrayBitmap ? [{ pubkey: tickArrayBitmap, isSigner: false, isWritable: true }] : []), ]; const data = Buffer.alloc(dataLayout.span); dataLayout.encode({ nonceIndex, zeroForOne, tickIndex, amount }, data); const aData = Buffer.from([...insId.openLimitOrder, ...data]); return new TransactionInstruction({ keys, programId, data: aData, }); } static increaseLimitOrderInstruction( programId: PublicKey, owner: PublicKey, poolId: PublicKey, tickArray: PublicKey, limitOrder: PublicKey, inputTokenAccount: PublicKey, inputVault: PublicKey, inputVaultMint: PublicKey, inputTokenProgram: PublicKey, amount: BN, ): TransactionInstruction { const dataLayout = struct([u64("amount")]); const keys = [ { pubkey: owner, isSigner: true, isWritable: false }, { pubkey: poolId, isSigner: false, isWritable: true }, { pubkey: tickArray, isSigner: false, isWritable: true }, { pubkey: limitOrder, isSigner: false, isWritable: true }, { pubkey: inputTokenAccount, isSigner: false, isWritable: true }, { pubkey: inputVault, isSigner: false, isWritable: true }, { pubkey: inputVaultMint, isSigner: false, isWritable: false }, { pubkey: inputTokenProgram, isSigner: false, isWritable: false }, ]; const data = Buffer.alloc(dataLayout.span); dataLayout.encode({ amount }, data); const aData = Buffer.from([...insId.increaseLimitOrder, ...data]); return new TransactionInstruction({ keys, programId, data: aData, }); } static decreaseLimitOrderInstruction( programId: PublicKey, owner: PublicKey, poolId: PublicKey, tickArray: PublicKey, limitOrder: PublicKey, inputTokenAccount: PublicKey, outputTokenAccount: PublicKey, inputVault: PublicKey, outputVault: PublicKey, inputVaultMint: PublicKey, outputVaultMint: PublicKey, amount: BN, amountMin: BN, tickArrayBitmap?: PublicKey, ): TransactionInstruction { const dataLayout = struct([u64("amount"), u64("amountMin")]); const keys = [ { pubkey: owner, isSigner: true, isWritable: false }, { pubkey: poolId, isSigner: false, isWritable: true }, { pubkey: tickArray, isSigner: false, isWritable: true }, { pubkey: limitOrder, 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: inputVaultMint, isSigner: false, isWritable: false }, { pubkey: outputVaultMint, isSigner: false, isWritable: false }, { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: TOKEN_2022_PROGRAM_ID, isSigner: false, isWritable: false }, ...(tickArrayBitmap ? [{ pubkey: tickArrayBitmap, isSigner: false, isWritable: true }] : []), ]; const data = Buffer.alloc(dataLayout.span); dataLayout.encode({ amount, amountMin }, data); const aData = Buffer.from([...insId.decreaseLimitOrder, ...data]); return new TransactionInstruction({ keys, programId, data: aData, }); } static settleLimitOrderInstruction( programId: PublicKey, signer: PublicKey, poolId: PublicKey, tickArray: PublicKey, limitOrder: PublicKey, outputTokenAccount: PublicKey, outputVault: PublicKey, outputVaultMint: PublicKey, outputTokenProgram: PublicKey, ): TransactionInstruction { const keys = [ { pubkey: signer, isSigner: true, isWritable: false }, { pubkey: poolId, isSigner: false, isWritable: false }, { pubkey: tickArray, isSigner: false, isWritable: true }, { pubkey: limitOrder, isSigner: false, isWritable: true }, { pubkey: outputTokenAccount, isSigner: false, isWritable: true }, { pubkey: outputVault, isSigner: false, isWritable: true }, { pubkey: outputVaultMint, isSigner: false, isWritable: false }, { pubkey: outputTokenProgram, isSigner: false, isWritable: false }, ]; const aData = Buffer.from([...insId.settleLimitOrder]); return new TransactionInstruction({ keys, programId, data: aData, }); } static closeLimitOrderInstruction( programId: PublicKey, signer: PublicKey, rentReceiver: PublicKey, limitOrder: PublicKey, ): TransactionInstruction { const keys = [ { pubkey: signer, isSigner: true, isWritable: false }, { pubkey: rentReceiver, isSigner: false, isWritable: true }, { pubkey: limitOrder, isSigner: false, isWritable: true }, ]; const aData = Buffer.from([...insId.closeLimitOrder]); return new TransactionInstruction({ keys, programId, data: aData, }); } static createPoolInstructions(props: CreatePoolInstruction): ReturnTypeMakeInstructions<{ poolId: PublicKey; observationId: PublicKey; exBitmapAccount: PublicKey; mintA: PublicKey; mintB: PublicKey; mintAProgram: PublicKey; mintBProgram: PublicKey; mintAVault: PublicKey; mintBVault: PublicKey; }> { const { programId, owner, mintA, mintB, ammConfigId, initialPriceX64, extendMintAccount } = props; const [mintAAddress, mintBAddress] = [new PublicKey(mintA.address), new PublicKey(mintB.address)]; const [mintAProgram, mintBProgram] = [ new PublicKey(mintA.programId || TOKEN_PROGRAM_ID), new PublicKey(mintB.programId || TOKEN_PROGRAM_ID), ]; const { publicKey: poolId } = getPdaPoolId(programId, ammConfigId, mintAAddress, mintBAddress); const { publicKey: observationId } = getPdaObservationAccount(programId, poolId); const { publicKey: mintAVault } = getPdaPoolVaultId(programId, poolId, mintAAddress); const { publicKey: mintBVault } = getPdaPoolVaultId(programId, poolId, mintBAddress); const exBitmapAccount = getPdaExBitmapAccount(programId, poolId).publicKey; const ins = [ this.createPoolInstruction( programId, poolId, owner, ammConfigId, observationId, mintAAddress, mintAVault, mintAProgram, mintBAddress, mintBVault, mintBProgram, exBitmapAccount, initialPriceX64, extendMintAccount, ), ]; return { signers: [], instructions: ins, instructionTypes: [InstructionType.CreateAccount, InstructionType.ClmmCreatePool], address: { poolId, observationId, exBitmapAccount, mintA: mintAAddress, mintB: mintBAddress, mintAProgram, mintBProgram, mintAVault, mintBVault, }, lookupTableAddress: [], }; } static async openPositionInstructions({ poolInfo, poolKeys, ownerInfo, tickLower, tickUpper, liquidity, amountMaxA, amountMaxB, base, withMetadata, getEphemeralSigners, nft2022, }: { poolInfo: ApiV3PoolInfoConcentratedItem; poolKeys: ClmmKeys; ownerInfo: { feePayer: PublicKey; wallet: PublicKey; tokenAccountA: PublicKey; tokenAccountB: PublicKey; }; tickLower: number; tickUpper: number; liquidity: BN; amountMaxA: BN; amountMaxB: BN; base: "MintA" | "MintB" | null; withMetadata: "create" | "no-create"; getEphemeralSigners?: (k: number) => any; nft2022?: boolean; }): 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 = TickArrayUtil.getTickArrayStartIndex(tickLower, poolInfo.config.tickSpacing); const tickArrayUpperStartIndex = TickArrayUtil.getTickArrayStartIndex(tickUpper, poolInfo.config.tickSpacing); const { publicKey: tickArrayLower } = getPdaTickArrayAddress(programId, id, tickArrayLowerStartIndex); const { publicKey: tickArrayUpper } = getPdaTickArrayAddress(programId, id, tickArrayUpperStartIndex); const { publicKey: positionNftAccount } = nft2022 ? getATAAddress(ownerInfo.wallet, nftMintAccount, TOKEN_2022_PROGRAM_ID) : getATAAddress(ownerInfo.wallet, nftMintAccount, TOKEN_PROGRAM_ID); const { publicKey: metadataAccount } = getPdaMetadataKey(nftMintAccount); const { publicKey: personalPosition } = getPdaPersonalPositionAddress(programId, nftMintAccount); const { publicKey: protocolPosition } = getPdaProtocolPositionAddress(programId, id, tickLower, tickUpper); const ins = nft2022 ? this.openPositionWithToken22NftInstruction( programId, ownerInfo.feePayer, id, ownerInfo.wallet, nftMintAccount, positionNftAccount, protocolPosition, tickArrayLower, tickArrayUpper, personalPosition, ownerInfo.tokenAccountA, ownerInfo.tokenAccountB, 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 === "create", base ? base === "MintA" : base, PoolUtil.isOverflowDefaultTickarrayBitmap({ tickSpacing: poolInfo.config.tickSpacing, tickIndexs: [tickArrayLowerStartIndex, tickArrayUpperStartIndex], }) ? getPdaExBitmapAccount(programId, id).publicKey : undefined, ) : this.openPositionV2Instruction( programId, ownerInfo.feePayer, id, ownerInfo.wallet, nftMintAccount, positionNftAccount, metadataAccount, protocolPosition, tickArrayLower, tickArrayUpper, personalPosition, ownerInfo.tokenAccountA, ownerInfo.tokenAccountB, 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 === "create", null, PoolUtil.isOverflowDefaultTickarrayBitmap({ tickSpacing: poolInfo.config.tickSpacing, tickIndexs: [tickArrayLowerStartIndex, tickArrayUpperStartIndex], }) ? getPdaExBitmapAccount(programId, id).publicKey : undefined, ); return { signers, instructions: [ins], instructionTypes: [InstructionType.ClmmOpenPosition], lookupTableAddress: poolKeys.lookupTableAccount ? [poolKeys.lookupTableAccount] : [], address: { nftMint: nftMintAccount, tickArrayLower, tickArrayUpper, positionNftAccount, metadataAccount, personalPosition, protocolPosition, }, }; } static async openPositionFromBaseInstructions({ poolInfo, poolKeys, ownerInfo, tickLower, tickUpper, base, baseAmount, otherAmountMax, liquidity, withMetadata, getEphemeralSigners, nft2022, }: { poolInfo: SimpleClmmPoolInfo; poolKeys: { vault: { A: string | PublicKey; B: string | PublicKey; }; lookupTableAccount?: string; }; ownerInfo: { feePayer: PublicKey; wallet: PublicKey; tokenAccountA: PublicKey; tokenAccountB: PublicKey; }; tickLower: number; tickUpper: number; base: "MintA" | "MintB" | null; baseAmount: BN; otherAmountMax: BN; liquidity: BN; withMetadata: "create" | "no-create"; getEphemeralSigners?: (k: number) => any; nft2022?: boolean; }): Promise<ReturnTypeMakeInstructions<OpenPositionFromBaseExtInfo>> { 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 = TickArrayUtil.getTickArrayStartIndex(tickLower, poolInfo.config.tickSpacing); const tickArrayUpperStartIndex = TickArrayUtil.getTickArrayStartIndex(tickUpper, poolInfo.config.tickSpacing); const { publicKey: tickArrayLower } = getPdaTickArrayAddress(programId, id, tickArrayLowerStartIndex); const { publicKey: tickArrayUpper } = getPdaTickArrayAddress(programId, id, tickArrayUpperStartIndex); const { publicKey: positionNftAccount } = nft2022 ? getATAAddress(ownerInfo.wallet, nftMintAccount, TOKEN_2022_PROGRAM_ID) : getATAAddress(ownerInfo.wallet, nftMintAccount, TOKEN_PROGRAM_ID); const { publicKey: metadataAccount } = getPdaMetadataKey(nftMintAccount); const { publicKey: personalPosition } = getPdaPersonalPositionAddress(programId, nftMintAccount); const { publicKey: protocolPosition } = getPdaProtocolPositionAddress(programId, id, tickLower, tickUpper); const ins = nft2022 ? this.openPositionWithToken22NftInstruction( programId, ownerInfo.feePayer, id, ownerInfo.wallet, nftMintAccount, positionNftAccount, protocolPosition, tickArrayLower, tickArrayUpper, personalPosition, ownerInfo.tokenAccountA, ownerInfo.tokenAccountB, 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, !base || base === "MintA" ? baseAmount : otherAmountMax, !base || base === "MintA" ? otherAmountMax : baseAmount, withMetadata === "create", base ? base === "MintA" : base, PoolUtil.isOverflowDefaultTickarrayBitmap({ tickSpacing: poolInfo.config.tickSpacing, tickIndexs: [tickArrayLowerStartIndex, tickArrayUpperStartIndex], }) ? getPdaExBitmapAccount(programId, id).publicKey : undefined, ) : this.openPositionV2Instruction( programId, ownerInfo.feePayer, id, ownerInfo.wallet, nftMintAccount, positionNftAccount, metadataAccount, protocolPosition, tickArrayLower, tickArrayUpper, personalPosition, ownerInfo.tokenAccountA, ownerInfo.tokenAccountB, new PublicKey(poolKeys.vault.A), new PublicKey(poolKeys.vault.B), new PublicKey(poolInfo.mintA.address), new PublicKey(poolInfo.mintB.address), tickLower, tickUpper, tickArrayLowerStartIndex, tickArrayUpperStartIndex, BN_ZERO, base === "MintA" ? baseAmount : otherAmountMax, base === "MintA" ? otherAmountMax : baseAmount, withMetadata === "create", base === "MintA", PoolUtil.isOverflowDefaultTickarrayBitmap({ tickSpacing: poolInfo.config.tickSpacing, tickIndexs: [tickArrayLowerStartIndex, tickArrayUpperStartIndex], }) ? getPdaExBitmapAccount(programId, id).publicKey : undefined, ); return { address: { nftMint: nftMintAccount, tickArrayLower, tickArrayUpper, positionNftAccount, metadataAccount, personalPosition, protocolPosition, }, instructions: [ins], signers, instructionTypes: [InstructionType.ClmmOpenPosition], lookupTableAddress: poolKeys.lookupTableAccount ? [poolKeys.lookupTableAccount] : [], }; } static async openPositionFromLiquidityInstructions({ poolInfo, poolKeys, ownerInfo, tickLower, tickUpper, liquidity, amountMaxA, amountMaxB, base, withMetadata, getEphemeralSigners, nft2022, }: { poolInfo: SimpleClmmPoolInfo; poolKeys: ClmmKeys; ownerInfo: { wallet: PublicKey; tokenAccountA: PublicKey; tokenAccountB: PublicKey; }; tickLower: number; tickUpper: number; liquidity: BN; amountMaxA: BN; amountMaxB: BN; base: "MintA" | "MintB" | null; withMetadata: "create" | "no-create"; getEphemeralSigners?: (k: number) => any; nft2022?: boolean; }): Promise<ReturnTypeMakeInstructions<OpenPositionFromLiquidityExtInfo["address"]>> { let nftMintAccount: PublicKey; const signers: Keypair[] = []; if (getEphemeralSigners) { nftMintAccount = new PublicKey((await getEphemeralSigners(1))[0]); } else { const _k = Keypair.generate(); signers.push(_k); nftMintAccount = _k.publicKey; } const [programId, id] = [new PublicKey(poolInfo.programId), new PublicKey(poolInfo.id)]; const tickArrayLowerStartIndex = TickArrayUtil.getTickArrayStartIndex(tickLower, poolInfo.config.tickSpacing); const tickArrayUpperStartIndex = TickArrayUtil.getTickArrayStartIndex(tickUpper, poolInfo.config.tickSpacing); const { publicKey: tickArrayLower } = getPdaTickArrayAddress(programId, id, tickArrayLowerStartIndex); const { publicKey: tickArrayUpper } = getPdaTickArrayAddress(programId, id, tickArrayUpperStartIndex); const { publicKey: positionNftAccount } = nft2022 ? getATAAddress(ownerInfo.wallet, nftMintAccount, TOKEN_2022_PROGRAM_ID) : getATAAddress(ownerInfo.wallet, nftMintAccount, TOKEN_PROGRAM_ID); const { publicKey: metadataAccount } = getPdaMetadataKey(nftMintAccount); const { publicKey: personalPosition } = getPdaPersonalPositionAddress(programId, nftMintAccount); const { publicKey: protocolPosition } = getPdaProtocolPositionAddress(programId, id, tickLower, tickUpper); const ins = nft2022 ? this.openPositionWithToken22NftInstruction( programId, ownerInfo.wallet, id, ownerInfo.wallet, nftMintAccount, positionNftAccount, protocolPosition, tickArrayLower, tickArrayUpper, personalPosition, ownerInfo.tokenAccountA, ownerInfo.tokenAccountB, new PublicKey(poolKeys.vault.A), new PublicKey(poolKeys.vault.B), new PublicKey(poolKeys.mintA.address), new PublicKey(poolKeys.mintB.address), tickLower, tickUpper, tickArrayLowerStartIndex, tickArrayUpperStartIndex, liquidity, amountMaxA, amountMaxB, withMetadata === "create", base ? base === "MintA" : base, PoolUtil.isOverflowDefaultTickarrayBitmap({ tickSpacing: poolInfo.config.tickSpacing, tickIndexs: [tickArrayLowerStartIndex, tickArrayUpperStartIndex], }) ? getPdaExBitmapAccount(programId, id).publicKey : undefined, ) : this.openPositionV2Instruction( programId, ownerInfo.wallet, id, ownerInfo.wallet, nftMintAccount, positionNftAccount, metadataAccount, protocolPosition, tickArrayLower, tickArrayUpper, personalPosition, ownerInfo.tokenAccountA, ownerInfo.tokenAccountB, new PublicKey(poolKeys.vault.A), new PublicKey(poolKeys.vault.B), new PublicKey(poolKeys.mintA.address), new PublicKey(poolKeys.mintB.address), tickLower, tickUpper, tickArrayLowerStartIndex, tickArrayUpperStartIndex, liquidity, amountMaxA, amountMaxB, withMetadata === "create", null, PoolUtil.isOverflowDefaultTickarrayBitmap({ tickSpacing: poolInfo.config.tickSpacing, tickIndexs: [tickArrayLowerStartIndex, tickArrayUpperStartIndex], }) ? getPdaExBitmapAccount(programId, id).publicKey : undefined, ); return { address: { nftMint: nftMintAccount, tickArrayLower, tickArrayUpper, positionNftAccount, metadataAccount, personalPosition, protocolPosition, }, instructions: [ins], signers, instructionTypes: [InstructionType.ClmmOpenPosition], lookupTableAddress: poolKeys.lookupTableAccount ? [poolKeys.lookupTableAccount] : [], }; } static closePositionInstructions({ poolInfo, poolKeys, ownerInfo, ownerPosition, nft2022, }: { poolInfo: ApiV3PoolInfoConcentratedItem; poolKeys: ClmmKeys; ownerPosition: ReturnType<typeof PersonalPositionLayout.decode>; ownerInfo: { wallet: PublicKey; }; nft2022?: boolean; }): ReturnTypeMakeInstructions<ClosePositionExtInfo["address"]> { const programId = new PublicKey(poolInfo.programId); // const { publicKey: positionNftAccount } = getATAAddress(ownerInfo.wallet, ownerPosition.nftMint, TOKEN_PROGRAM_ID); const positionNftAccount = nft2022 ? getATAAddress(ownerInfo.wallet, ownerPosition.nftMint, TOKEN_2022_PROGRAM_ID).publicKey : getATAAddress(ownerInfo.wallet, ownerPosition.nftMint, TOKEN_PROGRAM_ID).publicKey; const { publicKey: personalPosition } = getPdaPersonalPositionAddress(programId, ownerPosition.nftMint); const ins: TransactionInstruction[] = []; ins.push( this.closePositionInstruction( programId, ownerInfo.wallet, ownerPosition.nftMint, positionNftAccount, personalPosition, nft2022, ), ); return { address: { positionNftAccount, personalPosition, }, signers: [], instructions: ins, instructionTypes: [InstructionType.ClmmClosePosition], lookupTableAddress: poolKeys.lookupTableAccount ? [poo