Networks
The Network class and workspace.networks collection — resolving bySlug/byChainId, adding a custom Network, overriding a built-in RPC URL with update(), dropping user networks, and account.setDefaultNetwork().
A Network is a mostly-flat data object describing one chain: its slug, display name, chain id, RPC endpoint, native currency, and virtual machine ("evm" or "svm"). Every workspace opens with a set of built-in networks already loaded, and you can add your own, override a built-in's RPC URL, or drop the ones you added. Both the class and its collection live behind the main entry:
import { Workspace, Network } from "wative-core";The Network class
Constructor
The primary form takes a single NetworkInit object:
const monad = new Network({
slug: "monad-testnet",
name: "Monad Testnet",
chainId: 10143,
rpcUrl: "https://testnet-rpc.monad.xyz",
nativeCurrency: { name: "Monad", symbol: "MON", decimals: 18 },
vm: "evm",
});A positional overload also exists — new Network(name, chainId, rpcUrl, nativeCurrency?, color?) — which derives the slug from name and infers vm from the chain id. The object form is preferred because every field is explicit.
NetworkInit
| Field | Type | Required | Notes |
|---|---|---|---|
slug | Slug (branded string) | yes | URL-safe identifier, 3–32 characters, unique within the workspace. A stored network whose slug exceeds 32 characters no longer loads. |
name | string | yes | Display name, 3–64 characters. |
chainId | ChainId (branded number) | yes | EVM chain id, or the library's pinned id for an SVM cluster. |
rpcUrl | string | yes | Primary JSON-RPC endpoint (back-compat). See rpcUrl validation; "" means "no RPC configured". When endpoints is omitted it is the sole entry of the default pool. |
endpoints | readonly string[] | no | Ordered default endpoint pool (failover order). Falls back to [rpcUrl] when omitted. |
readEndpoints | readonly string[] | no | Optional read-only pool; falls back to endpoints, then [rpcUrl]. |
writeEndpoints | readonly string[] | no | Optional send pool; falls back to endpoints, then [rpcUrl]. |
routes | NetworkRoutes | no | Optional per-route endpoint pools (staked / jito / mev). See NetworkRoutes. |
nativeCurrency | { name; symbol; decimals } | yes | name 1–32 chars, symbol 2–16 chars, decimals a non-negative integer. |
multicallAddress | string | no | Multicall3 contract (EVM address). Built-in EVM networks ship one; it is overridable and resets to defaultMulticallAddress. |
color | string | no | Hex color (e.g. #627eea), when provided. |
vm | VmToken | yes | "evm" or "svm". Casual casing and surrounding whitespace are normalized ("EVM", " svm " are accepted). |
The read-only network.symbol getter is a shortcut for network.nativeCurrency.symbol. The read-only network.defaultRpcUrl getter returns this network's canonical built-in RPC URL — see Resetting to the built-in RPC URL — and network.defaultMulticallAddress does the same for the Multicall3 contract (see Resetting to the built-in multicall). The read-only network.isBuiltin getter is true for a network wative-core ships as a built-in — the flag a UI reads to show it as non-deletable, with only its connectivity/presentation fields editable (its chain identity is fixed by the library). See Built-in Networks.
vm is typed as VmToken (ChainVM | (string & {})), leaving room for custom chain dialects to register their own tokens. A vm that is neither a built-in ("evm" / "svm") nor a registered dialect's token is rejected with PARAMETER_ERROR at construction.
NetworkRoutes
routes supplies per-route endpoint pools for landing-optimized and private submission, alongside the ordinary endpoints / readEndpoints / writeEndpoints pools. Every key is optional and validated at construction.
| Route | Shape | Purpose |
|---|---|---|
staked | { endpoints: readonly string[] } | A staked / landing-optimized RPC pool (ordinary JSON-RPC). |
jito | { blockEngineUrl: string; tipAccount?: string } | SVM Jito bundle route — its own block-engine URL and an optional tip account. |
mev | { relayUrl: string } | EVM private / MEV relay (e.g. Flashbots Protect / MEV-Share). |
The staked pool is honored today (as a soft pool at endpoint resolution). The jito and mev submission paths are accepted and validated at construction but their submission is not yet implemented — a send on the "jito" or "mev" route is refused rather than falling through to a public broadcast. They are a planned additive feature.
The workspace.networks collection
workspace.networks is a read-only array of Network (the NetworkCollection interface) with lookup and mutation helpers. Numeric and slug indexing both work, and a workspace-defined network overrides a built-in of the same slug.
ws.networks.length; // 15 at a fresh open
ws.networks[0]; // first Network in the array
ws.networks["bnbchain"]; // by slug (proxy indexing)
ws.networks.map((n) => n.slug); // ordinary array methodsbySlug and byChainId
Both return the matching Network, or null when nothing matches.
ws.networks.bySlug("ethereum").chainId; // 1
ws.networks.bySlug("arbitrum-sepolia").vm; // "evm"
ws.networks.byChainId(8453).slug; // "base"
ws.networks.bySlug("does-not-exist"); // null| Method | Signature | Returns |
|---|---|---|
bySlug | bySlug(slug: Slug) | Network | null |
byChainId | byChainId(id: ChainId) | Network | null |
add / update / drop
| Method | Signature | Purpose |
|---|---|---|
add | add(network: Network) → Promise<Network> | Register a new network. Persists. |
update | update(network: Network) → Promise<Network> | Replace the entry with the same slug. Persists. |
drop | drop(network: Network) → Promise<void> | Remove a user-added network. Persists. |
Adding a slug that is already registered rejects with DUPLICATE_IDENTITY:
await ws.networks.add(monad);
ws.networks.length; // 16
ws.networks.bySlug("monad-testnet").chainId; // 10143
await ws.networks.add(monad);
// rejects → WativeError { code: "DUPLICATE_IDENTITY" }update() replaces the existing entry in place — the common use is overriding a built-in's RPC URL with your own provider. Build a fresh Network by spreading the existing one and pass it to update(); the collection length is unchanged because the slug already existed:
const eth = ws.networks.bySlug("ethereum");
const customEth = new Network({
...eth,
rpcUrl: "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY",
});
await ws.networks.update(customEth);
ws.networks.bySlug("ethereum").rpcUrl;
// "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY"
ws.networks.length; // 15 — replaced, not appendedResetting to the built-in RPC URL
network.defaultRpcUrl is a read-only getter that returns the canonical RPC URL this network ships with — read straight from the frozen built-in registry, independent of any override the workspace copy carries. network.rpcUrl is the effective endpoint (your override, once you call update()); network.defaultRpcUrl is the value it resets back to.
const eth = ws.networks.bySlug("ethereum");
eth.rpcUrl; // "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY" (overridden)
eth.defaultRpcUrl; // the built-in default — unchanged by the override
// restore the shipped endpoint
await ws.networks.update(new Network({ ...eth, rpcUrl: eth.defaultRpcUrl }));defaultRpcUrl is defined for built-in networks only. On a custom network you added it throws UNSUPPORTED_OP, so gate on Network.isBuiltinSlug(slug) — or only surface a "reset" affordance when rpcUrl !== defaultRpcUrl.
Resetting to the built-in multicall
The same model applies to the Multicall3 contract. Every built-in EVM network ships one; network.multicallAddress is the effective value and network.defaultMulticallAddress is the shipped default it resets back to. Override and reset it exactly like the RPC URL above.
const eth = ws.networks.bySlug("ethereum");
eth.multicallAddress; // the effective multicall (your override, once set)
eth.defaultMulticallAddress; // the built-in default
// override, then restore the shipped contract
await ws.networks.update(new Network({ ...eth, multicallAddress: "0x1111111111111111111111111111111111111111" }));
await ws.networks.update(new Network({ ...eth, multicallAddress: eth.defaultMulticallAddress }));defaultMulticallAddress is a getter like defaultRpcUrl: a custom network throws UNSUPPORTED_OP, and a built-in that ships no multicall (the Solana networks) returns undefined.
The built-in guard
Networks you added can be dropped; the built-ins that ship with the workspace cannot:
await ws.networks.drop(custom);
ws.networks.bySlug("my-net"); // null
const eth = ws.networks.bySlug("ethereum");
await ws.networks.drop(eth);
// rejects → WativeError { code: "UNSUPPORTED_OP" }A built-in's RPC URL is still fully editable through update() — the guard is only on removing it.
A workspace-owned Network also has a convenience network.save() that upserts it into its owning workspace (add if new, update if the slug exists). Calling save() on a shared built-in constant throws UNSUPPORTED_OP.
network.assets
A network obtained from a workspace exposes network.assets — a live list of that network's tokens with add, update, drop, move and byId. A standalone Network (a shared built-in constant, or one not added to a workspace) exposes the same property as a read-only template whose mutators reject with UNSUPPORTED_OP. The collection and its methods are documented on the Assets page.
account.setDefaultNetwork
Each account carries a default network. account.defaultNetwork reads the resolved slug (a Slug); account.setDefaultNetwork(value) sets it and persists, returning a Promise<void>. The argument is a NetworkLike — Network | ChainId | string — so a slug, a numeric chain id, a hex chain id string, or a Network instance all resolve to the same network:
const acc = await ws.accounts.create("Desk", "wsp-pwd", MNEMONIC);
await acc.setDefaultNetwork("base"); // slug
acc.defaultNetwork; // "base"
await acc.setDefaultNetwork(8453); // chain id → "base"
await acc.setDefaultNetwork("0xa"); // hex chain id → "optimism"
await acc.setDefaultNetwork(Network.Arbitrum); // Network instance
acc.defaultNetwork; // "arbitrum"The choice survives a lock and reopen. An unresolvable value rejects with UNSUPPORTED_NETWORK:
await acc.setDefaultNetwork("does-not-exist");
// rejects → WativeError { code: "UNSUPPORTED_NETWORK" }
await acc.setDefaultNetwork(99999999);
// rejects → WativeError { code: "UNSUPPORTED_NETWORK" }NetworkLike string resolution also honors a few common aliases before slug lookup, so "mainnet"/"eth" map to ethereum, "bsc"/"binance" to bnbchain, "op" to optimism, and "sol" to solana.
A synchronous setter, account.defaultNetwork = value, is also available; it resolves the value the same way but its write to disk is fire-and-forget. Prefer setDefaultNetwork() when you need to await persistence or surface a write error.
rpcUrl validation
rpcUrl is trimmed before it is stored. An empty string is a supported "no RPC configured" state; the RPC client raises its own coded error if you try to use it. A non-empty value must be a valid URL with an allowed scheme, and hosts that resolve to link-local or cloud-metadata addresses are refused. All failures throw a WativeError with code PARAMETER_ERROR.
| Rule | Behavior |
|---|---|
| Missing scheme | Rejected — prefix with https://, http://, wss://, or ws://. |
| Allowed schemes | https:, http:, wss:, ws:. Any other scheme is rejected. |
| Link-local / metadata host | Rejected. |
Empty string ("") | Accepted — treated as no RPC configured. |
Reordering with move
move(slug: Slug, toIndex: number): Promise<void>Changes the persisted order of the networks — the order workspace.networks returns. toIndex is the slug's final 0-based position; moving it to its current index is a no-op. The write is persisted and rolls back on failure.
await ws.networks.move("base", 0); // make Base the first networkError codes
| Code | Raised when |
|---|---|
DUPLICATE_IDENTITY | add() a slug already registered. |
PARAMETER_ERROR | An invalid NetworkInit (bad rpcUrl, out-of-range field, reserved SVM chain id claimed as non-svm, a vm that is neither a built-in nor a registered dialect's token); or an out-of-range move() toIndex. |
RECORD_NOT_FOUND | move() a slug the workspace does not have. |
UNSUPPORTED_OP | drop() or save() a built-in network; defaultRpcUrl or defaultMulticallAddress on a custom network. |
UNSUPPORTED_NETWORK | setDefaultNetwork() given a network the workspace does not know. |