Pump.fun代币迁移实时监视

本文介绍如何使用Shyft gRPC监控从Pump.fun到Raydium的代币迁移。

Pump.fun代币迁移实时监视
一键发币: SUI | SOL | BNB | ETH | BASE | ARB | OP | POLYGON | AVAX | FTM | OK

Pumpfun完成其债券曲线活动后,代币被迁移到Raydium进行交易。使用gRPC可以更轻松地识别已迁移并正在Raydium上交易的代币。

通过本文末尾,您将学会如何使用gRPC和Shyft API流式传输从Pump.fun迁移到Raydium的代币。

1、开始之前

在开始构建之前,请注册并获取Shyft RPC/API和gRPC令牌访问权限。

gRPC服务不直接支持Web浏览器,因此您需要一个后端应用程序来处理gRPC数据。虽然此示例使用Node.js,但您可以根据自己的偏好选择多种服务器端语言,包括C#、Go、Java、Kotlin、Python或PHP。

在这篇文章中,我们将查看如何使用gRPC获取Raydium上代币的价格更新。我们将涵盖以下步骤:

  • 设置gRPC连接
  • 跟踪Pumpfun上已完成的债券曲线
  • 反序列化我们的Pumpfun数据
  • 使用Defi API获取流动性详情
  • 结论
本文所有相关代码均可在我们的 GitHub Replit 上找到。欢迎您克隆它并跟随操作。

2、设置gRPC连接

要开始流式传输,您需要配置gRPC URL访问令牌

const client = new Client(  
    '您的区域特定Shyft gRPC URL',  
    'Shyft gRPC访问令牌',  
    undefined,  
  );

现在开始流式传输!

3、跟踪Pumpfun上已完成的债券曲线

我们需要基于我们建立的逻辑最终确定Pumpfun上的债券曲线。只有已完成的债券曲线才有资格迁移到Raydium并进行交易。为了过滤相关数据,我们使用memcmp以确保只检索已完成的债券曲线。

const req: SubscribeRequest = {  
  slots: {},  
  accounts: {  
    pumpfun: {  
      account: [],  
      filters: [  
        {  
          memcmp: {  
            offset: structure.offsetOf('complete').toString(),  
            bytes: Uint8Array.from([1]),  
          },  
        },  
      ],  
      owner: [pumpfun], //pump-fun程序ID  
    },  
  },  
  transactions: {},  
  blocks: {},  
  blocksMeta: {  
    block: [],  
  },  
  accountsDataSlice: [],  
  commitment: CommitmentLevel.PROCESSED,  
  entry: {},  
  transactionsStatus: {},  
};

4、gRPC请求的关键组件

让我们分解这个请求的主要部分:

  1. 账户过滤器:这里的关键过滤器是memcmp过滤器,它检查代币的“完成”状态。这有助于识别在Pump.fun上完成其债券曲线活动并准备迁移到Raydium的代币。
  • offset指定账户结构中完成状态的位置。使用structure.offsetOf('complete')确保我们基于代币的最终状态进行过滤。
  • bytes过滤器与Uint8Array.from([1])一起查找值1,表示债券曲线活动已完成。

2. 程序所有者owner字段指定Pumpfun程序ID或Raydium程序ID。这确保我们只订阅与迁移到Raydium相关的事件。

3. 提交级别CommitmentLevel.PROCESSED设置允许您订阅已处理块,这确保您可以实时接收交易和代币迁移的更新。

4. 交易和区块:通过订阅这些字段,您可以跟踪代币的持续活动,允许您监控与其迁移和交易相关的实时事件。

当我们console.log数据变量时,我们应该期望输出如下格式

filters: [ 'pumpfun' ],  
account: {  
  account: {  
     pubkey: <Buffer fc 97 83 0f e5 17 be a3 5b b8 40 7a 09 41 30 4a 07 f0 53 8f 4b 76 8e 1c d4 31 1b ee b5 8d 1a 22>,  
     lamports: '85006591115',  
     owner: <Buffer 01 56 e0 f6 93 66 5a cf 44 db 15 68 bf 17 5b aa 51 89 cb 97 f5 d2 ff 3b 65 5d 2b b6 fd 6d 18 b0>,  
     executable: false,  
     rentEpoch: '18446744073709551615',  
     data: <Buffer 17 b7 f8 37 60 d8 ac 60 00 98 12 4c 91 fe 00 00 5b 84 da c6 1a 00 00 00 00 00 00 00 00 00 00 00 5b d8 b6 ca 13 00 00 00 00 80 c6 a4 7e 8d 03 00 01>,  
     writeVersion: '1536398957277',  
     txnSignature: <Buffer 3c 9f 98 aa 21 1e a5 31 fb 9c ae a8 6c 53 df 6d 4a e0 6c d5 bf 2e fa a3 56 48 be 00 b1 ef 23 c3 46 3b 76 72 af 22 28 e1 e0 b9 57 04 d8 59 9b 97 8b 38 ... 14 more bytes>  
  },  
  slot: '300981652',  
  isStartup: false  
},  
  slot: undefined,  
  transaction: undefined,  
  block: undefined,  
  ping: undefined,  
  pong: undefined,  
  blockMeta: undefined,  
  entry: undefined  
}

