// Live trades in your terminal. // // npm run tape pump.fun and PumpSwap trades of 0.01 SOL or more (smaller ones are mostly volume bots) // npm run tape -- 1 only trades of 1 SOL or more // npm run tape -- 0 every single trade // // It reads OScope's firehose when OScope is running on this computer, otherwise the stream itself. import WebSocket from 'ws'; import { config } from '../src/config.mjs'; const minSol = Math.max(0, Number(process.argv[2] ?? process.env.MIN_SOL ?? 0.01) || 0); const local = `ws://127.0.0.1:${config.port}/firehose?pools=pump,pump-amm`; const c = { g: s => `\x1b[32m${s}\x1b[0m`, r: s => `\x1b[31m${s}\x1b[0m`, d: s => `\x1b[2m${s}\x1b[0m`, b: s => `\x1b[1m${s}\x1b[0m`, y: s => `\x1b[33m${s}\x1b[0m` }; let usd = 0; const price = () => fetch('https://api.coinbase.com/v2/prices/SOL-USD/spot', { signal: AbortSignal.timeout(4000) }).then(r => r.json()).then(j => { usd = +j.data.amount || usd; }).catch(() => {}); setInterval(price, 30000).unref(); const money = v => (v >= 1e6 ? (v / 1e6).toFixed(2) + 'M' : v >= 1e3 ? (v / 1e3).toFixed(1) + 'K' : v.toFixed(0)); let shown = 0, seen = 0; function open(url, fallback) { const ws = new WebSocket(url); let ok = false; ws.on('open', () => { ok = true; console.log(c.d(`reading ${url.split('?')[0]}${minSol ? `, trades of ${minSol} SOL or more` : ''} (Ctrl+C to stop)\n`)); }); ws.on('message', buf => { let f; try { f = JSON.parse(buf.toString()); } catch { return; } if ((f.pool !== 'pump' && f.pool !== 'pump-amm') || (f.action !== 'buy' && f.action !== 'sell' && f.action !== 'create' && f.action !== 'migrate')) return; seen++; const t = new Date(f.timestamp || Date.now()).toTimeString().slice(0, 8); const sym = String(f.symbol || '').slice(0, 12).padEnd(12); if (f.action === 'create') return console.log(`${c.d(t)} ${c.y('NEW ')} ${c.b(sym)} ${String(f.name || '').slice(0, 40)} ${c.d(f.mint)}`); if (f.action === 'migrate') return console.log(`${c.d(t)} ${c.y('MIGR')} ${c.b(sym)} moved to PumpSwap ${c.d(f.mint)}`); const sol = +f.quoteAmount || 0; if (sol < minSol) return; shown++; const side = f.action === 'buy' ? c.g('BUY ') : c.r('SELL'); const mc = usd && f.marketCapQuote ? '$' + money(f.marketCapQuote * usd) : (f.marketCapQuote || 0).toFixed(0) + ' SOL'; console.log(`${c.d(t)} ${side} ${sol.toFixed(3).padStart(9)} SOL ${c.b(sym)} MC ${mc.padEnd(8)} ${c.d(f.pool === 'pump' ? 'curve' : 'swap ')} ${c.d(String(f.txSigner || '').slice(0, 6) + '…')}`); }); ws.on('close', () => { if (!ok && fallback) return open(fallback, null); console.log(c.d('\nstream closed, reopening in 3 s')); setTimeout(() => open(url, null), 3000); }); ws.on('error', () => {}); } process.on('SIGINT', () => { console.log(c.d(`\n${seen.toLocaleString('en-US')} trades seen, ${shown.toLocaleString('en-US')} shown`)); process.exit(0); }); price().then(() => open(local, config.feedUrl));