Pump作为Solana的发币平台,每天有大量的新流动池被创建,本文提供了一个demo,教你如何狙击pump上的新流动池。主要内容包括:①基于geysergrpc监听pump新流动池创建;②获取买入和卖出新流动池代币所需要的账户;③基于Jito上链的买入;④卖出
Pump 作为 Solana 的发币平台,每天有大量的新流动池被创建,本文提供了一个 demo,教你如何狙击 pump 上的新流动池。主要内容包括:① 基于 geyser grpc 监听 pump 新流动池创建;② 获取买入和卖出新流动池代币所需要的账户;③ 基于 Jito 上链的买入;④ 卖出
<!--EndFragment-->
import "dotenv/config";
import Client, {
CommitmentLevel,
SubscribeRequest
} from '@triton-one/yellowstone-grpc';
import bs58 from "bs58";
import {
Connection,
PublicKey,
Transaction,
SystemProgram
} from "@solana/web3.js";
import {
AnchorProvider,
Program,
Wallet
} from "@coral-xyz/anchor";
import {
getKeypairFromEnvironment
} from "@solana-developers/helpers";
import fs from "fs";
import {
createAssociatedTokenAccountInstruction,
getAssociatedTokenAddress
} from "@solana/spl-token";
import {
BN
} from "bn.js";
import axios from "axios";
<!--StartFragment-->
为了保证获取链上数据的速度,本部分采用 geyser grpc 订阅的方法获取链上数据。
以下为订阅 pump 新池子的代码,主要步骤为:
<!--EndFragment-->
const client = new Client('https://grpc.chainbuff.com', undefined, { "grpc.max_receive_message_length": 64 * 1024 * 1024, // 64MiB }); const stream = await client.subscribe(); const streamClosed = new Promise<void>((resolve, reject) => { stream.on("error", (error) => { reject(error); stream.end(); }); stream.on("end", () => { resolve(); }); stream.on("close", () => { resolve(); }); }); stream.on("data", async (data) => { if (data.transaction && data.transaction.transaction.meta.logMessages && data.transaction.transaction.meta.logMessages.some(log => log.includes("Program log: Instruction: InitializeMint2"))) { console.log('slot:', data.transaction.slot); const accountKeys = data.transaction.transaction.transaction.message.accountKeys.map(ak => bs58.encode(ak)); console.log('Transaction signature:', bs58.encode(data.transaction.transaction.signature)); console.log('Mint:', accountKeys[1]); console.log('Bonding Curve:', accountKeys[3]); console.log('Associated Bonding Curve:', accountKeys[4]); console.log('---\n') } }); const request = { accounts: {}, slots: {}, transactions: {}, blocks: {}, blocksMeta: {}, entry: {}, commitment: CommitmentLevel.CONFIRMED, accountsDataSlice: [], ping: undefined, }; request.transactions.tx = { vote: false, failed: false, signature: undefined, accountInclude: ["6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"], // pump accountExclude: [], accountRequired: [], }; await new Promise<void>((resolve, reject) => { stream.write(request, (err) => { if (err === null || err === undefined) { resolve(); } else { reject(err); } }); }).catch((reason) => { console.error(reason); throw reason; }); await streamClosed;
输出应如下:
slot: 295023291 Transaction signature: 2HoK765u7TqoYUbDH8FL1MbuKqqV2gtRgoBuw3muoZh72hmowTmgRXxHRJB5fb3nv7D7xp3GwZCAbPJZHEmhCUw1 Mint: 29M9i98AVuWDHV4w1Bfodu9XT7D5y7GpL4zWd134pump Bonding Curve: HPrDgc4teTeVt1QWAJLMvKJsowgKXKzvUnWKVg3mEVha Associated Bonding Curve: 9cJRoqJVGr4SXp1TF6UfMG5scTDkh9MdVjvWGnuAGEoh --- slot: 295023297 Transaction signature: 63DDLJJ9E4gfzmPf8urUWWh3Zx4fGzbRcxCJMq884WBAxxRpHE16e2eWsp9yHJS7MaM3EgvYwBMg6QRaKD2pJxA7 Mint: FxuwwXaZGt41f1wZDBHQ7y282iw7FC7MzEjUn3dcpump Bonding Curve: 8fiNJQa8a8YWVm3rzkqBMV1xCnDKrfoWmivPpJr5cwRj Associated Bonding Curve: J9fh1SvH1voMSND9AeR4ZzSAAu4hRfMmRiizNxUUarZB ---
<!--StartFragment-->
买入操作需要与 pump 合约交互,首先我们需要 pump 合约的的 idl 文件
观察一笔 pump 的买入交易会发现,在调用 pump 合约的买入指令时,
<!--EndFragment-->
<!--StartFragment-->
因此,买入的交易可以按照下面的方法组装
<!--EndFragment-->
const payer = getKeypairFromEnvironment("PUMP_SECRET_KEY"); // 钱包私钥从本地.env文件中获取 console.log(payer.publicKey.toBase58()) const connection = new Connection('http\://127.0.0.1:8899', 'confirmed'); const wallet = new Wallet(payer); const provider = new AnchorProvider(connection, wallet, { commitment: 'confirmed', }); const pumpIDL = JSON.parse(fs.readFileSync('./pump_idl.json', 'utf8')); // 此处需要IDL文件 const pumpProgramId = new PublicKey('6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P'); const pumpProgram = new Program(pumpIDL, pumpProgramId, provider); // 创建交易 let transaction = new Transaction(); // 添加ATA创建指令 transaction.add( createAssociatedTokenAccountInstruction( payer.publicKey, associatedUser, payer.publicKey, new PublicKey(accountKeys\[1]), ) ) // 获取ATA const associatedUser = await getAssociatedTokenAddress(new PublicKey(accountKeys\[1]), payer.publicKey, false); // 添加pump买入指令 const amount = 17231 \* 1e6; const solAmount = 0.001 \* 1e9; transaction.add( await pumpProgram.methods .buy(new BN(amount.toString()), new BN(solAmount.toString())) .accounts({ global: new PublicKey('4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf'), feeRecipient: new PublicKey('CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM'), mint: new PublicKey(accountKeys\[1]), bondingCurve: new PublicKey(accountKeys\[3]), associatedBondingCurve: new PublicKey(accountKeys\[4]), associatedUser: associatedUser, user: payer.publicKey, systemProgram: new PublicKey('11111111111111111111111111111111'), tokenProgram: new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'), rent: new PublicKey('SysvarRent111111111111111111111111111111111'), eventAuthority: new PublicKey('Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1'), program: new PublicKey('6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P') }) .instruction() );
<!--StartFragment-->
至此,pump 新池子买入交易的组装其实就已经完成,通过对交易进行签名后,就可以正常发送。
此处可以在自己的 rpc 上模拟一下交易指令是否组装正确
<!--EndFragment-->
const { blockhash } = await connection.getLatestBlockhash(); transaction.recentBlockhash = blockhash; transaction.feePayer = payer.publicKey; const signedTransaction = await wallet.signTransaction(transaction); // simulate const simulationResult = await connection.simulateTransaction(signedTransaction); console.log(JSON.stringify(simulationResult));
输出如下,没有报错
{"context":{"apiVersion":"2.0.3","slot":295026886},"value":{"accounts":null,"err":null,"innerInstructions":null,"logs":\["Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke \[1]","Program log: Create","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke \[2]","Program log: Instruction: GetAccountDataSize","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1569 of 382633 compute units","Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success","Program 11111111111111111111111111111111 invoke \[2]","Program 11111111111111111111111111111111 success","Program log: Initialize the associated token account","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke \[2]","Program log: Instruction: InitializeImmutableOwner","Program log: Please upgrade to SPL Token 2022 for immutable owner support","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1405 of 376046 compute units","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke \[2]","Program log: Instruction: InitializeAccount3","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4188 of 372164 compute units","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success","Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 32307 of 400000 compute units","Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success","Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke \[1]","Program log: Instruction: Buy","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke \[2]","Program log: Instruction: Transfer","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 347555 compute units","Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success","Program 11111111111111111111111111111111 invoke \[2]","Program 11111111111111111111111111111111 success","Program 11111111111111111111111111111111 invoke \[2]","Program 11111111111111111111111111111111 success","Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke \[2]","Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2003 of 335467 compute units","Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success","Program data: vdt/007mYe5mbiGblezgN2DrBjE9HC+Ww3+vh6e5SKBBfQ/CypN13zNdCAAAAAAAwDEMAwQAAAABDEX33hExn+8SWHycXRZ2xxy10o60OnPy0sawSA80E8GrRAlnAAAAADOdYXMHAAAAQV1OEOGSAwAz8T13AAAAAEHFO8RPlAIA","Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 35954 of 367693 compute units","Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success"],"replacementBlockhash":null,"returnData":null,"unitsConsumed":68261}}
<!--StartFragment-->
使用 Jito 上链只需要①在交易的最后添加一笔给 jito tip 账户转账的指令,用于支付小费;②将交易发给 Jito 的 block engine
具体代码如下
<!--EndFragment-->
// 添加支付小费指令 transaction.add(SystemProgram.transfer({ fromPubkey: wallet.publicKey, toPubkey: new PublicKey('DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL'), lamports: 0.001\*1e9, })) const { blockhash } = await connection.getLatestBlockhash(); transaction.recentBlockhash = blockhash; transaction.feePayer = payer.publicKey; const signedTransaction = await wallet.signTransaction(transaction); // 发送交易 const serializedTransaction = signedTransaction.serialize(); const base58Transaction = bs58.encode(serializedTransaction); const bundle_data = { jsonrpc: "2.0", id: 1, method: "sendBundle", params: \[\[base58Transaction]] }; const bundle_resp = await axios.post(\`https\://frankfurt.mainnet.block-engine.jito.wtf/api/v1/bundles\`, bundle_data, { headers: { 'Content-Type': 'application/json' } }); const bundle_id = bundle_resp.data.result console.log(\`sent to frankfurt, bundle id: ${bundle_id}\`)
<!--StartFragment-->
观察一笔卖出的交易指令会发现,输入账户与买入相同,指令参数变为了卖出的代币数量和获得的最少 sol 数量。可参照之前的买入操作写自己的卖出策略。
<!--EndFragment-->
<!--StartFragment-->
卖出策略因人而异,不仅要保证自己获取链上数据的速度和上链的速度,要买的快,还要卖的好。但要问我哪个更重要,我想说,买的快不如卖的好。
<!--EndFragment-->
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!