5、反序列化Pump.fun数据

我们将逐步了解如何使用提供的代码解码Pumpfun交易。交易数据是以二进制格式存在的,我们将使用模拟数据布局的结构对其进行解码。

5.1 导入所需库

我们首先导入所需的库:

import base58 from "bs58";  
import { struct, bool, u64, Layout } from "@coral-xyz/borsh";
  • base58用于处理常用的Solana交易的base58编码。
  • @coral-xyz/borsh是一个强大的二进制序列化/反序列化库,我们将使用它定义和解码交易数据的结构。

5.2 定义数据结构

我们使用borsh中的struct函数定义债券曲线交易的数据结构:

export const structure = struct([  
  u64("discriminator"),  
  u64("virtualTokenReserves"),  
  u64("virtualSolReserves"),  
  u64("realTokenReserves"),  
  u64("realSolReserves"),  
  u64("tokenTotalSupply"),  
  bool("complete"),  
]);

以下是字段的分解:

  • discriminator:数据结构的独特标识符。
  • virtualTokenReserves:代币的虚拟储备。
  • virtualSolReserves:以Solana(SOL)形式的虚拟储备。
  • realTokenReserves:代币的真实储备。
  • realSolReserves:以SOL形式的真实储备。
  • tokenTotalSupply:代币的总供应量。
  • complete:一个布尔值,指示债券曲线过程是否已完成。

每个字段都映射到特定类型,例如u64(用于无符号64位整数)和bool(用于布尔值)。这确保了二进制数据能够正确解释。

5.3 解码交易数据

接下来,我们定义一个名为bondingCurveData的函数,该函数基于结构解码交易缓冲区:

export function bondingCurveData(buffer: Buffer) {  
  let value = structure.decode(buffer);  
  const discriminator = BigInt(value.discriminator);  
  const virtualTokenReserves = BigInt(value.virtualTokenReserves);  
  const virtualSolReserves = BigInt(value.virtualSolReserves);  
  const realTokenReserves = BigInt(value.realTokenReserves);  
  const realSolReserves = BigInt(value.realSolReserves);  
  const tokenTotalSupply = BigInt(value.tokenTotalSupply);  
  const complete = value.complete;
  return {  
    discriminator,  
    virtualTokenReserves,  
    virtualSolReserves,  
    realTokenReserves,  
    realSolReserves,  
    tokenTotalSupply,  
    complete  
  };  
}

解码的工作原理:

  • 输入:该函数接受一个Buffer作为输入,这是原始交易数据。
  • 结构解码:我们使用structure.decode(buffer)将原始二进制数据解码为基于我们之前定义的字段的结构化对象。
  • BigInt转换u64字段解析为BigInt以处理可能不适合标准JavaScript数字类型的大型值。
  • 布尔值处理complete字段是一个简单的布尔值,指示债券曲线过程是否已完成。

5.4 处理编码数据(Base58解码)

在某些情况下,交易数据可能是Base58编码的。我们可以先解码此数据,然后再将其传递给bondingCurveData函数。以下decodeTransact函数执行此任务:

export function decodeTransact(data) {  
  const output = base58.encode(Buffer.from(data, 'base64'));  
  return output;  
}

此函数接受base64编码的字符串(通常是传递交易数据的方式),将其转换为Buffer,然后将其编码为Base58。解码后,交易数据可以传递给bondingCurveData函数进行进一步处理。

这是完整的代码:

import base58 from "bs58";  
import { struct, bool, u64, Layout } from "@coral-xyz/borsh";
export const structure = struct([  
    u64("discriminator"),  
    u64("virtualTokenReserves"),  
    u64("virtualSolReserves"),  
    u64("realTokenReserves"),  
    u64("realSolReserves"),  
    u64("tokenTotalSupply"),  
    bool("complete"),  
  ]);export function decodeTransact(data){  
    const output = base58.encode(Buffer.from(data,'base64'))  
    return output;  
}  
export function  bondingCurveData(buffer: Buffer) {    let value = structure.decode(buffer);  
    const discriminator = BigInt(value.discriminator);  
    const virtualTokenReserves = BigInt(value.virtualTokenReserves);  
    const virtualSolReserves = BigInt(value.virtualSolReserves);  
    const realTokenReserves = BigInt(value.realTokenReserves);  
    const realSolReserves = BigInt(value.realSolReserves);  
    const tokenTotalSupply = BigInt(value.tokenTotalSupply);  
    const complete = value.complete;  
    return {  
        discriminator,  
        virtualTokenReserves,  
        virtualSolReserves,  
        realTokenReserves,  
        realSolReserves,  
        tokenTotalSupply,  
        complete  
    };  
  }

我们的编码结果应如下所示

