Robinhood Chain Testnet RPC-Starter: Schlüssellose Lesezugriffe, WebSocket-Logs, dann Mainnet

Starten Sie mit dem Robinhood Chain Testnet RPC: öffentliche RPC-URL, schlüssellose Lesezugriffe, WebSocket-Logs mit einem API key, Faucet-Zugang und Wechsel desselben Schlüssels zum Mainnet.

BlockVectra stellt das Robinhood Chain Testnet (Chain-ID 46630) über JSON-RPC und WebSocket bereit, und derselbe API key funktioniert auch im Robinhood Chain Mainnet. Dieser Leitfaden führt Sie anhand der Vorlage Robinhood Chain Testnet starter durch drei Schritte: das Testnet ohne Schlüssel auslesen, programmatisch ein Konto erstellen und Logs streamen sowie anschließend denselben Schlüssel im Mainnet verwenden. Endpunktparameter, Methodenrichtlinien und tokenisierte Aktiendaten finden Sie im Leitfaden zur Robinhood Chain.

Vorlage ausführen

git clone https://github.com/blockvectra/robinhood-testnet-starter
cd robinhood-testnet-starter
npm install
npm run typecheck

Node.js 18 oder neuer. Die drei Skripte sind npm run step1, npm run step2 und npm run step3. Optionale Variablen (BLOCKVECTRA_API_KEY, WALLET_PRIVATE_KEY) werden aus der Shell ausgelesen; .env wird nicht automatisch geladen.

Schritt 1: Testnet ohne Schlüssel auslesen

Der öffentliche Endpunkt https://api.blockvectra.com/v1/robinhood_testnet/public stellt Wallet-JSON-RPC-Methoden ohne Konto und ohne API key bereit. Fragen Sie die EIP-155 Chain-ID direkt ab:

curl -s "https://api.blockvectra.com/v1/robinhood_testnet/public" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_chainId","params":[]}'

Die Antwort lautet {"jsonrpc":"2.0","id":1,"result":"0xb626"}; 0xb626 ist die hexadezimale Chain-ID, was dezimal 46630 entspricht.

Die Vorlage liest den Chain-Eintrag aus GET /v1/chains aus und erstellt daraus einen viem-Client, sodass Chain-Name und Chain-ID nicht fest im Code hinterlegt sind. Aus src/shared.ts:

import { createPublicClient, defineChain, http, webSocket } from "viem";

export const API_BASE = "https://api.blockvectra.com/v1";

export interface ChainEntry {
  chain: string;
  name: string;
  chain_id: number;
  data: boolean;
  ws: boolean;
  subscriptions: string[];
  public?: { url: string };
}

export async function getChain(slug: string): Promise<ChainEntry> {
  const res = await fetch(`${API_BASE}/chains`);
  if (!res.ok) throw new Error(`GET /v1/chains failed: ${res.status}`);
  const { chains } = (await res.json()) as { chains: ChainEntry[] };
  const entry = chains.find((c) => c.chain === slug);
  if (!entry) throw new Error(`${slug} not found in /v1/chains`);
  return entry;
}

export function toViemChain(entry: ChainEntry, rpcUrl: string) {
  return defineChain({
    id: entry.chain_id,
    name: entry.name,
    nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
    rpcUrls: { default: { http: [rpcUrl] } },
  });
}

export function httpClient(entry: ChainEntry, url: string, apiKey?: string) {
  return createPublicClient({
    chain: toViemChain(entry, url),
    transport: http(url, apiKey ? { fetchOptions: { headers: { "x-api-key": apiKey } } } : undefined),
  });
}

export function wsClient(entry: ChainEntry, apiKey: string) {
  const base = "wss://api.blockvectra.com/v1";
  const url = `${base}/${entry.chain}/${apiKey}`;
  return createPublicClient({ chain: toViemChain(entry, url), transport: webSocket(url) });
}

Mit diesem Modul liest src/step1-public-read.ts die Chain-ID, den neuesten Block und den Kontostand einer Adresse aus:

import { formatEther, type Address } from "viem";
import { API_BASE, getChain, httpClient } from "./shared.js";

const SLUG = "robinhood_testnet";
// Any address works; override with the first CLI argument.
const address = (process.argv[2] ?? "0x0000000000000000000000000000000000000000") as Address;

const chain = await getChain(SLUG);
const client = httpClient(chain, `${API_BASE}/${SLUG}/public`);

const [chainId, blockNumber, balance] = await Promise.all([
  client.getChainId(),
  client.getBlockNumber(),
  client.getBalance({ address }),
]);

console.log(`chain       : ${chain.name} (${SLUG})`);
console.log(`eth_chainId : ${chainId} (0x${chainId.toString(16)})`);
console.log(`block       : ${blockNumber}`);
console.log(`balance     : ${formatEther(balance)} ETH  (${address})`);

Schritt 2: Programmatisch ein Konto erstellen und Logs abonnieren

src/step2-key-and-logs.ts meldet sich mit einem Wallet (SIWE, EIP-191) unter https://console-api.blockvectra.com/v1 an. Die erste Anmeldung erstellt das Konto; der Client erstellt anschließend einen API key. Neue Konten erhalten 30,000,000 CU bei der Registrierung — keine Kreditkarte erforderlich.

import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
import type { Hex } from "viem";

const CONSOLE_API = "https://console-api.blockvectra.com/v1";
const REF = "gh-robinhood-testnet-starter";

