import WebSocket from "ws";
const apiKey = process.env.SOLANA_RPC_API_KEY;
const account = process.env.ACCOUNT_ADDRESS;
if (!apiKey || !account) {
throw new Error("Set SOLANA_RPC_API_KEY and ACCOUNT_ADDRESS");
}
const endpoint = new URL("wss://rpc-data.solanatracker.io/");
endpoint.searchParams.set("api_key", apiKey);
const socket = new WebSocket(endpoint);
let subscriptionId;
let stopping = false;
let closeTimer;
function unsubscribe() {
socket.send(JSON.stringify({
jsonrpc: "2.0", id: 2,
method: "accountUnsubscribe", params: [subscriptionId],
}));
}
socket.on("open", () => {
socket.send(JSON.stringify({
jsonrpc: "2.0", id: 1, method: "accountSubscribe",
params: [account, { encoding: "base64", commitment: "confirmed" }],
}));
});
socket.on("message", raw => {
let message;
try { message = JSON.parse(raw.toString()); }
catch { console.error("Invalid JSON received"); return; }
if (message.error) {
console.error("RPC error", message.error);
socket.close();
return;
}
if (message.id === 1) {
subscriptionId = message.result;
console.log("Subscribed", subscriptionId);
if (stopping) unsubscribe();
} else if (message.id === 2) {
console.log("Unsubscribed", message.result);
socket.close();
} else if (message.method === "accountNotification" &&
message.params.subscription === subscriptionId) {
const { context, value } = message.params.result;
console.log({ slot: context.slot, lamports: value.lamports });
}
});
socket.on("error", error => console.error("WebSocket error", error.message));
socket.on("close", () => {
clearTimeout(closeTimer);
console.log("Connection closed");
});
process.once("SIGINT", () => {
stopping = true;
closeTimer = setTimeout(() => socket.terminate(), 3_000);
if (socket.readyState === WebSocket.OPEN && subscriptionId !== undefined) {
unsubscribe();
} else if (socket.readyState !== WebSocket.OPEN) {
socket.terminate();
}
});