Created
February 6, 2025 03:06
-
-
Save nshen/ec1240f9283457a972ee3afb8a792426 to your computer and use it in GitHub Desktop.
listen-buy.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
.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