@powrldgr/raydium-sdk-v2
Version:
An SDK for building applications on top of Raydium.
1,533 lines (1,368 loc) • 81.1 kB
text/typescript
import { Connection, Keypair, PublicKey, Signer, SystemProgram, TransactionInstruction } from "@solana/web3.js";
import BN from "bn.js";
import { ReturnTypeMakeInstructions } from "@/raydium/type";
import { ApiV3PoolInfoConcentratedItem, ApiV3Token, ClmmKeys } from "@/api/type";
import {
InstructionType,
MEMO_PROGRAM_ID,
MEMO_PROGRAM_ID2,
METADATA_PROGRAM_ID,
RENT_PROGRAM_ID,
createLogger,
getATAAddress,
parseBigNumberish,
} from "@/common";
import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, TOKEN_PROGRAM_ID } from "@solana/spl-token";
import { bool, s32, struct, u128, u64, u8 } from "@/marshmallow";
import { ClmmPositionLayout, ObservationInfoLayout } from "./layout";
import {
ClmmPoolPersonalPosition,
ClosePositionExtInfo,
InitRewardExtInfo,
ManipulateLiquidityExtInfo,
OpenPositionFromBaseExtInfo,
OpenPositionFromLiquidityExtInfo,
ClmmLockAddress,
} from "./type";
import {
getPdaExBitmapAccount,
getPdaLockPositionId,
getPdaMetadataKey,
getPdaObservationAccount,
getPdaOperationAccount,
getPdaPersonalPositionAddress,
getPdaPoolId,
getPdaPoolRewardVaulId,
getPdaPoolVaultId,
getPdaProtocolPositionAddress,
getPdaTickArrayAddress,
getPdaLockClPositionIdV2,
getPdaMintExAccount,
} from "./utils/pda";
import { PoolUtils } from "./utils/pool";
import { TickUtils } from "./utils/tick";
import { ZERO } from "./utils/constants";
ObservationInfoLayout.span; // do not delete this line
const logger = createLogger("Raydium_Clmm");
const anchorDataBuf = {
createPool: [233, 146, 209, 142, 207, 104, 64, 188],
initReward: [95, 135, 192, 196, 242, 129, 230, 68],
setRewardEmissions: [112, 52, 167, 75, 32, 201, 211, 137],
openPosition: [77, 184, 74, 214, 112, 86, 241, 199],
openPositionWithTokenEx: [77, 255, 174, 82, 125, 29, 201, 46],
closePosition: [123, 134, 81, 0, 49, 68, 98, 98],
increaseLiquidity: [133, 29, 89, 223, 69, 238, 176, 10],
decreaseLiquidity: [58, 127, 188, 62, 79, 82, 196, 96],
swap: [43, 4, 237, 11, 26, 201, 30, 98], // [248, 198, 158, 145, 225, 117, 135, 200],
collectReward: [18, 237, 166, 197, 34, 16, 213, 144],
};
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,
mintVaultA: PublicKey,
mintProgramIdA: PublicKey,
mintB: PublicKey,
mintVaultB: PublicKey,
mintProgramIdB: PublicKey,
exTickArrayBitmap: PublicKey,
sqrtPriceX64: BN,
extendMintAccount?: PublicKey[],
): TransactionInstruction {
const dataLayout = struct([u128("sqrtPriceX64"), u64("zero")]);
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: mintVaultA, isSigner: false, isWritable: true },
{ pubkey: mintVaultB, isSigner: false, isWritable: true },
{ pubkey: observationId, isSigner: false, isWritable: true },
{ pubkey: exTickArrayBitmap, 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 },
...(extendMintAccount?.map((k) => ({ pubkey: k, isSigner: false, isWritable: false })) || []),
];
const data = Buffer.alloc(dataLayout.span);
dataLayout.encode(
{
sqrtPriceX64,
zero: ZERO,
},
data,
);
const aData = Buffer.from([...anchorDataBuf.createPool, ...data]);
return new TransactionInstruction({
keys,
programId,
data: aData,
});
}
static async createPoolInstructions(props: CreatePoolInstruction): Promise<
ReturnTypeMakeInstructions<{
poolId: PublicKey;
observationId: PublicKey;
exBitmapAccount: 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 { 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,
new PublicKey(mintA.programId || TOKEN_PROGRAM_ID),
mintBAddress,
mintBVault,
new PublicKey(mintB.programId || TOKEN_PROGRAM_ID),
exBitmapAccount,
initialPriceX64,
extendMintAccount,
),
];
return {
signers: [],
instructions: ins,
instructionTypes: [InstructionType.CreateAccount, InstructionType.ClmmCreatePool],
address: { poolId, observationId, exBitmapAccount, mintAVault, mintBVault },
lookupTableAddress: [],
};
}
static openPositionFromLiquidityInstruction(
programId: PublicKey,
payer: PublicKey,
poolId: PublicKey,
positionNftOwner: PublicKey,
positionNftMint: PublicKey,
positionNftAccount: PublicKey,
metadataAccount: PublicKey,
protocolPosition: PublicKey,
tickArrayLower: PublicKey,
tickArrayUpper: PublicKey,
personalPosition: PublicKey,
ownerTokenAccountA: PublicKey,
ownerTokenAccountB: 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: 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: true },
{ pubkey: tickArrayLower, isSigner: false, isWritable: true },
{ pubkey: tickArrayUpper, isSigner: false, isWritable: true },
{ pubkey: personalPosition, isSigner: false, isWritable: true },
{ pubkey: ownerTokenAccountA, isSigner: false, isWritable: true },
{ pubkey: ownerTokenAccountB, 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: METADATA_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 },
...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,
data: aData,
});
}
static openPositionFromLiquidityInstruction22(
programId: PublicKey,
payer: PublicKey,
poolId: PublicKey,
positionNftOwner: PublicKey,
positionNftMint: PublicKey,
positionNftAccount: PublicKey,
protocolPosition: PublicKey,
tickArrayLower: PublicKey,
tickArrayUpper: PublicKey,
personalPosition: PublicKey,
ownerTokenAccountA: PublicKey,
ownerTokenAccountB: 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: 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: true },
{ pubkey: tickArrayLower, isSigner: false, isWritable: true },
{ pubkey: tickArrayUpper, isSigner: false, isWritable: true },
{ pubkey: personalPosition, isSigner: false, isWritable: true },
{ pubkey: ownerTokenAccountA, isSigner: false, isWritable: true },
{ pubkey: ownerTokenAccountB, 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 },
...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.openPositionWithTokenEx, ...data]);
return new TransactionInstruction({
keys,
programId,
data: aData,
});
}
static async openPositionInstructions({
poolInfo,
poolKeys,
ownerInfo,
tickLower,
tickUpper,
liquidity,
amountMaxA,
amountMaxB,
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;
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 = 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: 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.openPositionFromLiquidityInstruction22(
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,
PoolUtils.isOverflowDefaultTickarrayBitmap(poolInfo.config.tickSpacing, [
tickArrayLowerStartIndex,
tickArrayUpperStartIndex,
])
? getPdaExBitmapAccount(programId, id).publicKey
: undefined,
)
: this.openPositionFromLiquidityInstruction(
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,
PoolUtils.isOverflowDefaultTickarrayBitmap(poolInfo.config.tickSpacing, [
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,
withMetadata,
getEphemeralSigners,
nft2022,
}: {
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;
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 = 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: 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.openPositionFromBaseInstruction22(
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,
withMetadata,
base,
baseAmount,
otherAmountMax,
PoolUtils.isOverflowDefaultTickarrayBitmap(poolInfo.config.tickSpacing, [
tickArrayLowerStartIndex,
tickArrayUpperStartIndex,
])
? getPdaExBitmapAccount(programId, id).publicKey
: undefined,
)
: this.openPositionFromBaseInstruction(
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,
withMetadata,
base,
baseAmount,
otherAmountMax,
PoolUtils.isOverflowDefaultTickarrayBitmap(poolInfo.config.tickSpacing, [
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 openPositionFromBaseInstruction(
programId: PublicKey,
payer: PublicKey,
poolId: PublicKey,
positionNftOwner: PublicKey,
positionNftMint: PublicKey,
positionNftAccount: PublicKey,
metadataAccount: PublicKey,
protocolPosition: PublicKey,
tickArrayLower: PublicKey,
tickArrayUpper: PublicKey,
personalPosition: PublicKey,
ownerTokenAccountA: PublicKey,
ownerTokenAccountB: 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: 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: true },
{ pubkey: tickArrayLower, isSigner: false, isWritable: true },
{ pubkey: tickArrayUpper, isSigner: false, isWritable: true },
{ pubkey: personalPosition, isSigner: false, isWritable: true },
{ pubkey: ownerTokenAccountA, isSigner: false, isWritable: true },
{ pubkey: ownerTokenAccountB, 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: METADATA_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 },
...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,
data: aData,
});
}
static openPositionFromBaseInstruction22(
programId: PublicKey,
payer: PublicKey,
poolId: PublicKey,
positionNftOwner: PublicKey,
positionNftMint: PublicKey,
positionNftAccount: PublicKey,
protocolPosition: PublicKey,
tickArrayLower: PublicKey,
tickArrayUpper: PublicKey,
personalPosition: PublicKey,
ownerTokenAccountA: PublicKey,
ownerTokenAccountB: 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: 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: true },
{ pubkey: tickArrayLower, isSigner: false, isWritable: true },
{ pubkey: tickArrayUpper, isSigner: false, isWritable: true },
{ pubkey: personalPosition, isSigner: false, isWritable: true },
{ pubkey: ownerTokenAccountA, isSigner: false, isWritable: true },
{ pubkey: ownerTokenAccountB, 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 },
...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.openPositionWithTokenEx, ...data]);
return new TransactionInstruction({
keys,
programId,
data: aData,
});
}
static async openPositionFromLiquidityInstructions({
poolInfo,
poolKeys,
ownerInfo,
tickLower,
tickUpper,
liquidity,
amountMaxA,
amountMaxB,
withMetadata,
getEphemeralSigners,
nft2022,
}: {
poolInfo: ApiV3PoolInfoConcentratedItem;
poolKeys: ClmmKeys;
ownerInfo: {
wallet: PublicKey;
tokenAccountA: PublicKey;
tokenAccountB: PublicKey;
};
tickLower: number;
tickUpper: number;
liquidity: BN;
amountMaxA: BN;
amountMaxB: BN;
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 = 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: 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.openPositionFromLiquidityInstruction22(
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,
PoolUtils.isOverflowDefaultTickarrayBitmap(poolInfo.config.tickSpacing, [
tickArrayLowerStartIndex,
tickArrayUpperStartIndex,
])
? getPdaExBitmapAccount(programId, id).publicKey
: undefined,
)
: this.openPositionFromLiquidityInstruction(
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,
PoolUtils.isOverflowDefaultTickarrayBitmap(poolInfo.config.tickSpacing, [
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 closePositionInstruction(
programId: PublicKey,
positionNftOwner: PublicKey,
positionNftMint: PublicKey,
positionNftAccount: PublicKey,
personalPosition: PublicKey,
nft2022?: boolean,
): TransactionInstruction {
const dataLayout = struct([]);
const keys = [
{ pubkey: positionNftOwner, 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 data = Buffer.alloc(dataLayout.span);
dataLayout.encode({}, data);
const aData = Buffer.from([...anchorDataBuf.closePosition, ...data]);
return new TransactionInstruction({
keys,
programId,
data: aData,
});
}
static closePositionInstructions({
poolInfo,
poolKeys,
ownerInfo,
ownerPosition,
nft2022,
}: {
poolInfo: ApiV3PoolInfoConcentratedItem;
poolKeys: ClmmKeys;
ownerPosition: ClmmPositionLayout;
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 ? [poolKeys.lookupTableAccount] : [],
};
}
static increasePositionFromLiquidityInstruction(
programId: PublicKey,
positionNftOwner: PublicKey,
positionNftAccount: PublicKey,
personalPosition: PublicKey,
poolId: PublicKey,
protocolPosition: PublicKey,
tickArrayLower: PublicKey,
tickArrayUpper: PublicKey,
ownerTokenAccountA: PublicKey,
ownerTokenAccountB: PublicKey,
mintVaultA: PublicKey,
mintVaultB: PublicKey,
mintMintA: PublicKey,
mintMintB: 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: positionNftOwner, isSigner: true, 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: ownerTokenAccountA, isSigner: false, isWritable: true },
{ pubkey: ownerTokenAccountB, isSigner: false, isWritable: true },
{ pubkey: mintVaultA, isSigner: false, isWritable: true },
{ pubkey: mintVaultB, isSigner: false, isWritable: true },
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: TOKEN_2022_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: mintMintA, isSigner: false, isWritable: false },
{ pubkey: mintMintB, 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,
data: aData,
});
}
static increasePositionFromLiquidityInstructions({
poolInfo,
poolKeys,
ownerPosition,
ownerInfo,
liquidity,
amountMaxA,
amountMaxB,
nft2022,
}: {
poolInfo: ApiV3PoolInfoConcentratedItem;
poolKeys: ClmmKeys;
ownerPosition: ClmmPositionLayout;
ownerInfo: {
wallet: PublicKey;
tokenAccountA: PublicKey;
tokenAccountB: PublicKey;
};
liquidity: BN;
amountMaxA: BN;
amountMaxB: BN;
nft2022?: boolean;
}): 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: positionNftAccount } = nft2022
? getATAAddress(ownerInfo.wallet, ownerPosition.nftMint, TOKEN_2022_PROGRAM_ID)
: getATAAddress(ownerInfo.wallet, ownerPosition.nftMint, TOKEN_PROGRAM_ID);
const { publicKey: personalPosition } = getPdaPersonalPositionAddress(programId, ownerPosition.nftMint);
const { publicKey: protocolPosition } = getPdaProtocolPositionAddress(
programId,
id,
ownerPosition.tickLower,
ownerPosition.tickUpper,
);
const ins = this.increasePositionFromLiquidityInstruction(
programId,
ownerInfo.wallet,
positionNftAccount,
personalPosition,
id,
protocolPosition,
tickArrayLower,
tickArrayUpper,
ownerInfo.tokenAccountA,
ownerInfo.tokenAccountB,
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,
},
signers: [],
instructions: [ins],
instructionTypes: [InstructionType.ClmmIncreasePosition],
lookupTableAddress: poolKeys.lookupTableAccount ? [poolKeys.lookupTableAccount] : [],
};
}
static increasePositionFromBaseInstructions({
poolInfo,
poolKeys,
ownerPosition,
ownerInfo,
base,
baseAmount,
otherAmountMax,
nft2022,
}: {
poolInfo: ApiV3PoolInfoConcentratedItem;
poolKeys: ClmmKeys;
ownerPosition: ClmmPoolPersonalPosition;
ownerInfo: {
wallet: PublicKey;
tokenAccountA: PublicKey;
tokenAccountB: PublicKey;
};
base: "MintA" | "MintB";
baseAmount: BN;
otherAmountMax: BN;
nft2022?: boolean;
}): 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: positionNftAccount } = nft2022
? getATAAddress(ownerInfo.wallet, ownerPosition.nftMint, TOKEN_2022_PROGRAM_ID)
: getATAAddress(ownerInfo.wallet, ownerPosition.nftMint, TOKEN_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(
programId,
ownerInfo.wallet,
positionNftAccount,
personalPosition,
id,
protocolPosition,
tickArrayLower,
tickArrayUpper,
ownerInfo.tokenAccountA,
ownerInfo.tokenAccountB,
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.ClmmIncreasePosition],
lookupTableAddress: poolKeys.lookupTableAccount ? [poolKeys.lookupTableAccount] : [],
};
}
static increasePositionFromBaseInstruction(
programId: PublicKey,
positionNftOwner: PublicKey,
positionNftAccount: PublicKey,
personalPosition: PublicKey,
poolId: PublicKey,
protocolPosition: PublicKey,
tickArrayLower: PublicKey,
tickArrayUpper: PublicKey,
ownerTokenAccountA: PublicKey,
ownerTokenAccountB: PublicKey,
mintVaultA: PublicKey,
mintVaultB: PublicKey,
mintMintA: PublicKey,
mintMintB: 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: positionNftOwner, isSigner: true, 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: ownerTokenAccountA, isSigner: false, isWritable: true },
{ pubkey: ownerTokenAccountB, isSigner: false, isWritable: true },
{ pubkey: mintVaultA, isSigner: false, isWritable: true },
{ pubkey: mintVaultB, isSigner: false, isWritable: true },
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: TOKEN_2022_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: mintMintA, isSigner: false, isWritable: false },
{ pubkey: mintMintB, 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,
data: aData,
});
}
static decreaseLiquidityInstruction(
programId: PublicKey,
positionNftOwner: PublicKey,
positionNftAccount: PublicKey,
personalPosition: PublicKey,
poolId: PublicKey,
protocolPosition: PublicKey,
tickArrayLower: PublicKey,
tickArrayUpper: PublicKey,
ownerTokenAccountA: PublicKey,
ownerTokenAccountB: PublicKey,
mintVaultA: PublicKey,
mintVaultB: PublicKey,
mintMintA: PublicKey,
mintMintB: 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: positionNftOwner, isSigner: true, 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: mintVaultA, isSigner: false, isWritable: true },
{ pubkey: mintVaultB, isSigner: false, isWritable: true },
{ pubkey: tickArrayLower, isSigner: false, isWritable: true },
{ pubkey: tickArrayUpper, isSigner: false, isWritable: true },
{ pubkey: ownerTokenAccountA, isSigner: false, isWritable: true },
{ pubkey: ownerTokenAccountB, 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: mintMintA, isSigner: false, isWritable: false },
{ pubkey: mintMintB, 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,
data: aData,
});
}
static decreaseLiquidityInstructions({
poolInfo,
poolKeys,
ownerPosition,
ownerInfo,
liquidity,
amountMinA,
amountMinB,
programId,
nft2022,
}: {
poolInfo: ApiV3PoolInfoConcentratedItem;
poolKeys: ClmmKeys;
ownerPo