Network Nexus (NNX) is a first prototype of an NNS-governance-focused onchain workspace for the Internet Computer.
NNX uses a single persistent workspace shell. / intentionally starts empty
except for the global ambient globe, left module rail, search, theme toggle, and
a small welcome affordance. Dense intelligence surfaces are opened as workspace
modules or by deep-link routes:
/review, /tokenomics, /proposal-support, /releases,
/release/{version_id}, /subnet/{subnet_id}, /proposal/{proposal_id}, and
/neuron/{neuron_id}. The browser app queries NNS Governance, Registry, CMC,
and the NNX historian through the query facade only when a relevant module or
deep link is opened.
NNX proposal analysis uses only onchain/system-canister data available through the query facade: NNS Governance, NNS Registry, CMC, and normalized raw Registry reads. The analysis layer is lifecycle-aware, so pending proposals get precondition checks while successfully executed proposals get postcondition checks.
Supported Phase 1 proposal action types are subnet membership changes, subnet creation, removing nodes from subnets, and API boundary node add/remove proposals. NNX tracks all known proposal families in a level-based support matrix, so known unsupported types still decode into useful support cards with payload fields, lifecycle, target hints, and manual-review caveats. Manual external IP checks are reviewer aids only; NNX does not treat Globalping or other offchain tools as validation data. The DFINITY provider warning uses the fixed provider principal ID, not provider display names.
This repository uses icp-cli and icp.yaml as committed project config. Do
not add dfx.json; dfx is allowed only as an operator tool for explicit
staging upgrades documented in docs/staging-deploy.md.
Install icp-cli and the Rust Wasm target before deploying:
npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm
rustup target add wasm32-unknown-unknownnpm ci
npm run build:frontend
cargo test
icp deploy nnx_frontend --environment localFor local deployment, start the managed local network first if it is not already running:
icp network start -d/ empty NNX Workspace shell
/review Review Queue workspace panel
/tokenomics historian-backed tokenomics metrics
/proposal-support known NNS proposal support levels
/releases ICOS release timeline shell
/release/{version_id} ICOS version-specific timeline shell
/neuron/{neuron_id}
/proposal/{proposal_id} NNS proposal detail
/subnet/{subnet_id} IC subnet detail and node map
The default workspace does not load proposal, subnet, release, or tokenomics data. Deep links open the relevant workspace panel and then load data through the query facade. Malformed routes are handled by the Rust certified asset canister as HTTP 404. Valid-shaped but non-existent neuron IDs are detected client-side after querying NNS Governance.
NNX has a CSS-variable dark/light theme system. First load follows system preference, explicit toggles are persisted when localStorage is available, and the UI degrades to a readable default when storage is unavailable.
Tokenomics metrics are historian-backed. Governance cached metrics are the source for maturity, staked ICP, locked ICP, supply, and dissolve-delay bucket snapshots. Dissolve-delay bands use half-year Governance buckets and must be labeled as approximate near boundaries. ICP burned is shown only when it can be derived from allowed ledger/system canister sources; Dashboard APIs are not data sources.
Application and UI modules do not import actors, agents, or Candid declarations directly. They depend on createIcQueryFacade.
The current backend is agent-query-backend.js, which uses @icp-sdk/core/agent and checked-in reduced NNS Governance, Registry, and CMC declarations. It calls Governance list_neurons, list_known_neurons, list_node_providers, list_proposals, and get_proposal_info, Registry topology queries, raw Registry subnet_list discovery, and CMC get_subnet_types_to_subnets. A future ic-query backend can replace this module without changing UI or domain call sites.
Mainnet canister IDs:
NNS Governance rrkah-fqaaa-aaaaa-aaaaq-cai
NNS Registry rwlgt-iiaaa-aaaaa-aaaaa-cai
CMC rkp4c-7iaaa-aaaaa-aaaca-cai
The first NNX onchain data proxy lives behind createIcQueryFacade and returns normalized plain JavaScript objects. UI and domain code should call facade methods only:
const topology = await queryFacade.getIcTopology();
const providers = await queryFacade.getIcNodeProviders();
const subnet = await queryFacade.getIcSubnet({ subnetId: 'known-subnet-id' });
const subnetDetail = await queryFacade.getIcSubnetDetails({ subnetId: 'known-subnet-id' });
const { subnets, warnings } = await queryFacade.getIcSubnets({
subnetIds: ['known-subnet-id'],
});
const { countsBySubnetId } = await queryFacade.getIcSubnetNodeCounts({
subnetIds: ['known-subnet-id'],
});
const { labelsBySubnetId } = await queryFacade.getCmcSubnetLabels();
await queryFacade.refreshIcTopology();
queryFacade.clearTopologyCache();getIcTopology() uses Candid-safe reads:
- Governance
list_node_providers(). - Registry
get_node_operators_and_dcs_of_node_provider(providerPrincipal)for each provider. - Normalization into node providers, node operators, and data centers.
Candid-safe subnet reads are available when callers already know subnet IDs:
getIcSubnet({ subnetId })reads one Registryget_subnetrecord and returns a normalized subnet ornullfor RegistryErr.getIcSubnetDetails({ subnetId })reads the Registry subnet record, raw Registry node records, Governance node providers, Registry node operators, and Registry data center GPS metadata to return onchain-derived node locations for/subnet/{subnet_id}.getIcSubnets({ subnetIds })reads known subnet IDs with bounded concurrency and returns{ subnets, warnings }.getIcSubnetNodeCounts({ subnetIds })returns{ countsBySubnetId, warnings }for display code that only needs node counts and basic subnet metadata.
Example:
const { countsBySubnetId, warnings } = await queryFacade.getIcSubnetNodeCounts({
subnetIds: ['known-subnet-id'],
});getIcSubnets() without subnetIds discovers the complete subnet ID list through the Registry canister's raw protobuf get_value query for the subnet_list key, then reads each subnet through Candid-safe get_subnet. The raw protobuf code is isolated in raw-registry-client.js; UI and domain modules still receive normalized plain JavaScript objects only.
If raw Registry discovery is unavailable in a future backend, getIcSubnets() without IDs must fail clearly with RAW_REGISTRY_UNAVAILABLE, not return an empty all-subnet result.
getCmcSubnetLabels() reads CMC get_subnet_types_to_subnets() and get_default_subnets(), then normalizes them into { labelsBySubnetId, defaultSubnetIds, publicSubnetIds, warnings }. CMC labels are kept separate from Registry subnet type: CMC labels are user-facing placement labels such as Fiduciary or other CMC-configured subnet types, while Registry type remains system, application, verified_application, or cloud_engine.
Subnet workspace panels use subnet-loader.js to merge Registry subnet records
with CMC labels, group subnets by nodeCount, and render expandable node-count
groups. Subnets in the CMC default subnet list or assigned to a CMC subnet type
are shown as Permissionless; all others are shown as Unknown. CMC labels are
displayed only when the CMC assigns one. UI modules do not import the CMC actor,
Registry actor, raw Registry key names, protobuf helpers, or principal
utilities.
Topology cache behavior:
- In-memory only, no
localStorage. - Default TTL is 60 seconds.
- Concurrent
getIcTopology()calls share the same in-flight request. refreshIcTopology()bypasses the cache.clearTopologyCache()invalidates cached and in-flight topology state.
Topology errors use IcTopologyError with stable codes such as GOVERNANCE_CALL_FAILED, REGISTRY_CALL_FAILED, REGISTRY_RESPONSE_ERR, PARTIAL_TOPOLOGY, VALIDATION_FAILED, and RAW_REGISTRY_UNAVAILABLE. A total provider read failure throws an IcTopologyError; partial provider failures return a partial topology with structured warnings.
Node location modeling must be derived through the topology relationship, not as direct node fields:
node -> node operator -> data center -> gps
The subnet detail globe uses checked-in Natural Earth 110m land geometry served by the frontend canister from map/ne_110m_land.geojson. This file is only the visual basemap. Subnet membership, node-to-operator relationships, data center metadata, GPS coordinates, and CMC labels remain derived from onchain Registry, Governance, and CMC queries.
Normal test commands:
npm run test:frontend-unit
cargo test --workspace
npm run build:frontendNNS topic metadata is generated from upstream governance.proto in the DFINITY IC repository:
npm run generate:nns-topicsDo not manually maintain the full topic list. The app keeps only a small policy overlay for fallback semantics that are not fully discoverable from the enum alone.
By default, generation must read the live upstream governance.proto. If that fetch fails, the script will use tools/cache/governance.proto as a pinned fallback when the cache file exists and will print a warning that the cache was used. If the fetch fails and no pinned cache exists, generation exits non-zero.
The embedded proto snapshot is only an emergency fallback. To allow it explicitly, run with:
NNX_ALLOW_EMBEDDED_TOPIC_FALLBACK=1 npm run generate:nns-topicsPrivate neurons show controller as Anonymous.
Private hotkeys and followees show Private.
Non-existent valid-shaped neuron IDs are detected client-side after the NNS query.
The guarantee proof is structural, conservative, threshold-based, and bounded by max transitive depth. Alpha-vote and omega-vote are treated as guaranteed Yes anchors. Omega-reject is treated as a guaranteed No anchor. Unknown, private, cyclic, or depth-limited branches do not block a guarantee when already-known branches satisfy the relevant Yes/No threshold.
Additional checks:
npm ci --no-fund --no-audit
npm run test:frontend-unit
npm run build:frontend
cargo fmt --all -- --check
cargo test --workspace
cargo build --workspace --target wasm32-unknown-unknown --release
node tools/scripts/check-frontend-artifacts.mjs
node tools/scripts/check-boundaries.mjs
tools/scripts/security-scanSecurity scans:
tools/scripts/security-scanSee docs/release-checklist.md, docs/security/frontend-security.md, and
docs/architecture/query-boundaries.md.