{  
  signature: null,  
  pubKey: 'DmqJvcKbiH8L1yaFwxzLJQD7z1HrCMSAoWFs3xwEhybA',  
  owner: '6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P',  
  poolstate: {  
    discriminator: 6966180631402821399n,  
    virtualTokenReserves: 0n,  
    virtualSolReserves: 0n,  
    realTokenReserves: 0n,  
    realSolReserves: 0n,  
    tokenTotalSupply: 1000000000000000n,  
    complete: true  
  }  
}

6、使用DeFi API获取流动性详情

Shyft的DeFi API是一种API服务,聚合了各种去中心化交易所(DEX)的数据。通过其get_by_pair端点,您可以获取与代币对关联的流动性池详情。

以下是JavaScript中的函数:

export async function getTokenInfo(address) {  
  // 构造Shyft的API URL,使用提供的代币地址和Sol作为代币B  
  const url = `https://defi.shyft.to/v0/pools/get_by_pair?tokenA=${address}&tokenB=sol`;
  // 发出API请求以获取池数据  
  const response = await fetch(url, requestOptions);  
  const data = await response.json();  // 从响应中提取相关信息  
  const dexes = data?.result?.dexes;  
  const raydium = dexes?.raydiumAmm?.pools[0];  // 进一步提取Raydium池数据的各个属性  
  const pubKey = raydium?.pubkey;  
  const baseVault = raydium?.baseVault;  
  const quoteVault = raydium?.quoteVault;  
  const lp = raydium?.lpMint;  
  const owner = raydium?.owner;  // 以结构化格式返回提取的数据  
  return {  
    pubKey,  
    baseVault,  
    quoteVault,  
    lp,  
    owner  
  };  
}

7、实时监控迁移代币事件

下面的代码的主要目标是实时监控迁移的代币并提供有关流动性池债券曲线状态的重要详细信息。具体来说,该脚本监控PumpFun代币,并在债券曲线完成且已迁移到Pumpfun时获取更新。

stream.on("data", async (data) => {  
    try{  
    const result = await tOutPut(data);  
    if(!result) return;  
    const tokenInfo = await getTokenBalance(result.pubKey);  
    const poolInfo = await getTokenInfo(tokenInfo?.ca);  
    if(poolInfo.lp === undefined) return;  
    console.log(  
      `  
      PUMPFUN -- RAYDIUM  
      CA : ${tokenInfo?.ca}  
      Name : ${tokenInfo?.name} (${tokenInfo?.symbol})  
      POOL DETAILS : Base Vault ${poolInfo?.baseVault}  
                     Quote Vault ${poolInfo?.quoteVault}  
                     Public Key ${poolInfo?.pubKey}  
                     LP Mint ${poolInfo?.lp}  
      BONDING CURVE STATUS : COMPLETED                      
      `  
   )

我们将更新stream.on函数以适应我们的请求

我们的结果应为以下格式

PUMPFUN -- RAYDIUM  
      CA : 4wFZ2by5RWPrck2TBrgpjDpA6FRuNt4Hr8zD2GWyUCVh  
      Name : Chichi (Chichi)  
      POOL DETAILS : Base Vault 9LsYe4HuGBaZMjQZiadgfgN5CWMqY7KSoZp2XoFic1Ns   
                     Quote Vault EAS5XB5NnqSPDPcMNJTNpfYKnDbWG4RYEfebyKjYhsCk  
                     Public Key EbEQF3PtZxE2WSm4vvsiHsBngjzLbesndXnadNBpagDg   
                     LP Mint 2i4BM7e8uTa95fEvq5UNwPDtA2DStfVgdiB1pBwjBo1y      
      BONDING CURVE STATUS : COMPLETED
      PUMPFUN -- RAYDIUM  
      CA : 9Jh1TuT4hat9DW2oJikrikn8R8dwxuFqJZgD1Xx3pump  
      Name : Unknown Token (Token)  
      POOL DETAILS : Base Vault APdNU7jtC6MDjZVhoy9uX9sWmyPiQ3fFhtFiX5vtSivy  
                     Quote Vault 4zwqJM5RhndH3a9j9tzzjYh771KNYh4JhmEyQ3YSFuER  
                     Public Key FEJmFht44kdSuTctSyUhkp8Mp7SuJ5zngcpyAAzH8EFf  
                     LP Mint f3PBsht2jJ2fvt9Wn3NNEVGf7K6vYdNWGG3euFPWv9w  
      BONDING CURVE STATUS : COMPLETED

8、结束语

本质上,我们的方法涉及获取在Raydium去中心化交易所上交易的代币,这些代币已从Pumpfun迁移过来。我们利用了Shyft的DeFi API和功能强大的gRpc工具来访问实时区块链数据。


原文链接:How to track token transfers from Pump.fun to Raydium

DefiPlot翻译整理,转载请标明出处

免责声明:本站资源仅用于学习目的,也不应被视为投资建议,读者在采取任何行动之前应自行研究并对自己的决定承担全部责任。
通过 NowPayments 打赏