Wallet-Token-Guthaben-API: ERC-20-Assets und Transferverlauf
Erstellen Sie eine Wallet-Assets-Seite mit ERC-20-Token-Guthaben ungleich null, Token-Transferverlauf und Batch-Metadaten. Prüfen Sie die Chain-Abdeckung, paginieren Sie Ergebnisse und skalieren Sie ganzzahlige Beträge anhand der Dezimalstellen.
Erstellen Sie eine Wallet-Assets-Seite mit der Blockchain-Wallet-Data-API: Verwenden Sie die Token Balances API für ERC-20-Bestände ungleich null und die Token Transfers API für den Wallet-Verlauf. Entwickler und KI-Agenten nutzen dieselben authentifizierten Anfragen. Lesen Sie vor der Abfrage GET /v1/status und prüfen Sie data_features sowie data_status der ausgewählten Chain; die Guthabenabdeckung variiert je nach Chain. Anfrageparameter und Antwortschemas finden Sie in der Data-API-Referenz.
Aufgaben, die dieser Leitfaden abdeckt
- Wallet-Token-Guthaben auslesen mit einem API-Schlüssel und ERC-20-Bestände ungleich null paginieren.
- Wallet-Transferverlauf auslesen innerhalb eines festen Blockfensters und Cursorn für die ausgewählte Adresse folgen.
- Token-Metadaten ergänzen, um Namen und Symbole neben rohen ganzzahligen Guthaben anzuzeigen, wobei fehlende Felder erhalten bleiben.
Die drei Arten von Daten, die eine Wallet-Assets-Seite benötigt
Eine Wallet-Assets-Seite kann die ERC-20-Token-Guthaben, den Token-Transferverlauf und die Token-Metadaten einer Adresse anzeigen. Die Data API stellt für jeden Bereich einen Endpunkt bereit:
- Guthaben:
GET /{chain}/addresses/{address}/balancesgibt die ERC-20-Guthaben der Adresse ungleich null zurück, aufsteigend sortiert nach dertoken-Adresse, wobei Token-symbolunddecimalsenthalten sind, sofern verfügbar. Eine Adresse ohne Guthaben gibt200mitdata: []zurück. - Transfers:
GET /{chain}/addresses/{address}/transfersgibt Token-Transfers zurück, an denen die Adresse innerhalb eines erforderlichen Blockfensters beteiligt ist, absteigend sortiert nach(block_number, log_index). - Token-Metadaten:
GET /{chain}/tokens/{token}liest Name, Symbol, Dezimalstellen und Gesamtangebot eines einzelnen Tokens anhand der Contract-Adresse aus;POST /{chain}/tokens:batchliest dieselben Metadaten für bis zu 100 Adressen in einer einzigen Anfrage aus.
Alle drei verwenden https://api.blockvectra.com/v1/data als Basis-URL und den x-api-key-Anfrage-Header, mit robinhood_mainnet als Beispiel-Chain. Sie gehören zu den Fähigkeiten balances, transfers bzw. token_metadata; welche Chains die jeweilige Fähigkeit bieten, sehen Sie auf der Seite Unterstützte Chains. Auf einer Chain ohne die entsprechende Fähigkeit gibt der Endpunkt 422 no_coverage zurück.
Anfrage 1: Adress-Guthaben
Dieser Endpunkt erfordert weniger Parameter und eignet sich daher gut als erste Anfrage für eine Seite:
{chain}(Pfadparameter, erforderlich): Chain-Kennung, derchain-Wert eines Eintrags inGET /chains(zum Beispielrobinhood_mainnet). Der Abgleich erfolgt exakt und case-sensitiv; Aliase und numerische Chain-IDs werden nicht akzeptiert.{address}(Pfadparameter, erforderlich): 20-Byte-Adresse; das Präfix0xist optional und Groß-/Kleinschreibung wird gleichermaßen akzeptiert.limit(Query-Parameter, optional): Seitengröße. Standardmäßig 50; Werte über 500 werden auf 500 begrenzt;0oder ein Nicht-Ganzzahl-Wert gibt400 bad_requestzurück.cursor(Query-Parameter, optional): Dernext_cursorder vorherigen Antwort, der unverändert übergeben wird, um die nächste Seite abzurufen. Ein Cursor ist nur für die Chain, den Endpunkt und die Query-Parameter gültig, die ihn ausgegeben haben; eine Wiederverwendung an anderer Stelle gibt400 bad_requestzurück.
Er ist keyset-paginiert: next_cursor erscheint nur, wenn eine weitere Seite vorhanden ist. Auf der letzten Seite fehlt der Schlüssel vollständig, niemals 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"Der Antwort-Envelope ist AddressBalanceListEnvelope, der data und meta enthält. Jedes Element von data ist ein AddressBalance:
| Feld | Typ | Beschreibung |
|---|---|---|
token | string (Adresse) | Token-Contract-Adresse; die kanonische Form ist 0x plus 40 hexadezimale Kleinbuchstaben. |
balance | string (Dezimal) | Rohes ganzzahliges Guthaben, das 2^53 überschreiten kann, zurückgegeben als einfache Dezimalzeichenfolge — niemals eine JSON-Zahl, wissenschaftliche Notation oder Hex. |
symbol | string oder null | Token-Symbol oder null, falls nicht verfügbar. |
decimals | integer oder null | Token-Dezimalstellen, 0–255, oder null, falls nicht verfügbar. |
Anfrage 2: Adress-Transfers
Der Transfers-Endpunkt erfordert ein explizites Blockfenster: from_block und to_block sind beide erforderlich und müssen from_block <= to_block erfüllen. Er akzeptiert einige weitere Parameter:
standard(Query-Parameter, erforderlich):erc20odererc721. Adressbezogene Abfragen deckenerc1155nicht ab; die Übergabe gibt422 no_coveragezurück.direction(Query-Parameter, optional):in,outoderany; standardmäßiganyund filtert nach Richtung relativ zur Adresse.token(Query-Parameter, optional): Beschränkt die Ergebnisse auf einen einzelnen Token-Contract.clamp(Query-Parameter, optional): Nur die Literal-Zeichenfolgetrueaktiviert dies; jeder andere Wert wird alsfalsebehandelt.
Fenstergrenzen und Finalität: Ein explizites to_block über as_of_block gibt 409 not_indexed_yet zurück, es sei denn, clamp=true kürzt es auf as_of_block herunter; ein Fenster, das breiter als das Limit der Chain ist (limits.max_window_blocks aus GET /chains), gibt 409 window_too_large zurück, es sei denn, clamp=true schneidet am älteren Ende ab (erhöht from_block und hält to_block fest). Wenn from_block selbst bereits hinter as_of_block liegt, bleibt es auch mit clamp=true ein hartes 409. Wenn das Fenster gekürzt oder nur teilweise abgedeckt ist, lautet meta.coverage in der Antwort "partial"; andernfalls "full".
In den Transfer-Datensätzen enthalten ERC-20-Elemente zusätzlich amount; ERC-721-Elemente enthalten token_id. Beide enthalten token, standard, from, to, block_number, block_timestamp, tx_hash, tx_index und log_index.
export BLOCKVECTRA_API_KEY=rgw_your_api_key
# 1) Read as_of_block from the balances response.
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 truncates a too-wide window, or a to_block above as_of_block, instead of returning 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"Durch alle Transfers paginieren
Der next_cursor des Adress-Transfers-Endpunkts ist optimistisch: Er erscheint nur, wenn die Seite genau limit Zeilen zurückgegeben hat, sodass eine Seite einen next_cursor tragen kann und sich dennoch als die letzte Seite herausstellt. Halten Sie nicht an, wenn eine Seite leer ist; folgen Sie next_cursor, bis der Schlüssel fehlt.
Der folgende Code ruft jeden Transfer im Fenster ab:
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 truncates from the older end
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; // absent on the last page
} while (cursor);Anfrage 3: Token-Metadaten und tokens:batch
Lesen Sie einen einzelnen Token mit GET /{chain}/tokens/{token} aus; der Pfad erfordert lediglich {chain} und {token}, ohne Paginierung. Der Antwort-Envelope ist TokenEnvelope, und data ist ein Token:
| Feld | Typ | Beschreibung |
|---|---|---|
address | string (Adresse) | Token-Contract-Adresse. |
standard | string | erc20, erc721 oder unknown. |
name | string oder null | Token-Name oder null, falls nicht verfügbar. |
symbol | string oder null | Token-Symbol oder null, falls nicht verfügbar. |
decimals | integer oder null | Token-Dezimalstellen, 0–255, oder null, falls nicht verfügbar. |
total_supply | string oder null | Rohes Gesamtangebot; die API wendet keine decimals-Skalierung an. null, falls nicht verfügbar. |
first_seen_block | integer (int64) | Blockhöhe, bei der der Token erstmals gesehen wurde. |
metadata_updated_at | string (Zeitstempel) | UTC-Zeitpunkt, zu dem die Metadaten zuletzt aktualisiert wurden. |
metadata_block | integer (int64) | Blockhöhe, bei der die Metadaten ausgelesen wurden. |
metadata_status | string | ok, partial oder unavailable. |
metadata_issues | object | Problemaufzeichnungen pro Feld mit den Schlüsseln name, symbol, decimals, total_supply und den Werten reverted, no_data, invalid_encoding oder temporarily_unavailable. |
Ein {token}, der keine gültige 20-Byte-Adresse ist, gibt 400 bad_request zurück; ein unbekannter {token} gibt 404 not_found zurück; eine unbekannte {chain} gibt 404 unknown_chain zurück.
Der Guthaben-Endpunkt enthält bereits symbol und decimals, sofern verfügbar, jedoch können beide null sein. Um Name und Dezimalstellen für jeden Token in einer Wallet zu ergänzen, verwenden Sie POST /{chain}/tokens:batch:
- Der Request-Body ist
{"addresses": [...]}mit höchstens 100 Adressen pro Anfrage; mehr als 100 Einträge oder ein Eintrag, der keine gültige 20-Byte-Adresse ist, gibt400 bad_requestzurück (die Anfrage schlägt bei der ersten ungültigen Adresse fehl, auf die sie trifft). - Adressen, die nicht gefunden werden, lösen keinen Fehler aus; sie werden in
data.missingaufgeführt, währenddata.tokensnur diejenigen Token enthält, deren Metadaten gefunden wurden. - Doppelte Adressen werden sowohl in
tokensals auch inmissingdedupliziert, jeweils in der Reihenfolge des ersten Auftretens in der Anfrage.
export BLOCKVECTRA_API_KEY=rgw_your_api_key
# Single token
curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/tokens/0x1111111111111111111111111111111111111111" \
-H "x-api-key: $BLOCKVECTRA_API_KEY"
# Batch: up to 100 addresses per request
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"]}'Beträge anhand von Dezimalstellen skalieren
Das Guthabenfeld balance und das ERC-20-Transferfeld amount sind rohe Ganzzahlen, die als Dezimalzeichenfolgen dargestellt werden (UInt256String); auch das total_supply eines Tokens ist eine rohe On-Chain-Ganzzahl ohne angewandte decimals-Skalierung. Um eine lesbare Menge anzuzeigen, teilen Sie durch die decimals dieses Tokens.
decimalsstammt aussymbol/decimalsdes Guthabenelements selbst oder ausGET /{chain}/tokens/{token}undPOST /{chain}/tokens:batch; es kannnullsein.- Diese Werte können
2^53überschreiten; führen Sie die Berechnung daher nicht mit einer JSON-Zahl durch: Verwenden SieBigIntin TypeScript undDecimalin Python und parsen Sie die Dezimalzeichenfolge unverändert, um Präzisionsverluste zu vermeiden.
function toDisplayAmount(raw: string, decimals: number | null): string {
if (decimals === null) return raw; // no decimals metadata: keep the raw integer
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 is a raw decimal string; decimals comes from the same item or tokens:batch.
const display = toDisplayAmount(balance.balance, balance.decimals);Datenaktualität
Jede chainbezogene Erfolgsantwort enthält meta:
as_of_block: Der neueste vollständig geschriebene Block der Chain. Blockbezogene Endpunkte liefern Daten bis zu dieser Höhe.safe_block: Eine Markierung, die den Konsens-Block-Tagsafedes Nodes angibt (null, solange unbekannt). Liegt niemals unterfinalized_blockund führt weder zum Abschneiden, Abweisen noch zum Verzögern von Antworten.finalized_block: Eine Markierung, die den Konsens-Block-Tagfinalizeddes Nodes angibt (null, solange unbekannt). Führt weder zum Abschneiden, Abweisen noch zum Verzögern von Antworten; Clients entscheiden selbst, welche Sicherheit sie anhand der Markierung benötigen (beispielsweise einen Bestätigungsstatus).coverage:"full"oder"partial". Adress-Transfers und ähnliche Endpunkte melden"partial", wennclampdas bereitgestellte Fenster eingeengt hat oder wenn das Fenster vor dem ersten indexierten Block der Chain beginnt.refreshed_at: Zeitpunkt, zu dem die Daten hinter der Antwort zuletzt aktualisiert wurden (UTC). Kannnullsein:nullbedeutet, dass die Aktualisierungszeit der Daten unbekannt ist und sie als veraltet behandelt werden sollten; blockbasierte Endpunkte geben stets einen Wert zurück.- Es wiederholt außerdem
chain,chain_slugundchain_external_id.
Ein gängiges Muster: Lesen Sie meta.as_of_block aus einer beliebigen ersten Antwort aus, um bis zum neuesten indexierten Block zu lesen, und prüfen Sie meta.safe_block / meta.finalized_block, falls Sie einen bestätigten Status anzeigen möchten.
CU-Schätzung für einen Seitenaufruf
Jede Methode wird nach ihrem CU-Gewicht abgerechnet, das aus der Plans-API der Plattform ausgelesen wird:
CU-Gewichtung pro Aufruf
| Methode | CU pro Aufruf |
|---|---|
data.address_balances | 25 |
data.address_transfers | 25 |
data.tokens_batch | 10 |
Ein Seitenaufruf (geschätzt)
1 balances-Anfrage + 3 Transfer-Seiten + 1 tokens:batch-Anfrage(n), 5 Aufrufe insgesamt, ca. 110 CU. Der tatsächliche Verbrauch hängt von der Anzahl der Seiten und Token ab.
Abrechnungsentscheidungen und nicht abgerechnete Fehlerantworten finden Sie unter Abrechnungsregeln. Wenn Sie statt des indexierten Transferverlaufs Logs aus den neuesten Blöcken benötigen, lesen Sie zuerst Aktuelle Node-Daten vs. indexierter Verlauf, bevor Sie entscheiden, ob Sie zu eth_getLogs wechseln.
Nächste Schritte
- Datensatzverzeichnis durchsuchen, um alle von BlockVectra indexierten Datensätze zu sehen.
- Kostenlosen Tarif und Preise ansehen, um zu prüfen, was Ihr Konto beinhaltet.
- In der Konsole anmelden, um einen API-Schlüssel zu erstellen.
Zuletzt aktualisiert:
Transaktions-Traces
Rekonstruieren Sie Aufrufstrukturen (Call Trees) für eine Transaktion: die JSON-RPC-Methode debug_traceTransaction mit ihren zulässigen Tracern und Schutzmechanismen sowie die Data API-Endpunkte getTransactionTrace und getBlockTraces mit ihren Abdeckungsgrenzen.
Benutzerdefinierter Wallet-RPC
Fügen Sie eine BlockVectra-RPC-URL zu MetaMask oder Rabby hinzu. Finden Sie Chain-IDs und native Symbole, konfigurieren Sie einen Pfad-API-Schlüssel und verwalten Sie einen dedizierten Wallet-Schlüssel.