# 狙击pump

Pump作为Solana上的一个代币公平发售平台，每天有大量的新流动池被创建，本文提供了一个demo，教你如何狙击pump上的新流动池。主要内容包括：① 基于geyser grpc监听pump新流动池创建；② 获取买入和卖出新流动池代币所需要的账户；③ 基于Jito上链的买入；④ 卖出

## 用到的库

```
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";
```

## 监听pump新流动池创建

为了保证获取链上数据的速度，本部分采用geyser grpc订阅的方法获取链上数据。

以下为订阅pump新池子的代码，主要步骤为：

* 创建grpc订阅的客户端
* 订阅交易中包含pump账户（6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P）的交易
* 判断日志中是否有InitializeMint2方法
* 打印一些新池子账户，包括代币Mint账户，Bonding Curve账户和Associated Bonding Curve账户，都是后面买入操作需要的

```
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
---
```

## 买入

买入操作需要与pump合约交互，首先我们需要pump合约的的idl文件，[在此获取](https://github.com/ChainBuff/solana-program-idl/blob/main/pump)

观察一笔pump的买入交易会发现，在调用pump合约的买入指令时，

* 输入账户1，2，8，9，10，11，12是固定的；3，4，5从刚才监听到的新池子创建交易中已经获取到；6和7分别是ATA和我们的买入账户
* 指令参数分别是买入的代币数量和最大的sol花费

<figure><img src="/files/fJajrvcXvjCdTBHJPzEb" alt=""><figcaption></figcaption></figure>

因此，买入的交易可以按照下面的方法组装

* 创建交易
* 添加ATA创建指令
* 添加pump买入指令

```
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
const associatedUser = await getAssociatedTokenAddress(new PublicKey(accountKeys[1]), payer.publicKey, false);

// 添加ATA创建指令
transaction.add(
    createAssociatedTokenAccountInstruction(
        payer.publicKey,
        associatedUser,
        payer.publicKey,
        new PublicKey(accountKeys[1]),
    )
)

// 添加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()
);
```

至此，pump新池子买入交易的组装其实就已经完成，通过对交易进行签名后，就可以正常发送。

此处可以在自己的rpc上模拟一下交易指令是否组装正确

```
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));
```

输出如下，没有报错

{% code overflow="wrap" %}

```
{"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}}
```

{% endcode %}

## Jito发送交易

使用Jito上链只需要①在交易的最后添加一笔给jito tip账户转账的指令，用于支付小费；②将交易发给Jito的block engine

具体代码如下

```
// 添加支付小费指令
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}`)
```

成功的买入示例交易可以在此查看：<https://solscan.io/tx/3SsYxUY5F9w2Wk6APMSEGbSz7Yw13tYrRax2PECk1yF6XsTXVWuG2jQLwxCaJxdRN9MhewwZGcSpv58qMwdmLyie>

## 卖出

观察一笔卖出的交易指令会发现，输入账户与买入相同，指令参数变为了卖出的代币数量和获得的最少sol数量。可参照之前的买入操作写自己的卖出策略。

<figure><img src="/files/3wvyekDm3FyJmtDEf7Ml" alt=""><figcaption></figcaption></figure>

**卖出策略因人而异，不仅要保证自己获取链上数据的速度和上链的速度，要买的快，还要卖的好。但要问我哪个更重要，我想说，买的快不如卖的好。**


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://chainbuff.gitbook.io/tutorials/solana/lian-shang-ce-le/ju-ji-pump.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
