@cef-ai/chain
v1.0.1
Published
CEF-owned blockchain-ops layer (ADR-035), wrapping [polkadot-api (papi)](https://papi.how). The only package — with `@cef-ai/account` — permitted to import a chain library; every consumer above it stays chain-lib-free.
Readme
@cef-ai/chain
CEF-owned blockchain-ops layer (ADR-035), wrapping polkadot-api (papi).
The only package — with @cef-ai/account — permitted to import a chain library;
every consumer above it stays chain-lib-free.
import { connect } from "@cef-ai/chain";
const chain = connect({ network: "devnet" }); // or "testnet" | "mainnet", or connect(wsUrl)
try {
await chain.addProxy({ signer, delegate: gatewayAddress }); // Proxy.add_proxy(gateway,'Any',0)
} finally {
chain.disconnect();
}Multi-network model
We ship per-network typed descriptors (cereDevnet / cereTestnet /
cereMainnet), generated by papi from each chain's metadata (Cere serves
metadata v14/v15/v16 on all three). connect() selects the descriptor set by
network; a bare WS URL infers it (inferNetwork), defaulting to mainnet (the
most conservative) for unknown hosts.
Why per-network: it keeps genesis / codeHash / metadata correct per
environment, and lets the descriptors diverge if a network's runtime adds
pallets/calls the others lack. The calls we use today (Proxy.add_proxy,
balances) are identical across all three, so the static type is taken from the
mainnet baseline while the runtime descriptor is the per-network one.
Compatibility guard
How papi separates concerns: descriptors are compile-time types + checksums;
the actual codec is built from the live metadata papi fetches on connect, and
papi follows runtimeUpgrade so a mid-session upgrade reloads metadata without
reconnecting. Before encoding, addProxy asserts the call is compatible with the
connected runtime:
const token = await api.compatibilityToken;
if (!api.tx.Proxy.add_proxy.isCompatible(CompatibilityLevel.BackwardsCompatible, token))
throw new ChainIncompatibleError(...);So a network whose runtime predates a call we need fails fast and legibly, rather than with a cryptic encode error.
Runbook — updating to a new Cere runtime release
When a Cere network ships a runtime upgrade (new spec version / pallets):
- Regenerate descriptors from the live nodes:
(orpnpm --filter @cef-ai/chain exec papi update # re-fetches metadata for all entriespapi add cereDevnet -w <ws>to refresh a single entry). Source of truth is.papi/polkadot-api.json+.papi/metadata/*.scale. - Review the type diff. New pallets/calls and changed argument shapes show up
as TypeScript changes. Adding pallets is backward-compatible (existing
checksums unchanged); a breaking argument change drops the compatibility level
and is caught by
tsc+ the runtime guard. - Adapt
client.tsonly if a used call changed; runtsc -b+vitest. - Commit the updated
.papi/metadata/*.scale(the generated descriptors stay gitignored). Fresh clones / CI regenerate them automatically: this package'spreparescript runspapi generateagainst the committed metadata — fully offline, no node required. (preparealso runs beforepnpm pack/publish; it does NOT run for downstream workspaces that depend on this package.) Runpnpm --filter @cef-ai/chain generateto regenerate by hand.
The live proxy.addProxy round-trip through the shipped stack is validated by the
M4 devnet gate (account.provisioning.ensure() against devnet).
