Motivation
BsoResolver currently trusts whatever public RPC it's pointed at (default list: eth.drpc.org, ethereum.publicnode.com, ethereum-rpc.publicnode.com, rpc.mevblocker.io, 1rpc.io/eth, eth-pokt.nodies.app). A malicious or compromised RPC can return any ENS text record / content hash and we'd cache it as authoritative. For a name-resolution library this is the main remaining trust-on-third-party surface.
We should offer a mode where the RPC response is verified locally via an Ethereum light client.
Proposal: integrate @a16z/helios
Helios (a16z crypto) is a Rust light client with a pure-WASM TypeScript binding. It runs a local consensus layer that verifies beacon-chain sync-committee signatures, then uses those authenticated beacon blocks to prove execution-layer state (account balances, contract storage, eth_call results) from an untrusted execution RPC. The upshot: even if the execution RPC lies, Helios rejects the answer.
- npm:
@a16z/helios@0.11.1 (published 2026-02-27), MIT, deps only eventemitter3 + uuid, ~11.7 MB unpacked, no native bindings.
- Runs in-process in Node.js. No Docker sidecar, no new ports.
- Exposes an EIP-1193 provider; viem accepts it as
transport: custom(heliosProvider) — drop-in for the existing http(rpcUrl) transport we pass to createPublicClient.
- "Syncs in seconds, no storage."
Benefits for bso-resolver
- Trustless ENS resolution:
getEnsText, getEnsAvatar, content-hash lookups, CCIP-read — all flow through Helios and are cryptographically verified against a recent finalized checkpoint. A hostile RPC can no longer inject a fake bitsocial text record.
- No infra changes downstream: consumers (e.g. bitsocial-cli's Docker image) don't gain a new service, port, or binary. It's just an npm dep.
- Portable: pure WASM means no platform matrix (works on linux x64/arm64, macOS, Windows) and no rebuild on Node upgrades.
- Low sync cost: seconds on startup, no disk state, so daemon cold-starts and CI jobs aren't meaningfully slower.
- Clean integration: we keep
BsoResolver's public API, SQLite cache, and viem call sites exactly as they are. Only the transport swaps.
Core change
import { createHeliosProvider } from '@a16z/helios';
import { createPublicClient, custom } from 'viem';
import { mainnet } from 'viem/chains';
const heliosProvider = await createHeliosProvider({
executionRpc, // existing chain provider URL
consensusRpc, // new: public beacon API
network: 'mainnet',
checkpoint, // optional; fetch from a checkpoint-sync endpoint at startup
}, 'ethereum');
await heliosProvider.waitSynced();
const publicClient = createPublicClient({
chain: mainnet,
transport: custom(heliosProvider),
});
Everything downstream (getEnsText, the SQLite cache, BsoResolver public API) stays the same. Cache entries should tag _resolvedBy as helios:<executionRpc> so we can distinguish trustless hits from trusted ones.
API sketch
New optional BsoResolver options:
trustless: boolean (default false — opt-in for first couple of releases).
consensusRpcUrl: string (required when trustless: true).
checkpoint?: string (0x…, optional — fetched from checkpoint-sync endpoint if omitted).
checkpointSyncUrl?: string (optional).
On teardown, call heliosProvider.shutdown().
Endpoints available (mainnet, free, public)
Consensus (beacon) REST API — needs /eth/v1/beacon/... 24/7:
https://ethereum-beacon-api.publicnode.com
https://www.lightclientdata.org
https://ethereum.operationsolarstorm.org (recommended in Helios README)
https://lodestar-mainnet.chainsafe.io
- Ankr beacon (free tier)
- dRPC beacon
Checkpoint sync — from eth-clients/checkpoint-sync-endpoints (verified=true, mainnet):
https://sync-mainnet.beaconcha.in (beaconcha.in)
https://beaconstate.info
https://beaconstate.ethstaker.cc (EthStaker)
https://checkpointz.pietjepuk.net (PietjePuk)
https://mainnet-checkpoint-sync.stakely.io
https://mainnet.checkpoint.sigp.io (Sigma Prime)
https://mainnet-checkpoint-sync.attestant.io
https://beaconstate-mainnet.chainsafe.io
Open questions
- One Helios instance with fallback logic, or N instances mirroring the per-URL
BsoResolver shape? Needs a short look at Helios' JS API for reconnect/shutdown behavior.
- Default consensus + checkpoint lists (pick 3 of each for a rotating default).
- When to flip
trustless to default true — recommend keeping opt-in for 1–2 releases to see sync behavior in the wild first.
Downstream work
Once this lands, bitsocial-cli can bump the dep and add oclif flags (--trustlessEnsResolver, --consensusProviderUrls, --checkpointSyncUrls) on daemon to expose the new mode. No Docker image changes needed.
Motivation
BsoResolvercurrently trusts whatever public RPC it's pointed at (default list:eth.drpc.org,ethereum.publicnode.com,ethereum-rpc.publicnode.com,rpc.mevblocker.io,1rpc.io/eth,eth-pokt.nodies.app). A malicious or compromised RPC can return any ENS text record / content hash and we'd cache it as authoritative. For a name-resolution library this is the main remaining trust-on-third-party surface.We should offer a mode where the RPC response is verified locally via an Ethereum light client.
Proposal: integrate
@a16z/heliosHelios (a16z crypto) is a Rust light client with a pure-WASM TypeScript binding. It runs a local consensus layer that verifies beacon-chain sync-committee signatures, then uses those authenticated beacon blocks to prove execution-layer state (account balances, contract storage,
eth_callresults) from an untrusted execution RPC. The upshot: even if the execution RPC lies, Helios rejects the answer.@a16z/helios@0.11.1(published 2026-02-27), MIT, deps onlyeventemitter3+uuid, ~11.7 MB unpacked, no native bindings.transport: custom(heliosProvider)— drop-in for the existinghttp(rpcUrl)transport we pass tocreatePublicClient.Benefits for
bso-resolvergetEnsText,getEnsAvatar, content-hash lookups, CCIP-read — all flow through Helios and are cryptographically verified against a recent finalized checkpoint. A hostile RPC can no longer inject a fakebitsocialtext record.BsoResolver's public API, SQLite cache, and viem call sites exactly as they are. Only the transport swaps.Core change
Everything downstream (
getEnsText, the SQLite cache,BsoResolverpublic API) stays the same. Cache entries should tag_resolvedByashelios:<executionRpc>so we can distinguish trustless hits from trusted ones.API sketch
New optional
BsoResolveroptions:trustless: boolean(defaultfalse— opt-in for first couple of releases).consensusRpcUrl: string(required whentrustless: true).checkpoint?: string(0x…, optional — fetched from checkpoint-sync endpoint if omitted).checkpointSyncUrl?: string(optional).On teardown, call
heliosProvider.shutdown().Endpoints available (mainnet, free, public)
Consensus (beacon) REST API — needs
/eth/v1/beacon/...24/7:https://ethereum-beacon-api.publicnode.comhttps://www.lightclientdata.orghttps://ethereum.operationsolarstorm.org(recommended in Helios README)https://lodestar-mainnet.chainsafe.ioCheckpoint sync — from eth-clients/checkpoint-sync-endpoints (verified=true, mainnet):
https://sync-mainnet.beaconcha.in(beaconcha.in)https://beaconstate.infohttps://beaconstate.ethstaker.cc(EthStaker)https://checkpointz.pietjepuk.net(PietjePuk)https://mainnet-checkpoint-sync.stakely.iohttps://mainnet.checkpoint.sigp.io(Sigma Prime)https://mainnet-checkpoint-sync.attestant.iohttps://beaconstate-mainnet.chainsafe.ioOpen questions
BsoResolvershape? Needs a short look at Helios' JS API for reconnect/shutdown behavior.trustlessto defaulttrue— recommend keeping opt-in for 1–2 releases to see sync behavior in the wild first.Downstream work
Once this lands,
bitsocial-clican bump the dep and add oclif flags (--trustlessEnsResolver,--consensusProviderUrls,--checkpointSyncUrls) ondaemonto expose the new mode. No Docker image changes needed.