@raydium-io/raydium-sdk-v2
Version:
An SDK for building applications on top of Raydium.
658 lines (608 loc) • 21.5 kB
text/typescript
import BN from "bn.js";
import { AccountMeta, PublicKey, TransactionInstruction, Signer, Keypair, SystemProgram } from "@solana/web3.js";
import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, TOKEN_PROGRAM_ID } from "@solana/spl-token";
import {
MEMO_PROGRAM_ID2,
RENT_PROGRAM_ID,
SYSTEM_PROGRAM_ID,
METADATA_PROGRAM_ID,
createLogger,
CREATE_CPMM_POOL_PROGRAM,
CREATE_CPMM_POOL_AUTH,
InstructionType,
} from "@/common";
import { getCpmmPdaPoolId, getCpLockPda } from "./pda";
import { struct, u8, u64, bool } from "@/marshmallow";
import { ReturnTypeMakeInstructions } from "@/raydium/type";
import { ApiV3PoolInfoStandardItemCpmm, CpmmKeys } from "@/api";
import { getATAAddress } from "@/common";
import { getPdaMetadataKey } from "../clmm";
import { CpmmLockExtInfo, FeeOn } from "./type";
const logger = createLogger("Raydium_cpmm");
const anchorDataBuf = {
initialize: [175, 175, 109, 31, 13, 152, 155, 237],
deposit: [242, 35, 198, 137, 82, 225, 242, 182],
withdraw: [183, 18, 70, 156, 148, 109, 161, 34],
swapBaseInput: [143, 190, 90, 218, 196, 30, 51, 222],
swapBaseOutput: [55, 217, 98, 86, 163, 74, 180, 173],
lockCpLiquidity: [216, 157, 29, 78, 38, 51, 31, 26],
collectCpFee: [8, 30, 51, 199, 209, 184, 247, 133],
createPermissionPda: Buffer.from([135, 136, 2, 216, 137, 169, 181, 202]),
closePermissionPda: Buffer.from([156, 84, 32, 118, 69, 135, 70, 123]),
initializeWithPermission: Buffer.from([63, 55, 254, 65, 49, 178, 89, 121]),
collectCreatorFee: Buffer.from([20, 22, 86, 123, 198, 28, 219, 132]),
};
export function makeCreateCpmmPoolInInstruction(
programId: PublicKey,
creator: PublicKey,
configId: PublicKey,
authority: PublicKey,
poolId: PublicKey,
mintA: PublicKey,
mintB: PublicKey,
lpMint: PublicKey,
userVaultA: PublicKey,
userVaultB: PublicKey,
userLpAccount: PublicKey,
vaultA: PublicKey,
vaultB: PublicKey,
createPoolFeeAccount: PublicKey,
mintProgramA: PublicKey,
mintProgramB: PublicKey,
observationId: PublicKey,
amountMaxA: BN,
amountMaxB: BN,
openTime: BN,
): TransactionInstruction {
const dataLayout = struct([u64("amountMaxA"), u64("amountMaxB"), u64("openTime")]);
const pdaPoolId = getCpmmPdaPoolId(programId, configId, mintA, mintB).publicKey;
const keys: Array<AccountMeta> = [
{ pubkey: creator, isSigner: true, isWritable: false },
{ pubkey: configId, isSigner: false, isWritable: false },
{ pubkey: authority, isSigner: false, isWritable: false },
{ pubkey: poolId, isSigner: !poolId.equals(pdaPoolId), isWritable: true },
{ pubkey: mintA, isSigner: false, isWritable: false },
{ pubkey: mintB, isSigner: false, isWritable: false },
{ pubkey: lpMint, isSigner: false, isWritable: true },
{ pubkey: userVaultA, isSigner: false, isWritable: true },
{ pubkey: userVaultB, isSigner: false, isWritable: true },
{ pubkey: userLpAccount, isSigner: false, isWritable: true },
{ pubkey: vaultA, isSigner: false, isWritable: true },
{ pubkey: vaultB, isSigner: false, isWritable: true },
{ pubkey: createPoolFeeAccount, isSigner: false, isWritable: true },
{ pubkey: observationId, isSigner: false, isWritable: true },
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: mintProgramA, isSigner: false, isWritable: false },
{ pubkey: mintProgramB, isSigner: false, isWritable: false },
{ pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: SYSTEM_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: RENT_PROGRAM_ID, isSigner: false, isWritable: false },
];
const data = Buffer.alloc(dataLayout.span);
dataLayout.encode(
{
amountMaxA,
amountMaxB,
openTime,
},
data,
);
return new TransactionInstruction({
keys,
programId,
data: Buffer.from([...anchorDataBuf.initialize, ...data]),
});
}
export function makeDepositCpmmInInstruction(
programId: PublicKey,
owner: PublicKey,
authority: PublicKey,
poolId: PublicKey,
userLpAccount: PublicKey,
userVaultA: PublicKey,
userVaultB: PublicKey,
vaultA: PublicKey,
vaultB: PublicKey,
mintA: PublicKey,
mintB: PublicKey,
lpMint: PublicKey,
lpAmount: BN,
amountMaxA: BN,
amountMaxB: BN,
): TransactionInstruction {
const dataLayout = struct([u64("lpAmount"), u64("amountMaxA"), u64("amountMaxB")]);
const keys: Array<AccountMeta> = [
{ pubkey: owner, isSigner: true, isWritable: false },
{ pubkey: authority, isSigner: false, isWritable: false },
{ pubkey: poolId, isSigner: false, isWritable: true },
{ pubkey: userLpAccount, isSigner: false, isWritable: true },
{ pubkey: userVaultA, isSigner: false, isWritable: true },
{ pubkey: userVaultB, 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 },
{ pubkey: lpMint, isSigner: false, isWritable: true },
];
const data = Buffer.alloc(dataLayout.span);
logger.debug("cpmm deposit data", {
lpAmount: lpAmount.toString(),
amountMaxA: amountMaxA.toString(),
amountMaxB: amountMaxB.toString(),
});
dataLayout.encode(
{
lpAmount,
amountMaxA,
amountMaxB,
},
data,
);
return new TransactionInstruction({
keys,
programId,
data: Buffer.from([...anchorDataBuf.deposit, ...data]),
});
}
export function makeWithdrawCpmmInInstruction(
programId: PublicKey,
owner: PublicKey,
authority: PublicKey,
poolId: PublicKey,
userLpAccount: PublicKey,
userVaultA: PublicKey,
userVaultB: PublicKey,
vaultA: PublicKey,
vaultB: PublicKey,
mintA: PublicKey,
mintB: PublicKey,
lpMint: PublicKey,
lpAmount: BN,
amountMinA: BN,
amountMinB: BN,
): TransactionInstruction {
const dataLayout = struct([u64("lpAmount"), u64("amountMinA"), u64("amountMinB")]);
const keys: Array<AccountMeta> = [
{ pubkey: owner, isSigner: true, isWritable: false },
{ pubkey: authority, isSigner: false, isWritable: false },
{ pubkey: poolId, isSigner: false, isWritable: true },
{ pubkey: userLpAccount, isSigner: false, isWritable: true },
{ pubkey: userVaultA, isSigner: false, isWritable: true },
{ pubkey: userVaultB, 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 },
{ pubkey: lpMint, isSigner: false, isWritable: true },
{ pubkey: MEMO_PROGRAM_ID2, isSigner: false, isWritable: false },
];
const data = Buffer.alloc(dataLayout.span);
dataLayout.encode(
{
lpAmount,
amountMinA,
amountMinB,
},
data,
);
return new TransactionInstruction({
keys,
programId,
data: Buffer.from([...anchorDataBuf.withdraw, ...data]),
});
}
export function makeSwapCpmmBaseInInstruction(
programId: PublicKey,
payer: PublicKey,
authority: PublicKey,
configId: PublicKey,
poolId: PublicKey,
userInputAccount: PublicKey,
userOutputAccount: PublicKey,
inputVault: PublicKey,
outputVault: PublicKey,
inputTokenProgram: PublicKey,
outputTokenProgram: PublicKey,
inputMint: PublicKey,
outputMint: PublicKey,
observationId: PublicKey,
amountIn: BN,
amounOutMin: BN,
): TransactionInstruction {
const dataLayout = struct([u64("amountIn"), u64("amounOutMin")]);
const keys: Array<AccountMeta> = [
{ pubkey: payer, isSigner: true, isWritable: false },
{ pubkey: authority, isSigner: false, isWritable: false },
{ pubkey: configId, isSigner: false, isWritable: false },
{ pubkey: poolId, isSigner: false, isWritable: true },
{ pubkey: userInputAccount, isSigner: false, isWritable: true },
{ pubkey: userOutputAccount, isSigner: false, isWritable: true },
{ pubkey: inputVault, isSigner: false, isWritable: true },
{ pubkey: outputVault, isSigner: false, isWritable: true },
{ pubkey: inputTokenProgram, isSigner: false, isWritable: false },
{ pubkey: outputTokenProgram, isSigner: false, isWritable: false },
{ pubkey: inputMint, isSigner: false, isWritable: false },
{ pubkey: outputMint, isSigner: false, isWritable: false },
{ pubkey: observationId, isSigner: false, isWritable: true },
];
const data = Buffer.alloc(dataLayout.span);
dataLayout.encode(
{
amountIn,
amounOutMin,
},
data,
);
return new TransactionInstruction({
keys,
programId,
data: Buffer.from([...anchorDataBuf.swapBaseInput, ...data]),
});
}
export function makeSwapCpmmBaseOutInstruction(
programId: PublicKey,
payer: PublicKey,
authority: PublicKey,
configId: PublicKey,
poolId: PublicKey,
userInputAccount: PublicKey,
userOutputAccount: PublicKey,
inputVault: PublicKey,
outputVault: PublicKey,
inputTokenProgram: PublicKey,
outputTokenProgram: PublicKey,
inputMint: PublicKey,
outputMint: PublicKey,
observationId: PublicKey,
amountInMax: BN,
amountOut: BN,
): TransactionInstruction {
const dataLayout = struct([u64("amountInMax"), u64("amountOut")]);
const keys: Array<AccountMeta> = [
{ pubkey: payer, isSigner: true, isWritable: false },
{ pubkey: authority, isSigner: false, isWritable: false },
{ pubkey: configId, isSigner: false, isWritable: false },
{ pubkey: poolId, isSigner: false, isWritable: true },
{ pubkey: userInputAccount, isSigner: false, isWritable: true },
{ pubkey: userOutputAccount, isSigner: false, isWritable: true },
{ pubkey: inputVault, isSigner: false, isWritable: true },
{ pubkey: outputVault, isSigner: false, isWritable: true },
{ pubkey: inputTokenProgram, isSigner: false, isWritable: false },
{ pubkey: outputTokenProgram, isSigner: false, isWritable: false },
{ pubkey: inputMint, isSigner: false, isWritable: false },
{ pubkey: outputMint, isSigner: false, isWritable: false },
{ pubkey: observationId, isSigner: false, isWritable: true },
];
const data = Buffer.alloc(dataLayout.span);
dataLayout.encode(
{
amountInMax,
amountOut,
},
data,
);
return new TransactionInstruction({
keys,
programId,
data: Buffer.from([...anchorDataBuf.swapBaseOutput, ...data]),
});
}
export async function makeCpmmLockInstruction(props: {
poolInfo: ApiV3PoolInfoStandardItemCpmm;
poolKeys: CpmmKeys;
ownerInfo: {
feePayer: PublicKey;
wallet: PublicKey;
};
feeNftOwner: PublicKey;
lockProgram: PublicKey;
lockAuthProgram: PublicKey;
lpAmount: BN;
withMetadata?: boolean;
getEphemeralSigners?: (k: number) => any;
}): Promise<ReturnTypeMakeInstructions<CpmmLockExtInfo>> {
const { ownerInfo, poolInfo, poolKeys, feeNftOwner, getEphemeralSigners } = props;
const signers: Signer[] = [];
const [poolId, lpMint] = [new PublicKey(poolInfo.id), new PublicKey(poolInfo.lpMint.address)];
let nftMintAccount: PublicKey;
if (getEphemeralSigners) {
nftMintAccount = new PublicKey((await getEphemeralSigners(1))[0]);
} else {
const _k = Keypair.generate();
signers.push(_k);
nftMintAccount = _k.publicKey;
}
const { publicKey: nftAccount } = getATAAddress(feeNftOwner, nftMintAccount, TOKEN_PROGRAM_ID);
const { publicKey: metadataAccount } = getPdaMetadataKey(nftMintAccount);
const { publicKey: lockPda } = getCpLockPda(props.lockProgram, nftMintAccount);
const { publicKey: userLpVault } = getATAAddress(ownerInfo.wallet, lpMint, TOKEN_PROGRAM_ID);
const { publicKey: lockLpVault } = getATAAddress(props.lockAuthProgram, lpMint, TOKEN_PROGRAM_ID);
const ins = cpmmLockPositionInstruction({
programId: props.lockProgram,
auth: props.lockAuthProgram,
payer: ownerInfo.feePayer,
liquidityOwner: ownerInfo.wallet,
nftOwner: feeNftOwner,
nftMint: nftMintAccount,
nftAccount,
poolId,
lockPda,
mintLp: lpMint,
userLpVault,
lockLpVault,
poolVaultA: new PublicKey(poolKeys.vault.A),
poolVaultB: new PublicKey(poolKeys.vault.B),
metadataAccount,
lpAmount: props.lpAmount,
withMetadata: props.withMetadata ?? true,
});
return {
address: {
nftMint: nftMintAccount,
nftAccount,
metadataAccount,
lockPda,
userLpVault,
lockLpVault,
},
instructions: [ins],
signers,
instructionTypes: [InstructionType.CpmmLockLp],
lookupTableAddress: [],
};
}
export function cpmmLockPositionInstruction({
programId,
auth,
payer,
liquidityOwner,
nftOwner,
nftMint,
nftAccount,
poolId,
lockPda,
mintLp,
userLpVault,
lockLpVault,
poolVaultA,
poolVaultB,
metadataAccount,
lpAmount,
withMetadata,
}: {
programId: PublicKey;
auth: PublicKey;
payer: PublicKey;
liquidityOwner: PublicKey;
nftOwner: PublicKey;
nftMint: PublicKey;
nftAccount: PublicKey;
poolId: PublicKey;
lockPda: PublicKey;
mintLp: PublicKey;
userLpVault: PublicKey;
lockLpVault: PublicKey;
poolVaultA: PublicKey;
poolVaultB: PublicKey;
metadataAccount: PublicKey;
lpAmount: BN;
withMetadata: boolean;
}): TransactionInstruction {
const keys = [
{ pubkey: auth, isSigner: false, isWritable: false },
{ pubkey: payer, isSigner: true, isWritable: true },
{ pubkey: liquidityOwner, isSigner: true, isWritable: false },
{ pubkey: nftOwner, isSigner: false, isWritable: false },
{ pubkey: nftMint, isSigner: true, isWritable: true },
{ pubkey: nftAccount, isSigner: false, isWritable: true },
{ pubkey: poolId, isSigner: false, isWritable: false },
{ pubkey: lockPda, isSigner: false, isWritable: true },
{ pubkey: mintLp, isSigner: false, isWritable: false },
{ pubkey: userLpVault, isSigner: false, isWritable: true },
{ pubkey: lockLpVault, isSigner: false, isWritable: true },
{ pubkey: poolVaultA, isSigner: false, isWritable: true },
{ pubkey: poolVaultB, isSigner: false, isWritable: true },
{ pubkey: metadataAccount, 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 },
];
const dataLayout = struct([u64("lpAmount"), bool("withMetadata")]);
const data = Buffer.alloc(dataLayout.span);
dataLayout.encode(
{
lpAmount,
withMetadata,
},
data,
);
const aData = Buffer.from([...anchorDataBuf.lockCpLiquidity, ...data]);
return new TransactionInstruction({
keys,
programId,
data: aData,
});
}
export function collectCpFeeInstruction({
programId,
nftOwner,
auth,
nftAccount,
lockPda,
poolId,
mintLp,
userVaultA,
userVaultB,
poolVaultA,
poolVaultB,
mintA,
mintB,
lockLpVault,
lpFeeAmount,
cpmmProgram,
cpmmAuthProgram,
}: {
programId: PublicKey;
nftOwner: PublicKey;
auth: PublicKey;
nftMint: PublicKey;
nftAccount: PublicKey;
lockPda: PublicKey;
poolId: PublicKey;
mintLp: PublicKey;
userVaultA: PublicKey;
userVaultB: PublicKey;
poolVaultA: PublicKey;
poolVaultB: PublicKey;
mintA: PublicKey;
mintB: PublicKey;
lockLpVault: PublicKey;
lpFeeAmount: BN;
cpmmProgram?: PublicKey;
cpmmAuthProgram?: PublicKey;
}): TransactionInstruction {
const keys = [
{ pubkey: auth, isSigner: false, isWritable: false },
{ pubkey: nftOwner, isSigner: true, isWritable: false },
// { pubkey: nftMint, isSigner: false, isWritable: true },
{ pubkey: nftAccount, isSigner: false, isWritable: true },
{ pubkey: lockPda, isSigner: false, isWritable: true },
{ pubkey: cpmmProgram ?? CREATE_CPMM_POOL_PROGRAM, isSigner: false, isWritable: false },
{ pubkey: cpmmAuthProgram ?? CREATE_CPMM_POOL_AUTH, isSigner: false, isWritable: false },
{ pubkey: poolId, isSigner: false, isWritable: true },
{ pubkey: mintLp, isSigner: false, isWritable: true },
{ pubkey: userVaultA, isSigner: false, isWritable: true },
{ pubkey: userVaultB, isSigner: false, isWritable: true },
{ pubkey: poolVaultA, isSigner: false, isWritable: true },
{ pubkey: poolVaultB, isSigner: false, isWritable: true },
{ pubkey: mintA, isSigner: false, isWritable: false },
{ pubkey: mintB, isSigner: false, isWritable: false },
{ pubkey: lockLpVault, isSigner: false, isWritable: true },
// { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: TOKEN_2022_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: MEMO_PROGRAM_ID2, isSigner: false, isWritable: false },
];
const dataLayout = struct([u64("lpFeeAmount")]);
const data = Buffer.alloc(dataLayout.span);
dataLayout.encode(
{
lpFeeAmount,
},
data,
);
const aData = Buffer.from([...anchorDataBuf.collectCpFee, ...data]);
return new TransactionInstruction({
keys,
programId,
data: aData,
});
}
export function makeCollectCreatorFeeInstruction(
programId: PublicKey,
creator: PublicKey,
authority: PublicKey,
poolId: PublicKey,
configId: PublicKey,
vaultA: PublicKey,
vaultB: PublicKey,
mintA: PublicKey,
mintB: PublicKey,
ownerVaultA: PublicKey,
ownerVaultB: PublicKey,
mintProgramA: PublicKey,
mintProgramB: PublicKey,
): TransactionInstruction {
const keys: Array<AccountMeta> = [
{ pubkey: creator, isSigner: true, isWritable: false },
{ pubkey: authority, isSigner: false, isWritable: false },
{ pubkey: poolId, isSigner: false, isWritable: true },
{ pubkey: configId, isSigner: false, isWritable: false },
{ pubkey: vaultA, isSigner: false, isWritable: true },
{ pubkey: vaultB, isSigner: false, isWritable: true },
{ pubkey: mintA, isSigner: false, isWritable: false },
{ pubkey: mintB, isSigner: false, isWritable: false },
{ pubkey: ownerVaultA, isSigner: false, isWritable: true },
{ pubkey: ownerVaultB, isSigner: false, isWritable: true },
{ pubkey: mintProgramA, isSigner: false, isWritable: false },
{ pubkey: mintProgramB, isSigner: false, isWritable: false },
{ pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
];
return new TransactionInstruction({
keys,
programId,
data: anchorDataBuf.collectCreatorFee,
});
}
export function initializeWithPermission(
programId: PublicKey,
payer: PublicKey,
creator: PublicKey,
configId: PublicKey,
authority: PublicKey,
poolId: PublicKey,
mintA: PublicKey,
mintB: PublicKey,
lpMint: PublicKey,
payerVaultA: PublicKey,
payerVaultB: PublicKey,
payerLpAccount: PublicKey,
vaultA: PublicKey,
vaultB: PublicKey,
createPoolFeeAccount: PublicKey,
mintProgramA: PublicKey,
mintProgramB: PublicKey,
observationId: PublicKey,
permissionPda: PublicKey,
amountA: BN,
amountB: BN,
openTime: BN,
feeOn: FeeOn,
): TransactionInstruction {
const dataLayout = struct([u64("amountA"), u64("amountB"), u64("openTime"), u8("feeOn")]);
const keys: Array<AccountMeta> = [
{ pubkey: payer, isSigner: true, isWritable: false },
{ pubkey: creator, isSigner: false, isWritable: false },
{ pubkey: configId, isSigner: false, isWritable: false },
{ pubkey: authority, isSigner: false, isWritable: false },
{ pubkey: poolId, isSigner: false, isWritable: true },
{ pubkey: mintA, isSigner: false, isWritable: false },
{ pubkey: mintB, isSigner: false, isWritable: false },
{ pubkey: lpMint, isSigner: false, isWritable: true },
{ pubkey: payerVaultA, isSigner: false, isWritable: true },
{ pubkey: payerVaultB, isSigner: false, isWritable: true },
{ pubkey: payerLpAccount, isSigner: false, isWritable: true },
{ pubkey: vaultA, isSigner: false, isWritable: true },
{ pubkey: vaultB, isSigner: false, isWritable: true },
{ pubkey: createPoolFeeAccount, isSigner: false, isWritable: true },
{ pubkey: observationId, isSigner: false, isWritable: true },
{ pubkey: permissionPda, isSigner: false, isWritable: true },
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: mintProgramA, isSigner: false, isWritable: false },
{ pubkey: mintProgramB, 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(
{
amountA,
amountB,
openTime,
feeOn,
},
data,
);
return new TransactionInstruction({
keys,
programId,
data: Buffer.from([...anchorDataBuf.initializeWithPermission, ...data]),
});
}