The Hestia client
Every field of HestiaConfig, how Hestia.create wires the chain clients, and the Node vs. browser profiles.
Hestia is the single object an agent holds. You build it once with Hestia.create(config),
and it owns the public client (reads), the wallet client (submits), the local store, and the
indexer.
HestiaConfig
ts
interface HestiaConfig {
chain: Chain; // viem chain (base | baseSepolia | foundry)
rpcUrl: string; // RPC endpoint for reads
pool: Address; // HestiaPool contract
registry: Address; // AssociationSetRegistry contract
usdc: Address; // USDC token address for this chain
account: Account | Address; // signer (Node) or connected address (browser)
keys: Keys; // derived identity (sk, SK, vk, VK)
association: AssociationProvider; // supplies the association root + proofs
artifacts: ArtifactsByArity; // wasm/zkey sources for proving
transport?: Transport; // optional: browser wallet transport
metaChain?: ChainName; // chain tag for your meta-address (default "baseSepolia")
}| Field | Notes |
|---|---|
chain | A viem Chain. The console maps NEXT_PUBLIC_HESTIA_CHAIN to base / baseSepolia / foundry. |
rpcUrl | Used to build the read client and, unless transport is given, the wallet client too. |
pool / registry | Deployed contract addresses for the target chain. |
usdc | The token address; USDC_ADDRESS.base / .baseSepolia are provided. |
account | An Account (e.g. privateKeyToAccount) in Node; the connected Address in the browser. |
keys | From deriveKeysFromSeed / deriveKeysFromSignature. |
association | Any AssociationProvider. |
artifacts | Per-arity wasm/zkey. Paths in Node, URLs in the browser. |
transport | Pass custom(window.ethereum) so the user's wallet signs and submits. |
metaChain | The chain tag baked into hestia.metaAddress. Defaults to baseSepolia. |
What create builds
ts
static async create(cfg: HestiaConfig): Promise<Hestia>;Internally it constructs:
- a public client —
createPublicClient({ chain, transport: http(rpcUrl) })— for all reads (leaf index, receipts, events); - a wallet client —
createWalletClient({ account, chain, transport: transport ?? http(rpcUrl) })— forapprove,shield, and submitting transactions; and - a fresh store + indexer bound to the pool and registry.
The address the SDK acts as is resolved from account (the address itself, or account.address
for an Account).
Node profile
A server-side agent signs with an in-process key and talks to an RPC directly:
ts
import { privateKeyToAccount } from "viem/accounts";
const hestia = await Hestia.create({
chain: baseSepolia,
rpcUrl: "https://sepolia.base.org",
pool, registry, usdc,
account: privateKeyToAccount(process.env.AGENT_KEY as `0x${string}`),
keys, association, artifacts,
// transport omitted → defaults to http(rpcUrl)
});Browser profile
In a dApp the user's wallet signs. Pass a custom transport and the connected address:
ts
import { createWalletClient, custom, hexToBytes } from "viem";
import { deriveKeysFromSignature, KEY_DERIVATION_MESSAGE } from "@hestia/sdk";
const transport = custom(window.ethereum);
const wallet = createWalletClient({ chain, transport });
const [address] = await wallet.requestAddresses();
const sig = await wallet.signMessage({ account: address, message: KEY_DERIVATION_MESSAGE });
const keys = await deriveKeysFromSignature(hexToBytes(sig));
const hestia = await Hestia.create({
chain, rpcUrl, pool, registry, usdc,
account: address, // an Address, not an Account
transport, // user's wallet signs + submits
keys, association, artifacts,
});This is exactly how the Labs console is wired.
The instance surface
ts
hestia.metaAddress; // string — share to receive
hestia.exportViewingKey(); // Hex — for selective disclosure
await hestia.sync(); // pull latest events into the local index
await hestia.balance(token); // bigint — sum of unspent notes
await hestia.shield({ token, amount });
await hestia.send({ token, amount, to, fee? });
await hestia.unshield({ token, amount, to, fee? });Each is detailed in operations, and the full type signatures are in the API reference.