async function post<T>(path: string, body: unknown, token?: string): Promise<T> {
  const res = await fetch(`${CONSOLE_API}${path}`, {
    method: "POST",
    headers: { "Content-Type": "application/json", ...(token ? { Authorization: `Bearer ${token}` } : {}) },
    body: JSON.stringify(body),
  });
  if (!res.ok) throw new Error(`${path} failed: ${res.status} ${await res.text()}`);
  return (await res.json()) as T;
}

async function provisionKey(): Promise<string> {
  const pk = (process.env.WALLET_PRIVATE_KEY as Hex | undefined) ?? generatePrivateKey();
  const account = privateKeyToAccount(pk);
  console.log(`wallet: ${account.address}`);

  // SIWE: ask for a challenge, sign it verbatim (EIP-191), log in. A first sign-in creates the account.
  const { message } = await post<{ message: string }>("/auth/siwe/challenge", {
    address: account.address,
    purpose: "login",
  });
  const signature = await account.signMessage({ message });
  const login = await post<{ session: { token: string }; account_created: boolean }>("/auth/siwe/login", {
    message,
    signature,
    ref: REF,
  });
  console.log(`account_created: ${login.account_created}`);

  const created = await post<{ api_key: string }>("/keys", { label: "robinhood-testnet-starter" }, login.session.token);
  return created.api_key;
}

const apiKey = process.env.BLOCKVECTRA_API_KEY?.trim() || (await provisionKey());

Wenn Sie bereits einen Schlüssel besitzen, überspringt export BLOCKVECTRA_API_KEY=... die Registrierung. Ohne WALLET_PRIVATE_KEY generiert das Skript ein temporäres Wallet im Arbeitsspeicher und verwirft es nach Ende der Ausführung; setzen Sie WALLET_PRIVATE_KEY in Ihrer lokalen Umgebung, wenn Sie sich erneut beim selben Konto anmelden möchten.

Die WebSocket-URL bindet den Schlüssel im Pfad ein: wss://api.blockvectra.com/v1/robinhood_testnet/{api_key}. Die Vorlage prüft das aktuelle ws-Flag und die subscriptions-Liste aus GET /v1/chains, bevor das Abonnement gestartet wird:

const chain = await getChain("robinhood_testnet");
if (!chain.ws || !chain.subscriptions.includes("logs")) {
  throw new Error(`robinhood_testnet does not offer a logs subscription in /v1/chains`);
}
console.log(`subscriptions (from /v1/chains): ${chain.subscriptions.join(", ")}`);

const client = wsClient(chain, apiKey);
const stop = client.watchEvent({
  address: "0x1234567890123456789012345678901234567890",
  onLogs: (logs) => {
    for (const l of logs) console.log(`block ${l.blockNumber} ${l.address} topic0=${l.topics[0]}`);
  },
  onError: (e) => console.error("subscription error:", e.message),
});

Jeder Filter für ein logs-Abonnement muss eine address oder ein topic0 enthalten; ersetzen Sie die Beispieladresse durch den Contract, den Sie überwachen möchten. Filterregeln, Close-Codes und Wiederverbindungslogik finden Sie im Leitfaden zu WebSocket-Abonnements.

Schritt 3: Denselben Schlüssel zum Mainnet wechseln

Der Wechsel zum Mainnet erfordert nur die Änderung eines einzelnen Worts: Verwenden Sie den Slug robinhood_mainnet und denselben API key. src/step3-mainnet.ts liest die Mainnet-Blocknummer aus und ruft die Data API für Robinhood-Aktientoken auf:

const apiKey = process.env.BLOCKVECTRA_API_KEY?.trim();
if (!apiKey) throw new Error("Set BLOCKVECTRA_API_KEY (run step 2 first, or create a key in the console).");

const mainnet = await getChain("robinhood_mainnet");

// JSON-RPC with the key: the chain slug changes.
const client = httpClient(mainnet, `${API_BASE}/${mainnet.chain}`, apiKey);
console.log(`mainnet block: ${await client.getBlockNumber()}`);

// Data API: Robinhood stock-token leaderboard (see the Robinhood Chain guide).
const res = await fetch(`${API_BASE}/data/${mainnet.chain}/stocks`, { headers: { "x-api-key": apiKey } });
if (!res.ok) throw new Error(`Data API failed: ${res.status} ${await res.text()}`);
console.log(JSON.stringify(await res.json(), null, 2).slice(0, 2000));

Derselbe Bestenlisten-Endpunkt in cURL:

curl -s -H "x-api-key: $BLOCKVECTRA_API_KEY" \
  "https://api.blockvectra.com/v1/data/robinhood_mainnet/stocks"

Die Data API ist ausschließlich im Mainnet verfügbar: GET /v1/chains meldet data: false für robinhood_testnet und data: true für robinhood_mainnet. Anforderungsparameter und Antwortstrukturen finden Sie im Leitfaden zu tokenisierten Aktien.

Limits und Funktionen über die API ermitteln

Rufen Sie GET /v1/chains ab, um die aktuellen Flags für jsonrpc, data, ws und subscriptions, die zulässigen JSON-RPC-Methoden, Log-Blockbereiche, State-Aufbewahrungszeiträume und den öffentlichen Endpunkt jeder Chain einzusehen. Rufen Sie GET /v1/plans ab, um aktuelle Preise und Tariflimits zu prüfen.

curl -s "https://api.blockvectra.com/v1/chains"

Verwandte Leitfäden

Nächste Schritte

Zuletzt aktualisiert:

Auf dieser Seite