import {
Connection,
PublicKey,
Transaction,
TransactionInstruction,
SystemProgram,
} from '@solana/web3.js';
import {
createAssociatedTokenAccountIdempotentInstruction,
createSyncNativeInstruction,
TOKEN_PROGRAM_ID,
} from '@solana/spl-token';
// Constants
const LAUNCHLAB_PROGRAM_ID = new PublicKey('9SkAtSxgNUMvT9bGb93v6rLU5MjW1XibykqoGtqT9dbg');
const WSOL_MINT = new PublicKey('So11111111111111111111111111111111111111112');
const GLOBAL_CONFIG = new PublicKey('6s1xP3hpbAfFoNtUNF8mfHsjr2Bd97JxFJRWLbL6aHuX');
const PLATFORM_CONFIG = new PublicKey('3pcjttVo7W1eTYFjTfBTrWKm1YmWU2RXY6GKND3svqYi');
const VAULT_AUTHORITY = new PublicKey('WLHv2UAZm6z4KyaaELi5pjdbJh6RESMva1Rnn8pJVVh');
async function buyTokensManually(
connection: Connection,
payer: PublicKey,
tokenMint: PublicKey,
amountIn: bigint, // Lamports to spend
minAmountOut: bigint // Minimum tokens to receive (slippage protection)
): Promise<Transaction> {
const transaction = new Transaction();
// 1. Derive all PDAs
const [poolState] = await PublicKey.findProgramAddress(
[Buffer.from('pool'), tokenMint.toBuffer(), WSOL_MINT.toBuffer()],
LAUNCHLAB_PROGRAM_ID
);
const [baseVault] = await PublicKey.findProgramAddress(
[Buffer.from('pool_vault'), poolState.toBuffer(), tokenMint.toBuffer()],
LAUNCHLAB_PROGRAM_ID
);
const [quoteVault] = await PublicKey.findProgramAddress(
[Buffer.from('pool_vault'), poolState.toBuffer(), WSOL_MINT.toBuffer()],
LAUNCHLAB_PROGRAM_ID
);
const [eventAuthority] = await PublicKey.findProgramAddress(
[Buffer.from('__event_authority')],
LAUNCHLAB_PROGRAM_ID
);
const [platformVault] = await PublicKey.findProgramAddress(
[PLATFORM_CONFIG.toBuffer(), WSOL_MINT.toBuffer()],
LAUNCHLAB_PROGRAM_ID
);
// Get pool state to find creator
const poolAccountInfo = await connection.getAccountInfo(poolState);
if (!poolAccountInfo) throw new Error('Pool not found');
// Parse creator from pool state (offset 280, 32 bytes)
const creator = new PublicKey(poolAccountInfo.data.slice(280, 312));
const [creatorVault] = await PublicKey.findProgramAddress(
[creator.toBuffer(), WSOL_MINT.toBuffer()],
LAUNCHLAB_PROGRAM_ID
);
// 2. Get user token accounts (ATAs)
const [userTokenAccount] = await PublicKey.findProgramAddress(
[payer.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), tokenMint.toBuffer()],
new PublicKey('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL')
);
const [userWsolAccount] = await PublicKey.findProgramAddress(
[payer.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), WSOL_MINT.toBuffer()],
new PublicKey('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL')
);
// 3. Add pre-instructions
transaction.add(
createAssociatedTokenAccountIdempotentInstruction(
payer,
userTokenAccount,
payer,
tokenMint
)
);
transaction.add(
createAssociatedTokenAccountIdempotentInstruction(
payer,
userWsolAccount,
payer,
WSOL_MINT
)
);
transaction.add(
SystemProgram.transfer({
fromPubkey: payer,
toPubkey: userWsolAccount,
lamports: amountIn,
})
);
transaction.add(createSyncNativeInstruction(userWsolAccount));
// 4. Build buy instruction
const discriminator = Buffer.from([250, 234, 13, 123, 213, 156, 19, 236]);
const amountInBuffer = Buffer.alloc(8);
amountInBuffer.writeBigUInt64LE(amountIn, 0);
const minAmountOutBuffer = Buffer.alloc(8);
minAmountOutBuffer.writeBigUInt64LE(minAmountOut, 0);
const shareFeeRateBuffer = Buffer.alloc(8);
shareFeeRateBuffer.writeBigUInt64LE(0n, 0);
const instructionData = Buffer.concat([
discriminator,
amountInBuffer,
minAmountOutBuffer,
shareFeeRateBuffer,
]);
const buyInstruction = new TransactionInstruction({
programId: LAUNCHLAB_PROGRAM_ID,
data: instructionData,
keys: [
{ pubkey: payer, isSigner: true, isWritable: true },
{ pubkey: VAULT_AUTHORITY, isSigner: false, isWritable: false },
{ pubkey: GLOBAL_CONFIG, isSigner: false, isWritable: false },
{ pubkey: PLATFORM_CONFIG, isSigner: false, isWritable: false },
{ pubkey: poolState, isSigner: false, isWritable: true },
{ pubkey: userTokenAccount, isSigner: false, isWritable: true },
{ pubkey: userWsolAccount, isSigner: false, isWritable: true },
{ pubkey: baseVault, isSigner: false, isWritable: true },
{ pubkey: quoteVault, isSigner: false, isWritable: true },
{ pubkey: tokenMint, isSigner: false, isWritable: true },
{ pubkey: WSOL_MINT, isSigner: false, isWritable: false },
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: eventAuthority, isSigner: false, isWritable: false },
{ pubkey: LAUNCHLAB_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
{ pubkey: platformVault, isSigner: false, isWritable: true },
{ pubkey: creatorVault, isSigner: false, isWritable: true },
],
});
transaction.add(buyInstruction);
return transaction;
}