Usa l’API dell’explorer per leggere la chain 20 da uno script, un bot o un backend senza gestire un nodo. La guida completa con ogni campo si trova nel repository dell’explorer, randscan.org/docs/api.md; questa pagina ne è il riepilogo.
| URL di base | https://randscan.org/api/v1 |
| WebSocket | wss://randscan.org/ws |
| anonimo | 60 richieste al minuto per IP |
| con una chiave API | 600 richieste al minuto; le chiavi si ottengono da randscan.org/dashboard e si inviano come Authorization: Bearer rsk_… o X-API-Key |
Che cosa può mostrare l’explorer di una chain shielded
In questa API non compaiono da nessuna parte account, saldi, mittenti o destinatari e, dalla chain 14, nemmeno un asset pubblico su un bundle: un trasferimento di RAND e un trasferimento di un qualsiasi token RPL hanno la stessa forma. Ciò che serve è: ogni blocco; il bundle con asset nascosto di ogni transazione così come pubblicato (anchor, quattro nullifier, quattro commitment, commissione, burn_a, burn_r, burn_asset, ora, dimensioni della prova e della busta e, dalla chain 17, l’auth_commit e la dimensione della prova di autorizzazione); l’azione che una transazione conteneva e i suoi campi pubblici, inclusi la registrazione, i mint e i burn di un token RPL, le azioni di governance del bridge e la transizione di stato di un invoke RPL-2; il registro dei token RPL; le celle e il vault di un programma; l’albero dei commitment foglia per foglia; l’insieme dei nullifier; il registro dei validator; l’audit dell’offerta; lo stato pubblico del bridge, inclusi la pausa dei mint e l’insieme dei guardiani PQ. Quale asset abbia spostato un trasferimento è visibile solo a una viewing key o a una transaction key, nel browser. GET /accounts/:address risponde 410 { "error": "no_accounts" }.
Convenzioni: gli importi sono stringhe decimali di unità. Un importo il cui asset_index indica un token diverso da RAND (indice 0) è espresso nella più piccola unità di quel token, non nei nove decimali di RAND; risolvi l’indice tramite GET /tokens/:id prima di dividere. registration_fee e next_index sono i due campi che l’explorer serve come semplici numeri JSON; hash, id di programma, commitment e nullifier sono 64 caratteri esadecimali minuscoli; gli indirizzi dei validator sono in base58; le altezze sono interi decimali a partire da 0; vengono indicizzati solo i blocchi confermati, quindi un blocco presente nell’API è definitivo. Le liste accettano page (da 1) e limit (da 1 a 100, predefinito 20), restituiscono { "data": [...], "pagination": { page, limit, total, total_pages, has_next, has_prev } }, dal più recente. Gli errori sono { "error", "message", "code" } con 400, 404, 410, 429 o 500.
Endpoint
| metodo e percorso | restituisce |
|---|---|
GET /health | stato dell’explorer e ritardo dell’indexer |
GET /stats | chain id, altezza, view, dimensione dell’albero, numero di validator, stake totale, offerta, numero di programmi, tempo medio di blocco, epoch, l’hash di genesi e la build del nodo; hc_bundle e hc_auth; limits (i cinque limiti di genesi, poi envelope_bytes, hardening_v6, hc_auth, i gas_price e byte_price di genesi, gas_metering, bundle_gas_limit, adjust_bps e, su un nodo dalla v0.6.8, program_state); gas_prices, i prezzi correnti in punta alla chain. limits non include gli altri nuovi campi della v0.6.8 (binding_domain, proof_window_blocks, i tetti di prezzo, admission_by_vote, testnet): leggili da rand_getLimits del nodo |
GET /supply | l’audit dell’offerta del nodo alla lettera, inclusi i quattro contatori vesting_*, tutti "0" sulla chain 20, il cui genesi non ha una sezione vesting, e program_rand_out e program_rand_held di RPL-2, i RAND pagati dai vault dei programmi e i RAND che questi ancora detengono |
GET /bridge | lo stato pubblico del bridge: emitter, emitters, guardian_set_index, guardians, pq_guardians, mint_paused, pause_nonce, list_nonce, pause_key, registration_fee, burn_sequence, next_index (null dalla chain 14), rotation_nonce, rules_v2 (con global_minted_in_window e global_mint_headroom), min_inbound_sequence, assets ed endpoints, la rappresentazione propria dell’explorer di ciascun emitter così come la stampa la chain di origine. Non serve i campi fees, rotation_rules e pending_rotations della v0.6.8 del nodo: leggili da rand_getBridgeState |
GET /bridge/assets | una riga per backing: la riga del registro (index, chain, token, asset_id, locked, minted_today, mint_cap_per_day e, su un nodo v0.6.8, minted_in_window, mint_window_secs e mint_headroom, il deposito più grande che i limiti ammettono ora) unita a symbol, name, decimals e backings, e ai totali indicizzati. Per backing: burns, burned, outstanding (il locked del registro) e deposits/deposited solo quando il token ha un unico backing (null altrimenti: un deposito indica il token che ha coniato, non la moneta bloccata per esso). Per token, identici su ogni riga con lo stesso index: token_deposits, token_deposited, token_burns, token_burned, first_height, last_height; conta ogni index una sola volta quando calcoli i totali |
GET /bridge/tokens | la allowlist dei token, una lista statica: USDT e USDC su Ethereum, BSC, Tron e Solana, con USDC su Tron dismesso |
GET /tokens | l’intero registro dei token RPL come memorizzato in cache dal nodo: enabled, registration_fee, next_index, tokens |
GET /tokens/:id | un token per indice di registro, id di 64 caratteri esadecimali o forma testuale rpl1…, più deploy_tx e supply_history; 404 se nessuno corrisponde |
GET /nodes | il nodo dell’explorer e i suoi peer, con geolocalizzazione |
GET /provers | i prover delegati noti all’explorer (il suo elenco; la chain non ne tiene traccia): se ciascuno risponde al proprio prover_info, la sua capacità e commissione, e dove si trovano i suoi host |
GET /blocks?page&limit&proposer, GET /blocks/latest?limit, GET /blocks/:id | blocchi, per altezza o hash |
GET /transactions?page&limit&kind&height&validator&program, GET /transactions/latest, GET /transactions/:hash | transazioni; kind è transfer, mint, deploy, call, bond, unbond, withdraw, bridge_attest, bridge_burn, register_token, token_mint, set_authority, token_burn, pause_mints, unpause_mints, register_bridged_token, list_backing, invoke. Non esiste token_transfer: il trasferimento di un qualsiasi token RPL è transfer |
GET /transactions/:hash/envelopes | le note create da una transazione con le relative buste: i quattro slot del bundle, dummy inclusi, più le note calcolate dalla chain che vengono aggiunte da un deposito bridge_attest, da un token_mint, dal mint iniziale di un register_token o dai pagamenti di un invoke; per una call, h_in e la trascrizione sigillata dell’input |
GET /envelopes?from_leaf&limit | foglie con buste, dalla più vecchia, fino a 1.000 per pagina, per la scansione della cronologia |
GET /notes?page&limit, GET /notes/:id | foglie dell’albero, per commitment o indice di foglia |
GET /nullifiers/:nf | la transazione che ha pubblicato un nullifier |
GET /validators, GET /validators/:address | il registro, con share_percent, blocks_proposed, ultima altezza proposta |
GET /programs?page&limit, GET /programs/:id | programmi distribuiti (base_pc, words_len, code_hash, public_words_len, public_digest) con il numero di call e invoke; le call e gli invoke recenti di un programma e il suo program_state, letto in tempo reale dal nodo: vault (per asset), le prime 100 cells in ordine di chiave e cells_next |
GET /programs/:id/cells?after&limit | una pagina delle celle del programma in ordine di chiave, in tempo reale dal nodo (limit da 1 a 1.000, predefinito 100): { "cells", "next" }; 404 su una chain senza sezione program_state |
GET /search?q= | blocchi, transazioni, programmi, note, nullifier e validator |
curl -s https://randscan.org/api/v1/stats
curl -s https://randscan.org/api/v1/tokens/1
curl -s https://randscan.org/api/v1/transactions/8aa13d1f76d28f63a46c30bb09ef44b1ba35083ca80ba7301997f98e5f783666
Un riepilogo di transazione (un mint del faucet di 10 RAND all’altezza 102.197 della chain 18):
{
"hash": "a20b…feb5", "height": 102197, "block_hash": "f362…a06f", "tx_index": 0,
"kind": "mint", "fee": "0", "timestamp_ms": 1790777106034,
"has_bundle": false, "program": null, "validator": "EdrEC2QRQrQF64iRXxF9927jNj6RidiHHByzx5xD6F1e",
"amount": "10000000000", "asset_index": null
}
amount è valorizzato solo per i tipi con un importo pubblico — mint, bond, unbond, withdraw, bridge_attest, bridge_burn, token_mint, token_burn e un register_token con un mint iniziale — ed è null per un trasferimento, il cui asset_index è sempre null a sua volta. has_bundle è false per mint, unbond, withdraw, pause_mints e unpause_mints, che non portano alcun bundle e non pagano commissione. Il dettaglio aggiunge chain_id, bundle e, per ciascun tipo: words_len di un deploy; call_proof_len, input_envelope_len e receipt (tx, program, tier, outputs, height, index, h_in, h_pub) di una call; registered di un bond; action_nonce di un unbond o di un withdraw; attestation_len, recipient, note_time, deposit_r, commitment, pq_signers di un’attestazione del bridge; relayer_fee, to_chain, bridge_to, bridge_token di un burn del bridge; token_action di un’azione RPL (i campi propri dell’azione, etichettati da kind), con recipient, note_time, deposit_r per una nota coniata e action_nonce per un token_mint o un set_authority; bridge_governance di un’azione di governance del bridge, con pq_signers su tutte tranne pause_mints; call_proof_len, input_envelope_len, receipt e transition di un invoke (la rappresentazione del nodo: le celle lette e scritte, l’inflow e ogni nota pays e mints con il suo recipient, time, r e cm). Un tipo della v0.6.8 che questa build dell’explorer non conosce (admit_validator, slash_equivocation, le rotazioni _v2, cancel_rotation) è other.
Sulla chain 20, con le commissioni del bridge, l’amount di un bridge_attest e di un bridge_burn è l’importo lordo: quello firmato dai guardiani o quello bruciato dal bundle. L’explorer non serve il deposito netto, l’importo rilasciato né la nota di commissione; leggili da rand_getTransaction del nodo (deposit_amount, release_amount, fee_note) e da rand_getBridgeBurn. Il burn di 0,999 zUSD all’altezza 2.899 qui risulta "amount": "99900000"; i guardiani hanno firmato un rilascio di 99800100.
Il bundle nel dettaglio di una transazione è il bundle con asset nascosto, senza campo asset e senza un secondo bundle su un burn. Questo ha pagato la call dell’esempio curl qui sopra, all’altezza 98.335 della chain 18; quella transazione non esiste sulla chain 20, dove il terzo curl risponde 404:
"bundle": {
"anchor": "b814…b1ed",
"nullifiers": ["49d4…a766", "3363…61ea", "aac0…fcfc", "546c…3efd"],
"commitments": ["b52b…4f7b", "9ddd…0448", "5fa7…1630", "2827…8343"],
"fee": "6191437", "burn_a": "0", "burn_r": "0", "burn_asset": 0, "time": 98185,
"proof_len": 1504260, "envelope_len": [1860, 1860, 1860, 1860],
"auth_commit": "0bda…6512", "auth_proof_len": 1367303
}
auth_commit e auth_proof_len sono l’autorizzazione divisa (chain 17 e successive, dove limits.hc_auth è impostato): la prova del bundle è costruita a partire dalla viewing key e pubblica auth_commit, e una seconda, piccola prova sulla spend key, legata alla stessa transazione, deve corrispondervi. Entrambe le prove sono riportate solo per lunghezza. Ogni busta sulla chain 20 è di 1.860 byte (limits.envelope_bytes) e porta un memo cifrato; le chain fino alla 17 sigillavano 1.348 byte. Il limite di gas dichiarato di una call è un valore pubblico della sua prova, non un campo della receipt, quindi l’explorer non lo mostra per transazione; la commissione pagata è in fee.
burn_a è l’asset privato bruciato, diverso da zero solo in un token_burn, in un bridge_burn o in un invoke che deposita o brucia un token, con burn_asset che indica l’indice del registro; burn_r sono i RAND bruciati, diversi da zero solo in un bond o in un invoke che deposita RAND nel vault del programma.
Sulla chain 20 zUSD (“Shielded USD”, otto decimali) si trova all’indice 1, elencato nel genesis con tutti e sette i backing (registered_at 0, quindi deploy_tx è null) e riportato dalla chain 14 con lo stesso asset id. GET /bridge/assets restituisce quindi sette righe sotto l’indice 1. Altri cinque token sono stati registrati sulla chain 20 nel suo primo giorno, agli indici da 2 a 6, tre dei quali con un programma come autorità di mint; GET /tokens li elenca. Sulla chain 20 GET /bridge riporta rules_v2 con un tetto globale di mint di 4,000 zUSD ("400000000000") per finestra di 86,400 secondi, rotation_nonce 0, burn_sequence 13 al genesis e un min_inbound_sequence di 3 per le chain di origine 2, 3 e 4 e di 7 per la chain di origine 5 (1 e 4 sulla chain 19): la soglia minima di replay del genesis, ovvero la sequenza di lock più bassa che l’attestazione di una chain di origine può riportare per essere coniata qui. Sulla chain 14 è stato registrato all’altezza 256 da un register_bridged_token, con gli altri sei backing aggiunti da transazioni list_backing.
Aprire le envelope nel browser
Un’envelope è un dato pubblico della chain e l’explorer non detiene alcuna chiave. La sua pagina della transazione e la pagina History aprono le envelope nel browser con una build WebAssembly del codice stesso del nodo (crates/randscan-viewing): incolla una viewing key (nk, 64 hex) per vedere ogni nota inviata o ricevuta da quella parte, una chiave di transazione per aprire un singolo pagamento, una chiave di chiamata per aprire gli input di una singola chiamata, oppure un file di chiavi del wallet, del quale viene conservata solo la viewing key derivata. Una nota aperta viene verificata ricalcolandone l’impegno. Il suo asset divulgato è l’indice del registro dei token, risolto tramite GET /tokens per ottenere simbolo e decimali; è l’unico punto in cui, per un trasferimento, un importo è legato a un asset. Uno slot fittizio non si apre con nessuna chiave e appare identico a una nota che non è tua. Nulla di una chiave transita sulla rete; per costruire lo stesso strumento, recupera /envelopes e /transactions/:hash/envelopes e usa il crate.
Feed WebSocket
Connettiti a wss://randscan.org/ws e sottoscrivi blocks, transactions o stats:
{ "type": "subscribe", "channel": "blocks" }
{ "type": "new_block", "block": { … BlockSummary … } }
{ "type": "new_transaction", "transaction": { … TransactionSummary … } }
{ "type": "stats_update", "stats": { … } }
Invia { "type": "ping" } ogni 30 secondi attraverso i proxy. Il feed non prevede replay: in caso di disconnessione, riconnettiti e recupera i dati mancanti con GET /transactions?height=.
Eseguire il proprio explorer
Tutto ciò che è qui descritto è servito dall’explorer open source in randprotocol/randscan.org; l’indexer richiede solo il JSON-RPC rand_* di un nodo e un database PostgreSQL.