聪明钱监控

聪明钱跟单指监听链上胜率高的地址后跟随买入和卖出,本文提供了一个简单的demo,教你如何监控聪明钱地址。主要内容包括:① 基于geyser grpc监听聪明钱包地址与pump和raydium交互的交易;② 解析交易中的余额变动

用到的库

import "dotenv/config";
import Client, {CommitmentLevel, SubscribeRequest} from '@triton-one/yellowstone-grpc';
import bs58 from "bs58";
import {Connection, PublicKey, LAMPORTS_PER_SOL} from "@solana/web3.js";
import{ Metadata, deprecated } from "@metaplex-foundation/mpl-token-metadata";

监听包含聪明钱账户的交易

本部分使用geyser grpc订阅的方式获取链上与聪明钱地址有关的交易,并再次过滤了一下聪明钱地址与pump和raydium合约交互的交易(因为此地址可能会有一些其他类型的交易,例如此处未考虑在内的转账交易等)

因为聪明钱的交易频率不高,所以此处所指的聪明钱其实是一个高频交易的pump狙击,经常可以做到+0和+1冲开盘

const addr = ['orcACRJYTFjTeo2pV8TfYRTpmqfoYgbVi9GeANXTCc8'] // 聪明钱地址

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) {
        const accountKeys = data.transaction.transaction.transaction.message.accountKeys.map(ak => bs58.encode(ak));
        if (accountKeys.includes('6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P') || accountKeys.includes('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8')) {
        
		        // 解析余额变动
            checkBalances(data)
        }
    }
});

// 配置订阅
const request = {
    accounts: {},
    slots: {},
    transactions: {},
    blocks: {},
    blocksMeta: {},
    entry: {},
    commitment: CommitmentLevel.CONFIRMED,
    accountsDataSlice: [],
    ping: undefined,
};

request.transactions.tx = {
    vote: false,
    failed: false,
    signature: undefined,
    accountInclude: addr,
    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;

这样就监听过滤出了所有聪明钱地址跟pump和raydium交互的交易,后续通过一个checkBalances函数来解析余额变动

解析余额变动

先来看一笔pump买入的交易示例,主要关注两部分:

  • solana余额的变化

  • 聪明钱账户代币余额的变化

可以看到这笔交易实际总花费2.545549387个sol买入了80,144,432.9898个某代币,所以我们的checkBalances函数先打印一下这两部分

async function checkBalances (data) {

    // sol balance
    console.log('preBalances', data.transaction.transaction.meta.preBalances)
    console.log('postBalances', data.transaction.transaction.meta.postBalances)

    // token balance
    console.log('preTokenBalances', data.transaction.transaction.meta.preTokenBalances)
    console.log('postTokenBalances', data.transaction.transaction.meta.postTokenBalances)

    console.log('---\n')
}

一个示例的输出应如下,preBalances 和 postBalances 的首个元素为此账户sol余额的变动,preTokenBalances 和 postTokenBalances 为此笔交易中账户代币余额的变化,代币余额变化我们只关注owner为此聪明钱地址的部分

preBalances [
  '32562846002', '0',
  '65832298',    '281867236367207',
  '2039280',     '501231920',
  '1',           '1141440',
  '1',           '1009200',
  '934087680',   '8530000',
  '731913600',   '1461600',
  '0'
]
postBalances [
  '30017296615', '2039280',
  '77832298',    '281867261431207',
  '2039280',     '3007631920',
  '1',           '1141440',
  '1',           '1009200',
  '934087680',   '8530000',
  '731913600',   '1461600',
  '0'
]
preTokenBalances [
  {
    accountIndex: 4,
    mint: 'CdUVc4xQ3trWvksxyAcu22exniWxVARdrWQTPF6Qpump',
    uiTokenAmount: {
      uiAmount: 982409836.065574,
      decimals: 6,
      amount: '982409836065574',
      uiAmountString: '982409836.065574'
    },
    owner: 'HRAWGWZ86FBGdQCjoG27psb49cbFBRWN3LVwhQ8QXEBp',
    programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'
  }
]
postTokenBalances [
  {
    accountIndex: 1,
    mint: 'CdUVc4xQ3trWvksxyAcu22exniWxVARdrWQTPF6Qpump',
    uiTokenAmount: {
      uiAmount: 80144432.9898,
      decimals: 6,
      amount: '80144432989800',
      uiAmountString: '80144432.9898'
    },
    owner: 'orcACRJYTFjTeo2pV8TfYRTpmqfoYgbVi9GeANXTCc8',
    programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'
  },
  {
    accountIndex: 4,
    mint: 'CdUVc4xQ3trWvksxyAcu22exniWxVARdrWQTPF6Qpump',
    uiTokenAmount: {
      uiAmount: 902265403.075774,
      decimals: 6,
      amount: '902265403075774',
      uiAmountString: '902265403.075774'
    },
    owner: 'HRAWGWZ86FBGdQCjoG27psb49cbFBRWN3LVwhQ8QXEBp',
    programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'
  }
]

所以,完整的checkBalances函数应该如下

interface TokenAccount {
    accountIndex: number;
    mint: string;
    uiTokenAmount: {
        uiAmount: number;
        decimals: number;
        amount: string;
        uiAmountString: string;
    };
    owner: string;
    programId: string;
}

async function checkBalances (data) {

    console.log('slot:', data.transaction.slot);
    console.log(`https://solscan.io/tx/${bs58.encode(data.transaction.transaction.signature)}`);

    // sol balance
    // console.log('preBalances', data.transaction.transaction.meta.preBalances)
    // console.log('postBalances', data.transaction.transaction.meta.postBalances)
    const preBalance = data.transaction.transaction.meta.preBalances[0]
    const postBalance = data.transaction.transaction.meta.postBalances[0]
    const balanceChange = (postBalance - preBalance)/LAMPORTS_PER_SOL
    console.log(balanceChange, 'sol')

    // token balance
    // console.log('preTokenBalances', data.transaction.transaction.meta.preTokenBalances)
    // console.log('postTokenBalances', data.transaction.transaction.meta.postTokenBalances)
    const preTokenBalances: TokenAccount[] = data.transaction.transaction.meta.preTokenBalances
    const postTokenBalances: TokenAccount[] = data.transaction.transaction.meta.postTokenBalances
    for (const postTokenBalance of postTokenBalances) {
        if (addr.includes(postTokenBalance.owner)) {
						
            const mint = postTokenBalance.mint;
            const postTokenAmount= postTokenBalance.uiTokenAmount.uiAmount;
            const preTokenAmount = preTokenBalances.find(preBalance => preBalance.owner === postTokenBalance.owner && preBalance.mint === mint)?.uiTokenAmount.uiAmount || 0;
            const tokenBalanceChange = postTokenAmount - preTokenAmount;
						
	    // 此处获取代币名称
            let metadataPda = await deprecated.Metadata.getPDA(new PublicKey(mint));
            let metdadataContent =  await Metadata.fromAccountAddress(connection, metadataPda);
            const tokenName = metdadataContent.data.name

            console.log(tokenBalanceChange, tokenName, mint)
        }
    }

    console.log('---\n')
}

关于买入和卖出可以通过sol和代币余额的正负来判断,如上面输出是1笔买单和4笔卖单。

最后,监控到聪明钱后,可以根据自己的策略买入和卖出,也可以将日志消息推送给telegram机器人,实时的接收通知消息。

最后更新于