
getTransfersByAddress: история переводов Solana в разобранном виде за 1 вызов
Содержание
- Зачем нужен отдельный RPC-метод для переводов?
- Ответ getTransfersByAddress
- Почему переводы Solana сложно разбирать?
- SOL и WSOL
- Комиссии за переводы Token-2022
- Выпуск и сжигание токенов
- Преимущества getTransfersByAddress
- Поиск по минту
- Поиск по сумме
- Поиск по времени
- Поиск по контрагенту
- Режим SOL
- Пагинация и сортировка
- Когда использовать getTransfersByAddress
- Начало работы
getTransfersByAddress — новый эксклюзивный RPC-метод Helius для Solana, который возвращает разобранные и понятные человеку записи о переводах токенов и SOL для адреса кошелька. Он поддерживает встроенные фильтры по минту, времени, сумме, слоту, направлению и контрагенту.
Это идеальное дополнение к getTransactionsForAddress (gTFA). gTFA возвращает полные данные транзакций, а getTransfersByAddress — краткие объекты переводов: кто, что, кому, когда и сколько отправил.
Зачем нужен отдельный RPC-метод для переводов?
Большинству кошельков, платёжных и портфельных продуктов не нужны полные данные транзакции. Им нужны переводы.
Что же они делают? Каждая команда пишет собственную версию одного и того же парсера переводов, и, к сожалению, большинство неправильно обрабатывает пограничные случаи.
До сих пор для создания понятной истории переводов Solana разработчикам приходилось:
- Получать подписи через
getSignaturesForAddress - Запрашивать каждую подпись через
getTransaction - Разбирать балансы до и после транзакции, балансы токенов и внутренние инструкции
- Восстанавливать переводы, учитывать различия в комиссиях SPL Token и Token-2022 и отделять шум от обёртывания и развёртывания WSOL
- Повторять это для нескольких страниц, обрабатывать повторные попытки и сохранять результаты
Даже метод getTransactionsForAddress объединяет только шаги 1 и 2 в один вызов. Шаги 3–5 по-прежнему остаются на разработчике.
Теперь getTransfersByAddress выполняет эту работу за вас и возвращает результат в виде структурированного списка.
Ответ getTransfersByAddress
Каждый объект перевода содержит подпись, слот, время блока, тип перевода, отправителя, получателя, минт, сумму (исходную и отображаемую), количество десятичных знаков, статус подтверждения и точные индексы инструкций. Это позволяет сопоставить каждый перевод с исходной транзакцией.
{
"signature": "<TX_SIGNATURE>",
"slot": 315073428,
"blockTime": 1736159420,
"type": "transfer",
"fromUserAccount": "<SENDER_WALLET>",
"toUserAccount": "<RECIPIENT_WALLET>",
"fromTokenAccount": "<SENDER_TOKEN_ACCOUNT>",
"toTokenAccount": "<RECIPIENT_TOKEN_ACCOUNT>",
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"amount": "2500000",
"decimals": 6,
"uiAmount": "2.5",
"confirmationStatus": "finalized",
"transactionIdx": 35,
"instructionIdx": 1,
"innerInstructionIdx": 0
}Поле типа точно указывает, что произошло: transfer, transferFee, mint, burn, wrap, unwrap, changeAccountOwner или withdrawWithheldFee. Вам не придётся определять операцию по необработанным данным программы.
Почему переводы Solana сложно разбирать?
Перевод в транзакции Solana — не единая концепция.
Это категория, за которой скрывается множество пограничных случаев. Ошибка в любом из них искажает ваши данные.
SOL и WSOL
Для пользователя нативный SOL и Wrapped SOL выглядят как один актив, но в транзакции они находятся в разных местах.
Нативный SOL перемещается через балансы лампортов до и после транзакции в системных аккаунтах. WSOL перемещается через балансы SPL-токенов в токен-аккаунтах.
Пользователь при обмене на Jupiter может обернуть SOL в WSOL, обменять WSOL на USDC, а затем не развернуть остаток, оставив токен-аккаунт WSOL.
С точки зрения пользователя, он потратил SOL. С точки зрения сети, произошло три перевода и одно обёртывание.
Более того, само обёртывание не является переводом другому владельцу: тот же кошелёк перемещает лампорты в собственный токен-аккаунт. Если считать это переводом, активность пользователя будет учтена дважды.
Комиссии за переводы Token-2022
В Token-2022 появился TransferCheckedWithFee, при котором списанная у отправителя сумма не совпадает с зачисленной получателю.
Разница удерживается как комиссия в токен-аккаунте получателя. Позже её можно перевести органу, управляющему комиссиями, через withdrawWithheldFee.
Простой парсер видит один перевод и неверно определяет сумму. Более точный парсер обнаруживает расширение комиссии, разделяет инструкцию на перевод и начисление удержанной комиссии, а также отдельно отслеживает аккаунт комиссии.
Выпуск и сжигание токенов
У токенов, выпущенных в аккаунт, нет отправителя. У сожжённых токенов нет получателя. В изменениях балансов до и после транзакции обе операции выглядят как «переводы», но их смешение с переводами между кошельками искажает аналитику по контрагентам: кошельки якобы «получают» средства с нулевого адреса и «отправляют» их в никуда.
getTransfersByAddress представляет эти операции типами mint и burn, где fromUserAccount или toUserAccount имеет значение null. Вы можете включать или исключать их в зависимости от своего продукта.
Преимущества getTransfersByAddress
Метод getTransfersByAddress поддерживает фильтры, для применения которых раньше требовалось загружать и разбирать полную историю транзакций на стороне клиента.
Поиск по минту
Возвращайте только переводы определённого токена.
{
"jsonrpc": "2.0",
"id": "1",
"method": "getTransfersByAddress",
"params": [
"<WALLET_ADDRESS>",
{ "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" }
]
}Поиск по сумме
Фильтруйте по исходной сумме с помощью сравнений gt, gte, lt и lte. Это полезно для выявления китов, исключения пыли — аккаунтов с незначительным количеством токенов — или обнаружения необычной активности.
{
"params": [
"<WALLET_ADDRESS>",
{
"mint": "So11111111111111111111111111111111111111112",
"filters": {
"amount": { "gte": 1000000000, "lt": 10000000000 }
}
}
]
}Поиск по времени
Время блока можно задать как диапазон временных меток Unix. Диапазоны слотов аналогично позволяют выполнять запросы с точностью до слота.
{
"params": [
"<WALLET_ADDRESS>",
{
"filters": {
"blockTime": { "gte": 1735718400, "lt": 1738396800 }
}
}
]
}Поиск по контрагенту
Объедините параметры with и direction, чтобы запрашивать переводы между двумя конкретными кошельками в любом направлении.
{
"params": [
"<WALLET_ADDRESS>",
{
"with": "<COUNTERPARTY_WALLET>",
"direction": "in"
}
]
}Режим SOL
Нативный SOL и WSOL по-разному представлены в Solana, хотя для пользователя обычно означают одно и то же. Поэтому метод getTransfersByAddress предоставляет параметр solMode.
merged (по умолчанию)
WSOL обрабатывается как нативный SOL.
Строки обёртывания и развёртывания исключаются, а запрос по минту нативного SOL возвращает переводы как нативного SOL, так и WSOL.
separate
В этом режиме WSOL сохраняется как отдельный минт, а строки жизненного цикла обёртывания и развёртывания включаются для полной проверяемости.
Для большинства продуктов обычно подходит merged. Для сверки, бухгалтерского учёта и аналитики на уровне протокола часто нужен separate.
Пагинация и сортировка
Стандартная пагинация на основе курсора через paginationToken — до 100 записей на страницу. sortOrder принимает asc и desc.
{
"jsonrpc": "2.0",
"id": "1",
"method": "getTransfersByAddress",
"params": [
"<WALLET_ADDRESS>",
{ "limit": 50, "paginationToken": "315069220:308:2:1" }
]
}Когда использовать getTransfersByAddress
getTransfersByAddress и getTransactionsForAddress похожи, но предназначены для разных задач.
| Задача | Метод |
| Разобранные переводы токенов и SOL с фильтрами | getTransfersByAddress |
| Полные данные транзакций или действия, не связанные с переводами | getTransactionsForAddress |
| Декодированные инструкции для любой подписи или адреса | Parsed Events API |
| Только подписи | getTransactionsForAddress с transactionDetails: 'signatures' |
| Потоковая передача переводов в реальном времени | LaserStream |
Начало работы
Метод getTransfersByAddress уже доступен на всех платных планах, начиная с плана Developer. Один запрос стоит 10 кредитов и учитывается в стандартной группе лимитов запросов RPC.
Используйте его с существующим RPC URL Helius:
const response = await fetch("https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: "1",
method: "getTransfersByAddress",
params: ["<WALLET_ADDRESS>"]
})
});
const data = await response.json();
console.log(data.result.data);Полное описание параметров и ответа доступно в справочнике API.
Похожие статьи
Подпишитесь на Helius
Следите за новостями разработки на Solana и получайте уведомления о наших публикациях


