聪明钱监控
聪明钱跟单指监听链上胜率高的地址后跟随买入和卖出,本文提供了一个简单的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机器人,实时的接收通知消息。
最后更新于