This example illustrates subscribing to all transactions of a token on Raydium
So far we were streaming all transaction of a Solana address. Now imagine, if you want all transactions of a token, but only on Raydium V4. You don't want transactions of that token on Orca or any other dex. In this case we will use a new field accountRequired.
import Client, {
CommitmentLevel,
SubscribeRequestAccountsDataSlice,
SubscribeRequestFilterAccounts,
SubscribeRequestFilterBlocks,
SubscribeRequestFilterBlocksMeta,
SubscribeRequestFilterEntry,
SubscribeRequestFilterSlots,
SubscribeRequestFilterTransactions,
} from "@triton-one/yellowstone-grpc";
import { SubscribeRequestPing } from "@triton-one/yellowstone-grpc/dist/grpc/geyser";
import bs58 from "bs58";
// Interface for the subscription request structure
interface SubscribeRequest {
accounts: { [key: string]: SubscribeRequestFilterAccounts };
slots: { [key: string]: SubscribeRequestFilterSlots };
transactions: { [key: string]: SubscribeRequestFilterTransactions };
transactionsStatus: { [key: string]: SubscribeRequestFilterTransactions };
blocks: { [key: string]: SubscribeRequestFilterBlocks };
blocksMeta: { [key: string]: SubscribeRequestFilterBlocksMeta };
entry: { [key: string]: SubscribeRequestFilterEntry };
commitment?: CommitmentLevel;
accountsDataSlice: SubscribeRequestAccountsDataSlice[];
ping?: SubscribeRequestPing;
}
/**
* Subscribes to the gRPC stream and handles incoming data.
*
* @param client - Yellowstone gRPC client
* @param args - The Subscription request which specifies what data to stream
*/
async function handleStream(client: Client, args: SubscribeRequest) {
const stream = await client.subscribe();
// Promise that resolves when the stream ends or errors out
const streamClosed = new Promise<void>((resolve, reject) => {
stream.on("error", (error) => {
console.error("Stream error:", error);
reject(error);
stream.end();
});
stream.on("end", resolve);
stream.on("close", resolve);
});
// Handle incoming transaction data
stream.on("data", (data) => {
if (data?.transaction) {
console.log("\nReceived Transaction:");
console.log(bs58.encode(data?.transaction?.transaction?.signature));
console.log("\n");
console.log(data?.transaction);
}
});
// Send the subscription request
await new Promise<void>((resolve, reject) => {
stream.write(args, (err: any) => {
err ? reject(err) : resolve();
});
}).catch((err) => {
console.error("Failed to send subscription request:", err);
throw err;
});
// Wait for the stream to close
await streamClosed;
}
/**
* Entry point to start the subscription stream.
*
*/
async function subscribeCommand(client: Client, args: SubscribeRequest) {
while (true) {
try {
await handleStream(client, args);
} catch (error) {
console.error("Stream error, retrying in 1 second...", error);
await new Promise((resolve) => setTimeout(resolve, 1000));
}
}
}
// Instantiate Yellowstone gRPC client with env credentials
const client = new Client(
"YOUR-GRPC-ENDPOINT", //Your Region specific gRPC URL
"YOUR-ACCESS-TOKEN", // your Access Token
undefined,
);
/**
* Subscribe Request: The `transactions` field filters transaction streams to only include those
* that involve the specified address in `accountInclude` and `accountRequired`.
*/
const req: SubscribeRequest = {
accounts: {},
slots: {},
transactions: {
pumpFun: {
vote: false,
failed: false,
signature: undefined,
accountInclude: [
"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
],
accountExclude: [],
accountRequired: ["675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"],
},
},
transactionsStatus: {},
blocks: {},
blocksMeta: {},
entry: {},
accountsDataSlice: [],
ping: undefined,
commitment: CommitmentLevel.CONFIRMED,
};
// Start the subscription
subscribeCommand(client, req);
This lets you add another layer of filter, now gRPC will stream you transactions of that token only if it has Raydium V4 address in it.