Обзор
Подписки на аккаунты доставляют обновления в реальном времени при изменении баланса lamport, данных или владельца аккаунта. Вы можете отслеживать конкретные адреса, все аккаунты, принадлежащие программе, или применять байтовые фильтры данных.
Параметры фильтрации
| Параметр | Тип | Описание |
|---|
account | string[] | Конкретные публичные ключи аккаунтов для мониторинга. Совпадение с любым из списка (логическое ИЛИ). |
owner | string[] | Мониторинг всех аккаунтов, принадлежащих этим идентификаторам программ (логическое ИЛИ). |
filters | object[] | Дополнительные фильтры данных — dataSize и/или memcmp (логическое И). |
nonemptyTxnSignature | boolean | Только обновления, являющиеся частью транзакции. |
Фильтр dataSize
Получать только обновления аккаунтов с точно совпадающей длиной данных:
filters: [{ dataSize: 165 }]
Фильтр memcmp
Сопоставление аккаунтов по конкретной последовательности байт по заданному смещению:
filters: [
{
memcmp: {
offset: 0,
bytes: "base58EncodedBytes",
},
},
]
При комбинировании нескольких типов фильтров они работают как логическое И. В массивах account или owner значения работают как логическое ИЛИ.
Пример: Мониторинг конкретного кошелька
import Client, { CommitmentLevel, SubscribeRequest } from "@triton-one/yellowstone-grpc";
const client = new Client(
"https://your-endpoint.grpc.orbitflare.com",
"YOUR_GRPC_TOKEN",
{ "grpc.max_receive_message_length": 64 * 1024 * 1024 }
);
async function main() {
const stream = await client.subscribe();
const streamClosed = new Promise<void>((resolve, reject) => {
stream.on("error", (error) => { reject(error); stream.end(); });
stream.on("end", () => resolve());
stream.on("close", () => resolve());
});
stream.on("data", (data) => {
if (data.account) {
const { account, slot } = data.account;
console.log(`Обновление аккаунта в слоте ${slot}:`);
console.log(` Публичный ключ: ${account.pubkey}`);
console.log(` Lamports: ${account.lamports}`);
console.log(` Владелец: ${account.owner}`);
console.log(` Длина данных: ${account.data.length} байт`);
}
});
const request: SubscribeRequest = {
accounts: {
walletMonitor: {
account: ["YourWalletPublicKeyHere"],
owner: [],
filters: [],
},
},
commitment: CommitmentLevel.CONFIRMED,
accountsDataSlice: [],
transactions: {},
transactionsStatus: {},
slots: {},
blocks: {},
blocksMeta: {},
entry: {},
ping: { id: 1 },
};
await new Promise<void>((resolve, reject) => {
stream.write(request, (err) => {
if (err == null) resolve(); else reject(err);
});
});
await streamClosed;
}
main();
Пример: Мониторинг всех токен-аккаунтов по программе-владельцу
const request: SubscribeRequest = {
accounts: {
tokenAccounts: {
account: [],
owner: [
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", // SPL Token программа
],
filters: [
{ dataSize: 165 }, // Стандартный размер токен-аккаунта
],
},
},
commitment: CommitmentLevel.CONFIRMED,
accountsDataSlice: [],
transactions: {},
transactionsStatus: {},
slots: {},
blocks: {},
blocksMeta: {},
entry: {},
};
Оптимизация с accountsDataSlice
Если вам нужна только часть данных аккаунта (например, первые 64 байта для дискриминатора), используйте accountsDataSlice для уменьшения трафика:
const request: SubscribeRequest = {
accounts: {
myFilter: {
account: ["AccountPubkeyHere"],
owner: [],
filters: [],
},
},
accountsDataSlice: [
{ offset: 0, length: 64 },
],
commitment: CommitmentLevel.CONFIRMED,
transactions: {},
transactionsStatus: {},
slots: {},
blocks: {},
blocksMeta: {},
entry: {},
};
Распространённые сценарии использования
| Сценарий | Подход |
|---|
| Отслеживание баланса кошелька | Фильтр account с конкретными публичными ключами |
| Мониторинг всех токен-минтов | owner: [токен-программа] + dataSize: 82 |
| Наблюдение за состоянием программы | Фильтр owner: [идентификатор программы] |
| Обнаружение создания нового пула AMM | owner + dataSize, соответствующий размеру аккаунта пула |