Account Updates for a Program
Tracking Program Account Updates with gRPC Subscriptions
If an account belongs to a program, its owner is always the program's address. To stream all account updates for a program, use the account
field under the accounts filter. The owner
field should specify the program's address, as all accounts belonging to the program are owned by the program address itself.
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";
const PROGRAM_ID_TO_SUB = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P";
// 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?.account) {
console.log("\nReceived Account Update for:");
console.log(bs58.encode(data?.account?.account?.pubkey));
console.log("\n");
console.log(data?.account);
}
});
// 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-GRPC-ACCESS-TOKEN", // your Access Token
undefined,
);
/**
* Subscribe Request: The `accounts` field is for streaming account updates. The `owner` field is for streaming updates for accounts owned by the specified program ID.
*/
const req: SubscribeRequest = {
slots: {},
accounts: {
program_name: {
account: [],
filters: [],
owner: [PROGRAM_ID_TO_SUB], //account updates will be streamed for accounts with this owner
},
},
transactions: {},
blocks: {},
blocksMeta: {},
accountsDataSlice: [],
commitment: CommitmentLevel.PROCESSED, // Subscribe to processed blocks for the fastest updates
entry: {},
transactionsStatus: {},
};
// Start the subscription
subscribeCommand(client, req);
Last updated
Was this helpful?