raydium-sdk-v2-custody
Version:
An SDK for building applications on top of Raydium.
1,509 lines (1,325 loc) • 49.6 kB
text/typescript
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: {},
}
}
}