概述
账户监控让您可以实时跟踪 Solana 上的余额变化、数据修改、所有权转移以及账户创建/删除事件。本指南涵盖了不同用例的过滤策略和实现模式。先决条件: 本指南假设您已完成 Yellowstone gRPC 快速入门 并已设置好工作流。
账户过滤选项
- 特定账户
- 按所有者
- 高级过滤器
通过公钥监控单个账户当您确切知道要监控哪些账户时使用:
报告错误代码
复制
询问AI
const subscribeRequest: SubscribeRequest = {
accounts: {
accountSubscribe: {
account: [
"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC mint
"So11111111111111111111111111111111111111112" // Wrapped SOL
],
owner: [],
filters: []
}
},
commitment: CommitmentLevel.CONFIRMED
};
最佳用途: 监控特定代币铸造、已知钱包或关键程序账户
监控特定程序拥有的所有账户跟踪由某个程序拥有的所有账户(例如,特定铸造的所有代币账户):
报告错误代码
复制
询问AI
const subscribeRequest: SubscribeRequest = {
accounts: {
accountSubscribe: {
account: [],
owner: [
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", // Token Program
"11111111111111111111111111111111" // System Program
],
filters: []
}
},
commitment: CommitmentLevel.CONFIRMED
};
高数据量: 所有者过滤器可能会生成大量数据。使用其他过滤器来缩小结果范围。
结合数据大小和内存比较过滤器通过数据结构和内容过滤账户:
报告错误代码
复制
询问AI
const subscribeRequest: SubscribeRequest = {
accounts: {
accountSubscribe: {
account: [],
owner: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
filters: [
// Only token accounts (165 bytes)
{ dataSize: 165 },
// Only USDC token accounts (mint at offset 0)
{
memcmp: {
offset: 0,
bytes: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
}
}
]
}
},
commitment: CommitmentLevel.CONFIRMED
};
高效过滤: 结合大小和内容过滤器以最小化不必要的数据
数据切片
通过请求账户数据的特定字节范围来优化带宽:报告错误代码
复制
询问AI
// Only get the balance portion of token accounts (bytes 64-72)
const subscribeRequest: SubscribeRequest = {
accounts: {
accountSubscribe: {
owner: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
filters: [{ dataSize: 165 }]
}
},
accountsDataSlice: [
{ offset: 64, length: 8 } // Token balance (u64)
],
commitment: CommitmentLevel.CONFIRMED
};
实用示例
示例 1:监控大额代币持有者
跟踪具有大量余额的 USDC 账户:报告错误代码
复制
询问AI
import { StreamManager } from './stream-manager'; // From quickstart guide
async function monitorLargeUSDCHolders() {
const streamManager = new StreamManager(
"your-grpc-endpoint",
"your-api-key",
handleLargeHolderUpdate
);
const subscribeRequest: SubscribeRequest = {
accounts: {
accountSubscribe: {
owner: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
filters: [
{ dataSize: 165 }, // Token account size
{
memcmp: {
offset: 0,
bytes: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" // USDC mint
}
}
]
}
},
accountsDataSlice: [
{ offset: 32, length: 32 }, // Owner
{ offset: 64, length: 8 } // Balance
],
commitment: CommitmentLevel.CONFIRMED
};
await streamManager.connect(subscribeRequest);
}
function handleLargeHolderUpdate(data: any): void {
if (data.account) {
const account = data.account.account;
// Parse token account data
if (account.data && account.data.length >= 8) {
const balanceBuffer = Buffer.from(account.data.slice(64, 72), 'base64');
const balance = balanceBuffer.readBigUInt64LE();
const balanceInUSDC = Number(balance) / 1e6; // USDC has 6 decimals
// Only log accounts with > 100,000 USDC
if (balanceInUSDC > 100000) {
console.log(`🐋 Large USDC Holder Update:`);
console.log(` Account: ${account.pubkey}`);
console.log(` Balance: ${balanceInUSDC.toLocaleString()} USDC`);
console.log(` Slot: ${data.account.slot}`);
}
}
}
}
示例 2:跟踪程序账户变化
监控由特定程序拥有的所有账户:报告错误代码
复制
询问AI
async function monitorProgramAccounts() {
const PROGRAM_ID = "YourProgramId"; // Replace with actual program ID
const streamManager = new StreamManager(
"your-grpc-endpoint",
"your-api-key",
handleProgramAccountUpdate
);
const subscribeRequest: SubscribeRequest = {
accounts: {
accountSubscribe: {
owner: [PROGRAM_ID],
filters: []
}
},
commitment: CommitmentLevel.CONFIRMED
};
await streamManager.connect(subscribeRequest);
}
function handleProgramAccountUpdate(data: any): void {
if (data.account) {
const account = data.account.account;
console.log(`📋 Program Account Update:`);
console.log(` Account: ${account.pubkey}`);
console.log(` Owner: ${account.owner}`);
console.log(` Lamports: ${account.lamports}`);
console.log(` Data Length: ${account.data?.length || 0} bytes`);
console.log(` Executable: ${account.executable}`);
console.log(` Rent Epoch: ${account.rentEpoch}`);
}
}
示例 3:新账户创建监控
跟踪新账户创建的时间:报告错误代码
复制
询问AI
async function monitorNewAccounts() {
const streamManager = new StreamManager(
"your-grpc-endpoint",
"your-api-key",
handleNewAccountCreation
);
const subscribeRequest: SubscribeRequest = {
accounts: {
accountSubscribe: {
owner: ["11111111111111111111111111111111"], // System Program
filters: []
}
},
commitment: CommitmentLevel.CONFIRMED
};
await streamManager.connect(subscribeRequest);
}
function handleNewAccountCreation(data: any): void {
if (data.account && data.account.account.lamports === 0) {
// New account creation typically starts with 0 lamports
const account = data.account.account;
console.log(`🆕 New Account Created:`);
console.log(` Account: ${account.pubkey}`);
console.log(` Owner: ${account.owner}`);
console.log(` Slot: ${data.account.slot}`);
}
}
过滤逻辑参考
了解过滤器如何组合:过滤器组合规则
过滤器组合规则
账户级过滤器(AND 逻辑):
- 如果指定,
account和owner和filters必须全部匹配
account数组中的任何账户匹配owner数组中的任何所有者匹配
- 所有 dataSize 和 memcmp 过滤器必须匹配
报告错误代码
复制
询问AI
{
account: ["A", "B"], // Match account A OR B
owner: ["X", "Y"], // AND owned by X OR Y
filters: [
{ dataSize: 100 }, // AND data size is 100
{ memcmp: {...} } // AND memcmp matches
]
}
常见过滤器模式
常见过滤器模式
特定铸币的代币账户:具有最低余额的 SPL 代币账户:程序派生账户:
报告错误代码
复制
询问AI
{
owner: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
filters: [
{ dataSize: 165 },
{ memcmp: { offset: 0, bytes: "MINT_ADDRESS" } }
]
}
报告错误代码
复制
询问AI
{
owner: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
filters: [
{ dataSize: 165 },
{ memcmp: { offset: 64, bytes: "MINIMUM_BALANCE_BYTES" } }
]
}
报告错误代码
复制
询问AI
{
owner: ["YOUR_PROGRAM_ID"],
filters: [
{ dataSize: 200 }, // Your account size
{ memcmp: { offset: 8, bytes: "DISCRIMINATOR" } }
]
}
性能注意事项
带宽优化
使用数据切片 仅请求所需字节应用严格过滤器 以减少不必要的更新选择适当的承诺 水平以适应您的用例
规模管理
从特定账户开始 然后使用所有者过滤器监控订阅量 并根据需要调整过滤器实现背压处理 以应对高流量流
错误处理
常见账户监控错误及解决方案:过滤器过于宽泛
过滤器过于宽泛
错误: 接收到过多数据或达到速率限制解决方案: 添加更具体的过滤器:
- 使用
dataSize匹配精确账户类型 - 添加
memcmp过滤器以匹配特定数据模式 - 考虑使用
accountsDataSlice以减少带宽
未收到更新
未收到更新
错误: 流连接但没有账户更新出现解决方案:
- 验证账户地址是否正确
- 检查账户是否实际频繁更改
- 尝试使用
PROCESSED承诺以获得更频繁的更新 - 首先测试已知活跃账户