本文手把手教你用新版 Solana Web3.js 2.0 和 WebSocket 订阅实时监控任意 Solana 账户余额变动,附完整 TypeScript 示例与环境配置。
概述:为什么升级 Solana Web3.js 2.0
最新的 Solana Web3.js 2.0 带来了更健壮的 WebSocket 订阅系统,显著提升:
- 类型安全:全程 TypeScript 泛型约束,减少运行时错误。
- 现代异步迭代:用
for await...of代替旧版回调,代码更优雅。 - 中止控制器:原生支持 AbortController 清理订阅资源。
- 精细化错误 与 API 计费透明。
你将在本指南完成:
- 建立稳定 WebSocket 连接。
- 订阅关注账户并格式化余额变化。
- 优雅中断连接,避免额外 API 积分消耗。
- 提取可复用的监控模板。
你将需要
- Node.js ≥ 20.0(对 事件循环优化 更友好)
- npm 或 yarn
- TypeScript、ts-node
新旧差异对比:1.0 vs 2.0
| 维度 | v1.x | v2.0 |
|---|---|---|
| API 风格 | 回调地狱 | AsyncIterable |
| 错误处理 | 单一 throw | 多粒度 Error 类型 |
| 资源清理 | 手动 close | 内置 AbortSignal |
| 类型 | 任意 any | 严格 Address, Commitment |
五步部署实战
以下示例以 Pump.fun 费用账户 为例,亦可替换为你想追踪的任意地址。
1. 初始化项目
mkdir solana-sub-v2 && cd solana-sub-v2
npm init -y
npm install @solana/web3.js@2
npm install -D typescript ts-node @types/node
tsc --init在生成的 tsconfig.json 中确认:
"module": "NodeNext",
"target": "ESNext"2. 写入关键常量
新建 app.ts,头部声明:
import {
createSolanaRpcSubscriptions,
RpcSubscriptions,
SolanaRpcSubscriptionsApi,
address,
Address
} from '@solana/web3.js';
const WSS_PROVIDER_URL = 'wss://your-node-endpoint.example'; // 替换成你的 WebSocket RPC
const LAMPORTS_PER_SOL = 1_000_000_000;
const PUMP_FUN_FEE_ACCOUNT = address("CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM");3. helper 函数:Lamports → SOL 输出
const lamportsToSolString = (lamports: number, includeUnit = true): string => {
const solAmount = lamports / LAMPORTS_PER_SOL;
return `${solAmount.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} ${includeUnit ? 'SOL' : ''}`.trim();
};4. 核心监控函数
interface TrackAccountArgs {
rpcSubscriptions: RpcSubscriptions<SolanaRpcSubscriptionsApi>;
accountAddress: Address;
abortSignal: AbortSignal;
}
async function trackAccount({ rpcSubscriptions, accountAddress, abortSignal }: TrackAccountArgs) {
let lastLamports: number | null = null;
const accountNotifications = await rpcSubscriptions
.accountNotifications(accountAddress, { commitment: 'confirmed' })
.subscribe({ abortSignal });
for await (const notification of accountNotifications) {
const { slot } = notification.context;
const currentLamports = Number(notification.value.lamports);
const delta = lastLamports !== null ? currentLamports - lastLamports : 0;
const sign = delta > 0 ? '+' : delta < 0 ? '-' : ' ';
console.log(`📈 区块 ${slot.toLocaleString()}: ${lamportsToSolString(currentLamports)} SOL (${sign}${lamportsToSolString(Math.abs(delta))})`);
lastLamports = currentLamports;
}
}5. 启动入口
async function main() {
console.log(`💊 追踪 Pump.fun 费用账户: ${PUMP_FUN_FEE_ACCOUNT}`);
const rpcSubscriptions = createSolanaRpcSubscriptions(WSS_PROVIDER_URL);
const abortController = new AbortController();
try {
await trackAccount({
rpcSubscriptions,
accountAddress: PUMP_FUN_FEE_ACCOUNT,
abortSignal: abortController.signal
});
} catch (e) {
console.error('订阅异常:', e);
} finally {
abortController.abort();
console.log('✅ 清理完成');
}
}
main();一键运行:
ts-node app.ts计费与优化技巧
- 每条 Ws 通知 约 20 QuickNode 积分,按响应计费而非订阅条数。
- 用 AbortController 及时回收订阅,可大幅下降账单。
- 利用
commitment与过滤器减少冗余推送。
常见疑问解答 FAQ
Q1:我的 WebSocket 经常断开怎么办?
A:请检查节点稳定性,或考虑配置 Yellowstone gRPC Geyser 插件 获取更强健流式结构。
Q2:能一次订阅多个地址吗?
A:目前需各自调用 accountNotifications,但可并行运行多个 AbortSignal 实现秒级取消。
Q3:是否一定要 TypeScript?
A:JS 亦可运行,只是会失去 类型安全 和 IDE 智能提示 优势。
Q4:LAMPORTS 与 SOL 单位总是混淆?
A:牢记 1 SOL = 1,000,000,000 Lamports,可用 export const LAMPORTS_PER_SOL = 1_000_000_000 作为常量以防手滑。
Q5:如何排除垃圾推送?
A:使用 filters 参数或升级到 gRPC 高级过滤算子,如只接收 >100 Lamports 变化。
Q6:代码能否部署到浏览器?
A:Solana Web3.js 2.0 完全支持浏览器,可配合 Vite/webpack 打包。
进阶替代方案
若流量大或需要 历史回滚,可研究:
- Solana Streams → 管道式高效路由。
- Geyser gRPC → 企业级流式通道,自带重放功能。
下一步:让监控更懂你
本文模板高度通用,替换 PUMP_FUN_FEE_ACCOUNT 即可追踪你的 DAO 金库、NFT 铸造账户或节点奖励地址。
保持关注更新
👉 深入探索黄色石 gRPC 的 5 个灰度实战技巧