Registering a Dialect
registerDialect(vm, factory) to install a dialect under a new vm token — the same registry inversion as custom providers — with the vm whitelist opening automatically and the built-in evm/svm tokens now protected.
registerDialect installs a ChainDialect under a vm token. One call teaches the library about the chain, opens the vm whitelist to that token, and makes any Network on it a first-class network. This is the same registry inversion the custom providers use: Address resolves its dialect through the registry instead of a hardcoded switch, which is what lets a new chain be added without editing core.
Signature
import { ChainDialect, registerDialect } from "wative-core";
class XvmDialect extends ChainDialect {
/* ...the full contract... */
}
// One call teaches the library about "xvm" and opens the whitelist to that token.
registerDialect("xvm", () => new XvmDialect());registerDialect(vm: string, factory: () => ChainDialect): void
| Parameter | Type | Notes |
|---|---|---|
vm | string | The vm token. Normalized to a trimmed, lowercased form, so registerDialect("XVM", …) resolves for a later lookup of "xvm". |
factory | () => ChainDialect | Produces the dialect. It is invoked to obtain a fresh instance each time a dialect is resolved. |
A later registration for the same custom vm replaces the earlier one. Pass a factory (not an instance) so each resolution gets its own dialect.
The vm whitelist opens automatically
vm tokens are validated against a whitelist at every construction boundary. The token type is VmToken — ChainVM | (string & {}) — so the built-in evm / svm / sui autocomplete while any registered string is still accepted. A token that is neither built in nor registered is refused.
registerDialect flips its token on. Before registering, constructing a Network with that vm throws PARAMETER_ERROR; afterwards it is accepted:
import { Network } from "wative-core";
// After registerDialect("xvm", …):
const xnet = new Network({
slug: "xvm-testnet",
name: "XVM Testnet",
chainId: 909090,
rpcUrl: "https://rpc.xvm.example",
nativeCurrency: { name: "XVM", symbol: "XVM", decimals: 9 },
vm: "xvm",
});
// xnet.vm === "xvm"
// An unregistered vm is refused at construction:
new Network({
slug: "nope-net",
name: "Nope",
chainId: 111111,
rpcUrl: "https://nope.example",
nativeCurrency: { name: "N", symbol: "N", decimals: 9 },
vm: "totally-unregistered",
}); // throws WativeError("PARAMETER_ERROR")Built-in dialects are protected
The built-in evm and svm dialects register at module load and are immutable. A later attempt to re-register either token is refused:
registerDialect("evm", () => new MyEvmDialect());
// throws WativeError("PARAMETER_ERROR"):
// The built-in "evm" dialect cannot be replaced.Without this guard, any dependency running code at import time could silently swap the built-in signing dialect — and therefore the signing curve the key custody uses — process-wide. Custom vm tokens stay replaceable; only the built-in evm / svm tokens are locked.
Routing via Workspace and Address
Once a vm is registered, a Network declared on it behaves like any built-in network. Add it to a workspace and it is discoverable by slug; addresses created on that network delegate their signing, transaction building, and transfer lowering to the registered dialect.
import { Workspace, Network } from "wative-core";
const ws = await Workspace.open({ path: "./my-wallet", password: "…" });
const xnet = new Network({
slug: "xvm-testnet",
name: "XVM Testnet",
chainId: 909090,
rpcUrl: "https://rpc.xvm.example",
nativeCurrency: { name: "XVM", symbol: "XVM", decimals: 9 },
vm: "xvm",
});
await ws.networks.add(xnet);
ws.networks.bySlug("xvm-testnet").vm; // "xvm"
await ws.lock();Register the dialect once, at process start, before opening a workspace or constructing a Network on that vm — the whitelist check runs at construction time. Registration is process-global, shared by every workspace in the process.