API балансів токенів гаманця: активи ERC-20 та історія переказів
Створіть сторінку активів гаманця з ненульовими балансами токенів ERC-20, історією переказів токенів та пакетними метаданими. Перевіряйте покриття мереж, пагінуйте результати та масштабуйте цілочисельні суми за кількістю десяткових знаків.
Створіть сторінку активів гаманця за допомогою API блокчейн-даних гаманця: використовуйте API балансів токенів для ненульових активів ERC-20 та API переказів токенів для історії гаманця. Розробники та AI-агенти використовують ті самі автентифіковані запити. Перед виконанням запитів виконайте GET /v1/status та перевірте data_features і data_status обраної мережі; покриття балансів відрізняється залежно від мережі. Параметри запитів і схеми відповідей наведено в довіднику Data API.
Завдання, які допомагає вирішити цей посібник
- Зчитувати баланси токенів гаманця за допомогою ключа та пагінувати ненульові активи ERC-20.
- Зчитувати історію переказів гаманця у межах фіксованого вікна блоків та переходити за курсорами для обраної адреси.
- Заповнювати метадані токенів, щоб відображати назви та символи поруч із необробленими цілочисельними балансами, зберігаючи відсутні поля.
Три типи даних, необхідні сторінці активів гаманця
Сторінка активів гаманця може відображати баланси токенів ERC-20 адреси, історію переказів токенів та метадані токенів. Data API надає ендпоінт для кожного типу:
- Баланси:
GET /{chain}/addresses/{address}/balancesповертає ненульові баланси ERC-20 адреси, відсортовані за адресоюtokenу зростаючому порядку, включно ізsymbolтаdecimalsтокена, якщо вони доступні. Адреса без балансів повертає200ізdata: []. - Перекази:
GET /{chain}/addresses/{address}/transfersповертає перекази токенів за участю адреси у межах обов'язкового вікна блоків, відсортовані за(block_number, log_index)у спадному порядку. - Метадані токенів:
GET /{chain}/tokens/{token}зчитує назву, символ, кількість десяткових знаків та загальну пропозицію одного токена за адресою контракту;POST /{chain}/tokens:batchзчитує ті самі метадані для до 100 адрес в одному запиті.
Усі три ендпоінти використовують https://api.blockvectra.com/v1/data як базовий URL і заголовок запиту x-api-key, де robinhood_mainnet наведено як приклад мережі. Вони належать відповідно до можливостей balances, transfers та token_metadata; перелік мереж, що надають кожну можливість, дивіться на сторінці Підтримувані мережі. У мережі без відповідної можливості ендпоінт повертає 422 no_coverage.
Запит 1: баланси адреси
Цей ендпоінт приймає небагато параметрів, що робить його чудовим першим запитом для сторінки:
{chain}(параметр шляху, обов'язковий): ідентифікатор мережі, значенняchainзапису вGET /chains(наприклад,robinhood_mainnet). Зіставлення точне та чутливе до регістру; псевдоніми та числові Chain ID не приймаються.{address}(параметр шляху, обов'язковий): 20-байтна адреса; префікс0xнеобов'язковий, підтримується будь-який регістр.limit(параметр запиту, необов'язковий): розмір сторінки. За замовчуванням — 50; значення понад 500 обмежуються до 500;0або неціле число повертає400 bad_request.cursor(параметр запиту, необов'язковий):next_cursorз попередньої відповіді, переданий назад без змін для отримання наступної сторінки. Курсор дійсний лише для тієї мережі, ендпоінта та параметрів запиту, які його видали; повторне використання в іншому місці повертає400 bad_request.
Він використовує пагінацію за набором ключів: next_cursor з'являється лише тоді, коли існує наступна сторінка. На останній сторінці ключ взагалі відсутній, а не null.
export BLOCKVECTRA_API_KEY=rgw_your_api_key
curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/0x1111111111111111111111111111111111111111/balances?limit=50" \
-H "x-api-key: $BLOCKVECTRA_API_KEY"Обгорткою відповіді є AddressBalanceListEnvelope, що містить data та meta. Кожен елемент data є об'єктом AddressBalance:
| Поле | Тип | Опис |
|---|---|---|
token | string (адреса) | Адреса контракту токена; канонічною формою є 0x плюс 40 малих шістнадцяткових цифр. |
balance | string (десятковий) | Необроблений цілочисельний баланс, який може перевищувати 2^53, повертається як звичайний десятковий рядок — ніколи не як число JSON, наукова чи шістнадцяткова нотація. |
symbol | string або null | Символ токена, або null, якщо недоступно. |
decimals | integer або null | Кількість десяткових знаків токена, 0–255, або null, якщо недоступно. |
Запит 2: перекази адреси
Ендпоінт переказів вимагає явного вікна блоків: from_block і to_block є обов'язковими та мають задовольняти умову from_block <= to_block. Він приймає ще кілька параметрів:
standard(параметр запиту, обов'язковий):erc20абоerc721. Запити на рівні адреси не покриваютьerc1155; передача цього значення повертає422 no_coverage.direction(параметр запиту, необов'язковий):in,outабоany; за замовчуванням —any, фільтрує за напрямком відносно адреси.token(параметр запиту, необов'язковий): обмежує результати одним контрактом токена.clamp(параметр запиту, необов'язковий): лише точний рядокtrueактивує його; будь-яке інше значення вважаєтьсяfalse.
Межі вікна та фінальність: явний to_block, вищий за as_of_block, повертає 409 not_indexed_yet, якщо тільки clamp=true не скоротить його до as_of_block; вікно, ширше за ліміт мережі (limits.max_window_blocks із GET /chains), повертає 409 window_too_large, якщо тільки clamp=true не скоротить його зі старішого кінця (збільшуючи from_block і залишаючи to_block фіксованим). Якщо сам from_block уже перевищує as_of_block, запит залишається суворою помилкою 409 навіть із clamp=true. Коли вікно обрізано або частково покрите, поле meta.coverage у відповіді має значення "partial"; інакше — "full".
У записах переказів елементи ERC-20 додають amount; елементи ERC-721 додають token_id. Обидва типи містять token, standard, from, to, block_number, block_timestamp, tx_hash, tx_index та log_index.
export BLOCKVECTRA_API_KEY=rgw_your_api_key
# 1) Зчитайте as_of_block із відповіді balances.
AS_OF_BLOCK=$(curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/0x1111111111111111111111111111111111111111/balances" \
-H "x-api-key: $BLOCKVECTRA_API_KEY" | grep -o '"as_of_block":[0-9]*' | cut -d: -f2)
# 2) clamp=true скорочує занадто широке вікно або to_block вище as_of_block замість повернення 409.
curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/0x1111111111111111111111111111111111111111/transfers?standard=erc20&from_block=0&to_block=$AS_OF_BLOCK&direction=any&clamp=true" \
-H "x-api-key: $BLOCKVECTRA_API_KEY"Пагінація всіх переказів
Поле next_cursor ендпоінта переказів адреси є оптимістичним: воно з'являється лише тоді, коли сторінка повернула рівно limit рядків, тому сторінка може містити next_cursor і все одно виявитися останньою. Не зупиняйтеся, коли сторінка порожня; слідуйте за next_cursor, доки ключ не зникне.
Наведений нижче код отримує кожен переказ у вікні:
const address = "0x1111111111111111111111111111111111111111";
const head = await fetch(
`https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/${address}/balances`,
{ headers: { "x-api-key": process.env.BLOCKVECTRA_API_KEY! } },
).then((r) => r.json());
const asOfBlock = head.meta.as_of_block;
const transfers: unknown[] = [];
let cursor: string | undefined;
do {
const url = new URL(
`https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/${address}/transfers`,
);
url.searchParams.set("standard", "erc20");
url.searchParams.set("from_block", "0");
url.searchParams.set("to_block", String(asOfBlock));
url.searchParams.set("limit", "500");
// clamp обрізає зі старішого кінця
url.searchParams.set("clamp", "true");
if (cursor) url.searchParams.set("cursor", cursor);
const res = await fetch(url, {
headers: { "x-api-key": process.env.BLOCKVECTRA_API_KEY! },
});
const page = await res.json();
transfers.push(...page.data);
cursor = page.next_cursor; // відсутнє на останній сторінці
} while (cursor);Запит 3: метадані токенів та tokens:batch
Зчитайте один токен за допомогою GET /{chain}/tokens/{token}; шлях приймає лише {chain} та {token} без пагінації. Обгорткою відповіді є TokenEnvelope, а data є об'єктом Token:
| Поле | Тип | Опис |
|---|---|---|
address | string (адреса) | Адреса контракту токена. |
standard | string | erc20, erc721 або unknown. |
name | string або null | Назва токена, або null, якщо недоступно. |
symbol | string або null | Символ токена, або null, якщо недоступно. |
decimals | integer або null | Кількість десяткових знаків токена, 0–255, або null, якщо недоступно. |
total_supply | string або null | Необроблена загальна пропозиція; API не застосовує масштабування decimals. null, якщо недоступно. |
first_seen_block | integer (int64) | Висота блоку, де токен було помічено вперше. |
metadata_updated_at | string (часова мітка) | Час UTC останнього оновлення метаданих. |
metadata_block | integer (int64) | Висота блоку, на якій було зчитано метадані. |
metadata_status | string | ok, partial або unavailable. |
metadata_issues | object | Записи проблем для кожного поля з ключами name, symbol, decimals, total_supply та значеннями reverted, no_data, invalid_encoding або temporarily_unavailable. |
Значення {token}, яке не є дійсною 20-байтною адресою, повертає 400 bad_request; невідомий {token} повертає 404 not_found; невідома мережа {chain} повертає 404 unknown_chain.
Ендпоінт балансів уже містить symbol та decimals, де вони доступні, але обидва можуть бути null. Щоб заповнити назву та десяткові знаки для кожного токена в гаманці, використовуйте POST /{chain}/tokens:batch:
- Тіло запиту має вигляд
{"addresses": [...]}максимум зі 100 адресами на запит; понад 100 елементів або елемент, який не є дійсною 20-байтною адресою, повертає400 bad_request(помилка виникає на першій недійсній адресі, до якої дійде обробка). - Адреси, які не знайдено, не викликають помилки; вони перелічені в
data.missing, тоді якdata.tokensмістить лише ті токени, метадані яких було знайдено. - Повторювані адреси дедуплікуються як у
tokens, так і вmissing, кожна в порядку першої появи в запиті.
export BLOCKVECTRA_API_KEY=rgw_your_api_key
# Один токен
curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/tokens/0x1111111111111111111111111111111111111111" \
-H "x-api-key: $BLOCKVECTRA_API_KEY"
# Пакетний запит: до 100 адрес на запит
curl -s -X POST "https://api.blockvectra.com/v1/data/robinhood_mainnet/tokens:batch" \
-H "x-api-key: $BLOCKVECTRA_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"addresses":["0x1111111111111111111111111111111111111111","0x2222222222222222222222222222222222222222"]}'Масштабування сум за кількістю десяткових знаків
Поле балансу balance та поле переказу ERC-20 amount є необробленими цілими числами, представленими як десяткові рядки (UInt256String); загальна пропозиція токена total_supply також є необробленим ончейн-цілим числом без застосування масштабування decimals. Щоб показати зручну для читання кількість, розділіть її на 10^decimals відповідного токена.
decimalsбереться з власних полівsymbol/decimalsелемента балансу або зGET /{chain}/tokens/{token}іPOST /{chain}/tokens:batch; воно може дорівнюватиnull.- Ці значення можуть перевищувати
2^53, тому не виконуйте арифметичні дії зі стандартними числами JSON: використовуйтеBigIntу TypeScript таDecimalу Python, парсячи десятковий рядок як є, щоб уникнути втрати точності.
function toDisplayAmount(raw: string, decimals: number | null): string {
if (decimals === null) return raw; // метадані decimals відсутні: зберігаємо необроблене ціле число
const value = BigInt(raw);
const base = 10n ** BigInt(decimals);
const whole = value / base;
const fraction = (value % base)
.toString()
.padStart(decimals, "0")
.replace(/0+$/, "");
return fraction ? `${whole}.${fraction}` : whole.toString();
}
// balance.balance є необробленим десятковим рядком; decimals надходить із того самого елемента або tokens:batch.
const display = toDisplayAmount(balance.balance, balance.decimals);Свіжість даних
Кожна успішна відповідь у межах мережі містить meta:
as_of_block: найновіший повністю записаний блок мережі. Ендпоінти рівня блоків обслуговують дані до цієї висоти.safe_block: маркер, що вказує на консенсусний тег блокуsafeвузла (null, доки невідомо). Ніколи не буває нижчим заfinalized_block, не скорочує, не відхиляє та не затримує відповіді.finalized_block: маркер, що вказує на консенсусний тег блокуfinalizedвузла (null, доки невідомо). Він не скорочує, не відхиляє та не затримує відповіді; клієнти самі вирішують, який рівень безпеки їм потрібен від маркера (наприклад, статус підтвердження).coverage:"full"або"partial". Перекази адрес та подібні ендпоінти повідомляють про"partial", колиclampзвузив обслуговуване вікно або коли вікно починається до першого проіндексованого блоку мережі.refreshed_at: коли дані у відповіді оновлювалися востаннє (UTC). Може бутиnull:nullозначає, що час оновлення даних невідомий і їх слід вважати застарілими; ендпоінти на основі блоків завжди повертають значення.- Також повторюються поля
chain,chain_slugтаchain_external_id.
Поширений шаблон: прочитайте meta.as_of_block із будь-якої першої відповіді, щоб зчитувати дані до найновішого проіндексованого блоку, та перевірте meta.safe_block / meta.finalized_block, якщо бажаєте відображати статус підтвердження.
Оцінка CU для одного завантаження сторінки
Кожен метод тарифікується за його вагою в CU, зчитаною з API тарифних планів платформи:
Вага CU на виклик
| Метод | CU на виклик |
|---|---|
data.address_balances | 25 |
data.address_transfers | 25 |
data.tokens_batch | 10 |
Одне завантаження сторінки (оцінка)
1 запит balances + 3 сторінок transfer + 1 запит(ів) tokens:batch, загалом 5 викликів, близько 110 CU. Фактичне використання залежить від кількості сторінок і токенів.
Щодо рішень про білінг та незатарифікованих відповідей із помилками звертайтеся до правил білінгу. Якщо вам потрібна не індексована історія переказів, а логи з найновіших блоків, спершу прочитайте статтю Нещодавні дані вузла проти індексованої історії, перш ніж вирішувати, чи переходити на eth_getLogs.
Наступні кроки
- Перегляньте каталог наборів даних, щоб ознайомитися з усіма наборами даних, які індексує BlockVectra.
- Перегляньте безкоштовний план і ціни, щоб дізнатися, що включено у ваш акаунт.
- Увійдіть до консолі, щоб створити API key.
Востаннє оновлено:
Вибір RPC-провайдера
Оцінюйте вартість методів RPC, діапазони журналів, безкоштовні кредити, ліміти швидкості, покриття мереж, Push та Data API, автентифікацію та доступ для агентів за допомогою тестів робочого навантаження.
Трейси транзакцій
Реконструюйте дерева викликів виконання для транзакції: метод JSON-RPC debug_traceTransaction з дозволеними трейсерами та захисними обмеженнями, а також ендпоінти Data API getTransactionTrace і getBlockTraces з їхніми межами покриття.