Skip to content

Instantly share code, notes, and snippets.

@nshen
Created February 6, 2025 03:06
Show Gist options
  • Save nshen/ec1240f9283457a972ee3afb8a792426 to your computer and use it in GitHub Desktop.
Save nshen/ec1240f9283457a972ee3afb8a792426 to your computer and use it in GitHub Desktop.
listen-buy.ts
/*
.env file:
# https://quicknode.com/
HTTP_PROVIDER=https://magical-thrumming-firefly.solana-mainnet.quiknode.pro/<API_KEY>
WSS_PROVIDER=wss://magical-thrumming-firefly.solana-mainnet.quiknode.pro/<API_KEY>
run:
tsx --env-file=.env ./listen-buy.ts
*/
import { Connection, LAMPORTS_PER_SOL, PublicKey, clusterApiUrl } from "@solana/web3.js";
const PUMP_PROGRAM = new PublicKey("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P");
interface CreateEventData {
name: string;
symbol: string;
uri: string;
mint: PublicKey;
bondingCurve: PublicKey;
user: PublicKey;
}
type TradeEventType = {
mint: string;
solAmount: bigint;
tokenAmount: bigint;
isBuy: boolean;
user: string;
timestamp: bigint;
virtualSolReserves: bigint;
virtualTokenReserves: bigint;
}
// 解析 TradeEvent
function parseTradeEvent(buffer: Buffer): TradeEventType | null {
// TradeEvent 结构:
// mint: publicKey (32 bytes)
// solAmount: u64 (8 bytes)
// tokenAmount: u64 (8 bytes)
// isBuy: bool (1 byte)
// user: publicKey (32 bytes)
// timestamp: i64 (8 bytes)
// virtualSolReserves: u64 (8 bytes)
// virtualTokenReserves: u64 (8 bytes)
if (buffer.length < 8) {
return null
}
let offset = 8;
const mint = new PublicKey(buffer.slice(offset, offset + 32)).toString();
offset += 32;
const solAmount = buffer.readBigUInt64LE(offset);
offset += 8;
const tokenAmount = buffer.readBigUInt64LE(offset);
offset += 8;
const isBuy = buffer.readUInt8(offset) === 1;
offset += 1;
const user = new PublicKey(buffer.slice(offset, offset + 32)).toString();
offset += 32;
const timestamp = buffer.readBigInt64LE(offset);
offset += 8;
const virtualSolReserves = buffer.readBigUInt64LE(offset);
offset += 8
const virtualTokenReserves = buffer.readBigUInt64LE(offset);
return {
mint,
solAmount,
tokenAmount,
isBuy,
user,
timestamp,
virtualSolReserves,
virtualTokenReserves
}
}
let count = 0
function displayTradeEvent(event: TradeEventType) {
if (count === 0) {
setTimeout(() => {
// 统计次数
console.log('20 seconds passed:', count); //600 左右
}, 20000);
}
count++
const date = new Date(Number(event.timestamp) * 1000).toLocaleString()
// spl tokens : 9 decimals
// pump.fun tokens: 6 decimals
const solReserves = Number(event.virtualSolReserves) / Number(LAMPORTS_PER_SOL);
const tokenReserves = Number(event.virtualTokenReserves) / (10 ** 6);
const price = (solReserves / tokenReserves).toFixed(10);
const formattedEvent = {
// 'Event Type': event.isBuy ? 'Buy' : 'Sell',
'Mint': event.mint.toString(),
'SOL Amount': (Number(event.solAmount) / Number(LAMPORTS_PER_SOL)).toFixed(10),
'Token Amount': event.tokenAmount.toString(),
'Price': price.toString(),
'User': event.user.toString(),
'Timestamp': date, // 使用正确转换的日期
// 'Virtual SOL Reserves': event.virtualSolReserves.toString(),
// 'Virtual Token Reserves': event.virtualTokenReserves.toString()
};
const icon = event.isBuy ? '🛒' : '💰';
const eventType = event.isBuy ? 'Buy' : 'Sell';
console.log(`============== ${icon} New ${eventType} Event: ====================`);
console.table(formattedEvent);
}
const tokenMap = {};
function analyzeLogs(logs: string[], signature: string) {
if (!logs.some(log => log === 'Program log: Instruction: Buy')) return;
// console.log(logs);
const dataLog = logs.find(log => log.startsWith('Program data:'));
if (!dataLog) return;
// console.log(dataLog);
const base64Data = dataLog.split('Program data: ')[1];
const decodedData = Buffer.from(base64Data, 'base64');
const tradedata = parseTradeEvent(decodedData)
if (!tradedata) return;
displayTradeEvent(tradedata)
// tokenMap[tradedata.mint] = {
// count: tokenMap[tradedata.mint] ? tokenMap[tradedata.mint].count + 1 : 1,
// }
//
// console.table(tokenMap);
}
function main() {
const connection = new Connection(
process.env.HTTP_PROVIDER as string,
{
wsEndpoint: process.env.WSS_PROVIDER as string,
commitment: "confirmed"
})
connection.onLogs(
PUMP_PROGRAM,
({ logs, err, signature }) => {
if (err)
return;
if (!logs || logs.length === 0)
return;
if (!signature)
return;
analyzeLogs(logs, signature)
},
"confirmed"
);
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment