fix: switch to npm @hanzo/docs packages and fix API call

This commit is contained in:
2025-12-31 10:47:54 -08:00
parent 72d95eb54e
commit 004ed3db08
20 changed files with 3481 additions and 606 deletions
+12
View File
@@ -0,0 +1,12 @@
// @ts-nocheck
import { browser } from '@hanzo/docs-mdx/runtime/browser';
import type * as Config from '../source.config';
const create = browser<typeof Config, import("@hanzo/docs-mdx/runtime/types").InternalTypeConfig & {
DocData: {
}
}>();
const browserCollections = {
docs: create.doc("docs", {"index.mdx": () => import("../content/docs/index.mdx?collection=docs"), "build/index.mdx": () => import("../content/docs/build/index.mdx?collection=docs"), "learn/architecture.mdx": () => import("../content/docs/learn/architecture.mdx?collection=docs"), "learn/index.mdx": () => import("../content/docs/learn/index.mdx?collection=docs"), "learn/tokenomics.mdx": () => import("../content/docs/learn/tokenomics.mdx?collection=docs"), "nodes/index.mdx": () => import("../content/docs/nodes/index.mdx?collection=docs"), "reference/index.mdx": () => import("../content/docs/reference/index.mdx?collection=docs"), }),
};
export default browserCollections;
+8
View File
@@ -0,0 +1,8 @@
// @ts-nocheck
import { dynamic } from '@hanzo/docs-mdx/runtime/dynamic';
import * as Config from '../source.config';
const create = await dynamic<typeof Config, import("@hanzo/docs-mdx/runtime/types").InternalTypeConfig & {
DocData: {
}
}>(Config, {"configPath":"source.config.ts","environment":"next","outDir":".docs"}, {"doc":{"passthroughs":["extractedReferences"]}});
+22
View File
@@ -0,0 +1,22 @@
// @ts-nocheck
import { frontmatter as __fd_glob_11 } from "../content/docs/reference/index.mdx?collection=docs&only=frontmatter"
import { frontmatter as __fd_glob_10 } from "../content/docs/nodes/index.mdx?collection=docs&only=frontmatter"
import { frontmatter as __fd_glob_9 } from "../content/docs/learn/tokenomics.mdx?collection=docs&only=frontmatter"
import { frontmatter as __fd_glob_8 } from "../content/docs/learn/index.mdx?collection=docs&only=frontmatter"
import { frontmatter as __fd_glob_7 } from "../content/docs/learn/architecture.mdx?collection=docs&only=frontmatter"
import { frontmatter as __fd_glob_6 } from "../content/docs/build/index.mdx?collection=docs&only=frontmatter"
import { frontmatter as __fd_glob_5 } from "../content/docs/index.mdx?collection=docs&only=frontmatter"
import { default as __fd_glob_4 } from "../content/docs/reference/meta.json?collection=docs"
import { default as __fd_glob_3 } from "../content/docs/nodes/meta.json?collection=docs"
import { default as __fd_glob_2 } from "../content/docs/learn/meta.json?collection=docs"
import { default as __fd_glob_1 } from "../content/docs/build/meta.json?collection=docs"
import { default as __fd_glob_0 } from "../content/docs/meta.json?collection=docs"
import { server } from '@hanzo/docs-mdx/runtime/server';
import type * as Config from '../source.config';
const create = server<typeof Config, import("@hanzo/docs-mdx/runtime/types").InternalTypeConfig & {
DocData: {
}
}>({"doc":{"passthroughs":["extractedReferences"]}});
export const docs = await create.docsLazy("docs", "content/docs", {"meta.json": __fd_glob_0, "build/meta.json": __fd_glob_1, "learn/meta.json": __fd_glob_2, "nodes/meta.json": __fd_glob_3, "reference/meta.json": __fd_glob_4, }, {"index.mdx": __fd_glob_5, "build/index.mdx": __fd_glob_6, "learn/architecture.mdx": __fd_glob_7, "learn/index.mdx": __fd_glob_8, "learn/tokenomics.mdx": __fd_glob_9, "nodes/index.mdx": __fd_glob_10, "reference/index.mdx": __fd_glob_11, }, {"index.mdx": () => import("../content/docs/index.mdx?collection=docs"), "build/index.mdx": () => import("../content/docs/build/index.mdx?collection=docs"), "learn/architecture.mdx": () => import("../content/docs/learn/architecture.mdx?collection=docs"), "learn/index.mdx": () => import("../content/docs/learn/index.mdx?collection=docs"), "learn/tokenomics.mdx": () => import("../content/docs/learn/tokenomics.mdx?collection=docs"), "nodes/index.mdx": () => import("../content/docs/nodes/index.mdx?collection=docs"), "reference/index.mdx": () => import("../content/docs/reference/index.mdx?collection=docs"), });
+28
View File
@@ -0,0 +1,28 @@
// source.config.ts
import { defineConfig, defineDocs } from "@hanzo/docs/mdx/config";
var docs = defineDocs({
docs: {
async: true
},
meta: {}
});
var source_config_default = defineConfig({
mdxOptions: async () => {
const { rehypeCodeDefaultOptions } = await import("@hanzo/docs/core/mdx-plugins/rehype-code");
return {
rehypeCodeOptions: {
langs: ["ts", "js", "html", "tsx", "mdx", "go", "rust", "bash", "json", "yaml", "toml"],
inline: "tailing-curly-colon",
themes: {
light: "github-light",
dark: "github-dark"
},
transformers: [...rehypeCodeDefaultOptions.transformers ?? []]
}
};
}
});
export {
source_config_default as default,
docs
};
+396
View File
@@ -0,0 +1,396 @@
# Genesis Flow: CLI -> Netrunner -> Node -> EVM
## Critical Investigation Summary
**Date**: 2025-12-27
**Scope**: CLI (`/Users/z/work/lux/cli`) and Netrunner (`/Users/z/work/lux/netrunner`)
**Finding**: `stateRoot` and `genesisHash` are NOT stored in genesis JSON - they are computed by EVM at runtime.
---
## 1. Genesis Structure Overview
The main genesis.json contains **three genesis configurations**:
```
genesis.json (main)
├── networkID: 1 (mainnet) | 2 (testnet) | ...
├── allocations: [...] (P-Chain initial allocations)
├── initialStakers: [...] (validators)
├── cChainGenesis: "{...}" (C-Chain genesis as JSON STRING)
└── startTime, message, etc.
```
**Key Point**: `cChainGenesis` is embedded as an **escaped JSON string**, not a nested object.
---
## 2. Genesis Source Files
### 2.1 Canonical Genesis Package
**Location**: `/Users/z/work/lux/genesis/configs/`
```
genesis/configs/
├── configs.go # Main loader with GetCanonicalGenesisBytes()
├── mainnet/
│ ├── network.json # Network params (networkID, allocations, etc.)
│ ├── pchain.json # P-Chain validators
│ └── cchain.json # C-Chain genesis (raw JSON)
├── testnet/
├── devnet/
└── custom/
```
**`configs.go` key function**:
```go
func GetCanonicalGenesisBytes(networkID uint32) ([]byte, error) {
// Returns pre-serialized bytes to avoid JSON re-serialization
// which would cause "db contains invalid genesis hash" errors
switch networkID {
case constants.MainnetID:
return mainnetFS.ReadFile("mainnet/genesis.json")
case constants.TestnetID:
return testnetFS.ReadFile("testnet/genesis.json")
// ...
}
}
```
### 2.2 Netrunner Default Genesis
**Location**: `/Users/z/work/lux/netrunner/network/default/genesis.json`
This is the fallback genesis used for local/devnet when no canonical genesis exists.
---
## 3. Flow Diagram
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ USER COMMAND │
│ lux network start --mainnet OR lux chain deploy <name> │
└──────────────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ CLI (cmd/networkcmd/start.go) │
│ │
│ 1. Parse flags (--mainnet, --testnet, etc.) │
│ 2. Build globalNodeConfig: │
│ { │
│ "network-id": 1, │
│ "db-type": "badgerdb", │
│ "api-admin-enabled": true, <-- ADMIN API ENABLED HERE │
│ "track-chains": "..." │
│ } │
│ 3. Create gRPC client to netrunner │
│ 4. Call client.Start() with options │
└──────────────────────────────────┬──────────────────────────────────────────┘
│ gRPC
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ NETRUNNER SERVER (server/network.go) │
│ │
│ createConfig() function: │
│ │
│ switch networkID { │
│ case MainnetID: │
│ cfg = local.NewCanonicalMainnetConfig(execPath, numNodes) │
│ // Uses genesis/configs.GetCanonicalGenesisBytes(1) │
│ case TestnetID: │
│ cfg = local.NewCanonicalTestnetConfig(execPath, numNodes) │
│ // Uses genesis/configs.GetCanonicalGenesisBytes(2) │
│ default: │
│ cfg = local.NewDefaultConfig(execPath) │
│ // Uses embedded network/default/genesis.json │
│ } │
└──────────────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ NETRUNNER LOCAL (local/genesis_config.go) │
│ │
│ newCanonicalConfig() function: │
│ │
│ 1. genesisBytes := configs.GetCanonicalGenesisBytes(networkID) │
│ // Returns RAW BYTES - no re-serialization! │
│ │
│ 2. Load validator keys from genesis/configs/keys/ │
│ │
│ 3. Build network.Config{ │
│ Genesis: string(genesisBytes), <-- Genesis as string │
│ NodeConfigs: [...], <-- Per-node configs │
│ } │
└──────────────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ NETRUNNER LOCAL (local/network.go) │
│ │
│ NewNetwork() function: │
│ │
│ 1. Create node directories: │
│ ~/.lux/runs/{network}/run_{timestamp}/node{i}/ │
│ │
│ 2. Write genesis.json to each node: │
│ node{i}/genesis.json <-- Same genesis for all nodes │
│ │
│ 3. Write node config: │
│ node{i}/config.json │
│ │
│ 4. Write chain configs: │
│ node{i}/chainConfigs/C/config.json │
│ │
│ 5. Start luxd processes with: │
│ --genesis-file={node}/genesis.json │
│ --config-file={node}/config.json │
│ --chain-config-dir={node}/chainConfigs │
└──────────────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ LUXD NODE │
│ │
│ 1. Load genesis.json from --genesis-file │
│ │
│ 2. Parse main genesis: │
│ - Extract networkID, allocations, initialStakers │
│ - Extract cChainGenesis as JSON string │
│ │
│ 3. Initialize chains: │
│ - P-Chain: Uses allocations, initialStakers │
│ - X-Chain: Uses xChainGenesis (if present) │
│ - C-Chain: Passes cChainGenesis string to EVM plugin │
└──────────────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ EVM PLUGIN (coreth/evm) │
│ │
│ 1. Receive cChainGenesis JSON string from luxd │
│ │
│ 2. Parse into Genesis struct (core/genesis.go): │
│ type Genesis struct { │
│ Config *params.ChainConfig │
│ Nonce uint64 │
│ Timestamp uint64 │
│ ExtraData []byte │
│ GasLimit uint64 │
│ Difficulty *big.Int │
│ Alloc GenesisAlloc │
│ // NOTE: NO stateRoot or genesisHash fields! │
│ } │
│ │
│ 3. COMPUTE stateRoot from Alloc: │
│ - Create state trie │
│ - Apply all allocations (balances, code, storage) │
│ - Compute Merkle root = stateRoot │
│ │
│ 4. COMPUTE genesisHash: │
│ - Build genesis block header with computed stateRoot │
│ - Hash header = genesisHash │
│ │
│ 5. Write genesis block to database │
└─────────────────────────────────────────────────────────────────────────────┘
```
---
## 4. Where stateRoot/genesisHash Are Lost (They Aren't!)
### 4.1 The Misconception
`stateRoot` and `genesisHash` are **NOT stored** in genesis.json because they are **computed values**, not input values.
### 4.2 How They Work
```
INPUT COMPUTED
┌──────────────────┐ ┌──────────────────────┐
│ genesis.json │ │ Genesis Block │
│ │ │ │
│ - config │ │ - stateRoot │
│ - alloc │──────────▶ │ - genesisHash │
│ - timestamp │ COMPUTE │ - header fields │
│ - gasLimit │ │ │
│ - extraData │ │ │
└──────────────────┘ └──────────────────────┘
```
### 4.3 When genesisHash Mismatch Occurs
**Problem**: If you:
1. Re-serialize genesis.json (field order changes)
2. Modify any alloc entry (balances, code, storage)
3. Change any header field (timestamp, gasLimit, extraData)
**Result**: Different stateRoot → Different genesisHash → "db contains invalid genesis hash" error
### 4.4 Solution: Genesis Hash Override (EVM Feature)
The EVM plugin at `/Users/z/work/lux/evm/core/genesis.go` supports override fields:
```go
type Genesis struct {
// ... standard fields ...
// Override fields for block import compatibility
GenesisHash *common.Hash `json:"genesisHash,omitempty"`
StateRoot *common.Hash `json:"stateRoot,omitempty"`
}
```
When these are set:
- `toBlock()` uses `StateRoot` override (bypasses state computation)
- `Commit()` uses `GenesisHash` override (bypasses hash computation)
---
## 5. Admin API Configuration
### 5.1 How Admin API Is Enabled
**CLI sets in globalNodeConfig**:
```go
// cmd/networkcmd/start.go
globalNodeConfig := fmt.Sprintf(`{
"network-id": %d,
"db-type": "badgerdb",
"api-admin-enabled": true, // <-- HERE
"track-chains": %q
}`, cfg.networkID, trackChainsValue)
```
### 5.2 How It Flows to Nodes
1. CLI creates `globalNodeConfig` JSON string
2. gRPC sends to netrunner via `client.WithGlobalNodeConfig()`
3. Netrunner writes to `node{i}/config.json`
4. luxd reads config and enables admin API
### 5.3 Verification
```bash
# Check if admin API is enabled
curl -X POST http://127.0.0.1:9650/ext/admin \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"admin.getChainAliases","params":{"chain":"C"},"id":1}'
```
---
## 6. admin_importChain Support
### 6.1 CLI Implementation
**Location**: `/Users/z/work/lux/cli/cmd/chaincmd/import.go`
```go
func callAdminImportChain(rpcEndpoint, filePath string) (bool, error) {
req := map[string]interface{}{
"jsonrpc": "2.0",
"method": "admin_importChain",
"params": []string{filePath},
"id": 1,
}
// POST to RPC endpoint
}
```
### 6.2 Usage
```bash
# Import blocks to C-Chain
lux chain import --rlp /path/to/blocks.rlp --rpc http://127.0.0.1:9650/ext/bc/C/rpc
```
### 6.3 Known Issue: Import Persistence
**Problem**: Blocks imported via `admin_importChain` do not persist across network restarts.
**Root Cause**:
- Blocks are written to BadgerDB
- But "last accepted block" pointer is NOT updated in consensus layer
- On restart, chain initializes from genesis
**Status**: Investigating fix in coreth/subnet-evm.
---
## 7. Chain Deploy Flow
### 7.1 Command
```bash
lux chain deploy <chainName> --mainnet|--testnet
```
### 7.2 Flow
```
┌────────────────────────────────────────────────────────────────┐
│ CLI (cmd/chaincmd/deploy.go) │
│ │
│ 1. Load genesis from ~/.lux/chains/{name}/genesis.json │
│ 2. Load sidecar from ~/.lux/chains/{name}/sidecar.json │
│ 3. Validate EVM genesis format │
│ 4. Call DeployToLocalNetwork() via gRPC │
└────────────────────────────────┬───────────────────────────────┘
│ gRPC
▼
┌────────────────────────────────────────────────────────────────┐
│ NETRUNNER │
│ │
│ 1. Receive subnet creation request │
│ 2. Create subnet on P-Chain │
│ 3. Create blockchain with provided genesis │
│ 4. Track blockchain on all validators │
│ 5. Write chain config to nodes │
└────────────────────────────────┬───────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────────┐
│ LUXD NODES │
│ │
│ 1. Receive blockchain creation from P-Chain │
│ 2. Load EVM plugin for chain │
│ 3. Initialize chain with provided genesis │
│ 4. Start processing blocks │
└────────────────────────────────────────────────────────────────┘
```
---
## 8. File Reference
| Component | File | Purpose |
|-----------|------|---------|
| CLI | `cmd/networkcmd/start.go` | Network start command |
| CLI | `cmd/chaincmd/deploy.go` | Chain deploy command |
| CLI | `cmd/chaincmd/import.go` | Block import command |
| Netrunner | `server/network.go` | gRPC server, config creation |
| Netrunner | `local/network.go` | Local network management |
| Netrunner | `local/genesis_config.go` | Genesis config factories |
| Netrunner | `network/genesis.go` | Genesis loading/parsing |
| Netrunner | `network/default/genesis.json` | Default genesis template |
| Genesis | `configs/configs.go` | Canonical genesis loader |
| Genesis | `configs/mainnet/*.json` | Mainnet genesis files |
| EVM | `core/genesis.go` | Genesis struct, state computation |
---
## 9. Summary
1. **Genesis is stored as JSON** with cChainGenesis embedded as a string
2. **stateRoot/genesisHash are NOT in genesis.json** - they are computed by EVM
3. **Admin API is enabled** via `api-admin-enabled: true` in node config
4. **admin_importChain exists** in CLI at `cmd/chaincmd/import.go`
5. **Genesis hash mismatch** occurs when genesis is re-serialized or modified
6. **Solution**: Use genesis hash override fields in EVM genesis
---
*Document generated from investigation of CLI and Netrunner codebases.*
+1 -1
View File
@@ -2,7 +2,7 @@
Official documentation for Lux Network - Post-quantum secure blockchain infrastructure.
Built with [Fumadocs](https://fumadocs.dev) and the Hanzo Docs framework.
Built with [@hanzo/docs](https://hanzo.ai/docs) - the documentation framework by Hanzo AI.
## Getting Started
+12 -7
View File
@@ -2,13 +2,14 @@ import { source } from '@/lib/source';
import {
DocsPage,
DocsBody,
} from 'fumadocs-ui/page';
} from '@hanzo/docs/ui/page';
import { notFound } from 'next/navigation';
import defaultMdxComponents from 'fumadocs-ui/mdx';
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
import { Callout } from 'fumadocs-ui/components/callout';
import { TypeTable } from 'fumadocs-ui/components/type-table';
import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';
import defaultMdxComponents from '@hanzo/docs/ui/mdx';
import { Tab, Tabs } from '@hanzo/docs/ui/components/tabs';
import { Callout } from '@hanzo/docs/ui/components/callout';
import { TypeTable } from '@hanzo/docs/ui/components/type-table';
import { Accordion, Accordions } from '@hanzo/docs/ui/components/accordion';
import { Step, Steps } from '@hanzo/docs/ui/components/steps';
export default async function Page(props: {
params: Promise<{ slug?: string[] }>;
@@ -17,7 +18,9 @@ export default async function Page(props: {
const page = source.getPage(params.slug);
if (!page) notFound();
const { body: Mdx, toc } = await page.data.load();
// Type assertion to work around TypeScript inference issues with MDX async loading
const loadFn = (page.data as any).load;
const { body: Mdx, toc } = await loadFn();
return (
<DocsPage toc={toc}>
@@ -35,6 +38,8 @@ export default async function Page(props: {
TypeTable,
Accordion,
Accordions,
Step,
Steps,
}}
/>
</DocsBody>
+8 -16
View File
@@ -1,16 +1,21 @@
import type { ReactNode } from 'react';
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import { DocsLayout } from '@hanzo/docs/ui/layouts/docs';
import { baseOptions, logo } from '@/lib/layout.shared';
import { source } from '@/lib/source';
export default function Layout({ children }: { children: ReactNode }) {
const base = baseOptions();
return (
<DocsLayout
tree={source.pageTree}
{...base}
nav={{
...base.nav,
title: (
<>
<LuxIcon className="size-5" />
<span className="font-medium">Lux Docs</span>
{logo}
<span className="font-semibold max-md:hidden">Lux Docs</span>
</>
),
}}
@@ -22,16 +27,3 @@ export default function Layout({ children }: { children: ReactNode }) {
</DocsLayout>
);
}
function LuxIcon({ className }: { className?: string }) {
return (
<svg
className={className}
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" />
</svg>
);
}
+2 -2
View File
@@ -1,6 +1,6 @@
@import 'tailwindcss';
@import 'fumadocs-ui/css/neutral.css';
@import 'fumadocs-ui/css/preset.css';
@import '@hanzo/docs/ui/css/neutral.css';
@import '@hanzo/docs/ui/css/preset.css';
@import '@luxfi/brand/styles/docs.css';
@theme inline {
+6 -6
View File
@@ -2,17 +2,17 @@ import './global.css';
import type { Viewport, Metadata } from 'next';
import type { ReactNode } from 'react';
import { Geist, Geist_Mono } from 'next/font/google';
import { RootProvider } from 'fumadocs-ui/provider/next';
import { RootProvider } from '@hanzo/docs/ui/provider/next';
export const metadata: Metadata = {
title: {
template: '%s | Lux Docs',
default: 'Lux Docs',
},
description: 'Documentation for Lux Network - Post-quantum secure blockchain infrastructure.',
description: 'Documentation for Lux Network - Post-quantum secure, multi-consensus blockchain infrastructure.',
openGraph: {
title: 'Lux Docs',
description: 'Documentation for Lux Network - Post-quantum secure blockchain infrastructure.',
description: 'Documentation for Lux Network - Post-quantum secure, multi-consensus blockchain infrastructure.',
url: 'https://docs.lux.network',
siteName: 'Lux Docs',
},
@@ -34,8 +34,8 @@ const mono = Geist_Mono({
export const viewport: Viewport = {
themeColor: [
{ media: '(prefers-color-scheme: dark)', color: '#0A0A0A' },
{ media: '(prefers-color-scheme: light)', color: '#fff' },
{ media: '(prefers-color-scheme: dark)', color: '#000000' },
{ media: '(prefers-color-scheme: light)', color: '#ffffff' },
],
};
@@ -43,7 +43,7 @@ export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html
lang="en"
className={`${geist.variable} ${mono.variable} brand-lux`}
className={`${geist.variable} ${mono.variable}`}
suppressHydrationWarning
>
<body className="flex flex-col min-h-screen">
+75 -37
View File
@@ -1,57 +1,95 @@
import Link from 'next/link';
import { projectCategories } from '@/lib/layout.shared';
export default function HomePage() {
return (
<main className="flex flex-1 flex-col items-center justify-center text-center px-4">
<div className="max-w-3xl space-y-8">
<div className="space-y-4">
<main className="flex flex-1 flex-col px-4 py-16">
<div className="max-w-6xl mx-auto w-full space-y-16">
{/* Hero */}
<div className="text-center space-y-6">
<h1 className="text-4xl font-bold tracking-tight sm:text-6xl">
Lux Network
</h1>
<p className="text-xl text-fd-muted-foreground">
<p className="text-xl text-fd-muted-foreground max-w-2xl mx-auto">
Post-quantum secure, multi-consensus blockchain infrastructure
</p>
</div>
<p className="text-lg text-fd-muted-foreground max-w-2xl mx-auto">
Build scalable, secure applications on Lux Network with our comprehensive
documentation, SDKs, and developer tools.
</p>
<div className="flex flex-wrap justify-center gap-4">
<Link
href="/docs"
className="inline-flex items-center justify-center rounded-md bg-fd-primary text-fd-primary-foreground px-6 py-3 text-sm font-medium shadow transition-colors hover:bg-fd-primary/90"
>
Get Started
</Link>
<Link
href="https://github.com/luxfi"
className="inline-flex items-center justify-center rounded-md border border-fd-border bg-fd-background px-6 py-3 text-sm font-medium shadow-sm transition-colors hover:bg-fd-accent hover:text-fd-accent-foreground"
>
View on GitHub
</Link>
<div className="flex flex-wrap justify-center gap-4">
<Link
href="/docs"
className="inline-flex items-center justify-center rounded-md bg-fd-primary text-fd-primary-foreground px-6 py-3 text-sm font-medium shadow transition-colors hover:bg-fd-primary/90"
>
Get Started
</Link>
<Link
href="https://github.com/luxfi"
className="inline-flex items-center justify-center rounded-md border border-fd-border bg-fd-background px-6 py-3 text-sm font-medium shadow-sm transition-colors hover:bg-fd-accent"
>
View on GitHub
</Link>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 pt-8">
<div className="p-6 rounded-lg border border-fd-border bg-fd-card">
<h3 className="font-semibold mb-2">Learn</h3>
{/* Project Categories */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
{projectCategories.map((category) => (
<div
key={category.title}
className="p-6 rounded-xl border border-fd-border bg-fd-card"
>
<div className="flex items-center gap-3 mb-4">
<category.icon className="size-6 text-fd-primary" />
<h2 className="text-xl font-semibold">{category.title}</h2>
</div>
<p className="text-sm text-fd-muted-foreground mb-4">
{category.description}
</p>
<div className="space-y-2">
{category.projects.map((project) => (
<Link
key={project.name}
href={project.href}
className="block p-3 rounded-lg hover:bg-fd-accent transition-colors"
>
<div className="font-medium">{project.name}</div>
<div className="text-sm text-fd-muted-foreground">
{project.description}
</div>
</Link>
))}
</div>
</div>
))}
</div>
{/* Quick Links */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<Link
href="https://lux.network"
className="p-6 rounded-lg border border-fd-border bg-fd-card hover:bg-fd-accent transition-colors"
>
<h3 className="font-semibold mb-2">Lux Network</h3>
<p className="text-sm text-fd-muted-foreground">
Understand Lux Network architecture, consensus, and post-quantum security.
Main website and network information
</p>
</div>
<div className="p-6 rounded-lg border border-fd-border bg-fd-card">
<h3 className="font-semibold mb-2">Build</h3>
</Link>
<Link
href="https://explore.lux.network"
className="p-6 rounded-lg border border-fd-border bg-fd-card hover:bg-fd-accent transition-colors"
>
<h3 className="font-semibold mb-2">Explorer</h3>
<p className="text-sm text-fd-muted-foreground">
Deploy smart contracts and build dApps with our SDKs and tools.
Blockchain explorer and analytics
</p>
</div>
<div className="p-6 rounded-lg border border-fd-border bg-fd-card">
<h3 className="font-semibold mb-2">Run</h3>
</Link>
<Link
href="https://wallet.lux.network"
className="p-6 rounded-lg border border-fd-border bg-fd-card hover:bg-fd-accent transition-colors"
>
<h3 className="font-semibold mb-2">Wallet</h3>
<p className="text-sm text-fd-muted-foreground">
Operate validators, run nodes, and participate in the network.
Manage your LUX tokens and assets
</p>
</div>
</Link>
</div>
</div>
</main>
+117
View File
@@ -0,0 +1,117 @@
---
title: LUX Tokenomics
description: LUX token economics, denominations, and supply mechanics
---
# LUX Token Economics
LUX is the native token of the Lux Network, used for staking, transaction fees, and governance.
## Token Denominations
LUX uses **6 decimal places** on the P-Chain and X-Chain, similar to USDC/USDT. This allows for a maximum supply of approximately 18.4 trillion LUX within uint64 constraints.
| Unit | Symbol | Value in LUX | Value in µLUX |
|------|--------|--------------|---------------|
| MicroLux | µLUX | 0.000001 | 1 |
| MilliLux | mLUX | 0.001 | 1,000 |
| **Lux** | **LUX** | **1** | **1,000,000** |
| KiloLux | kLUX | 1,000 | 10^9 |
| MegaLux | MLUX | 1,000,000 | 10^12 |
| GigaLux | GLUX | 1,000,000,000 | 10^15 |
| TeraLux | TLUX | 1,000,000,000,000 | 10^18 |
### Minimum Transferable Unit
The smallest transferable unit on the P-Chain is **1 µLUX (microLUX) = 0.000001 LUX**.
### Why 6 Decimals?
- **Maximum Supply**: With 6 decimals, uint64 can represent up to ~18.4 trillion LUX
- **Target Supply Cap**: 2 trillion LUX maximum supply
- **Practical Minimums**: 0.000001 LUX is small enough for all practical use cases
- **Compatibility**: Matches USDC/USDT decimal precision
## Chain-Specific Denominations
### P-Chain / X-Chain
- Uses **6 decimals** (µLUX base unit)
- Native LUX token for staking and transfers
- Validator rewards paid in LUX
### C-Chain (EVM)
- Uses **18 decimals** (Wei base unit, standard EVM)
- 1 LUX = 10^18 Wei on C-Chain
- Gas fees denominated in Wei
## Supply Mechanics
### Maximum Supply
- **Supply Cap**: 2,000,000,000,000 LUX (2 trillion)
- Enforced by the reward calculator
### Initial Distribution
- Genesis allocations with unlock schedules
- Validator staking rewards
- No pre-mine beyond documented allocations
### Reward Calculation
Validators earn rewards based on:
- Stake duration (longer = higher rate)
- Stake amount relative to total supply
- Remaining supply (rewards decrease as supply approaches cap)
```
MintingRate = MinRate + (MaxRate - MinRate) × (StakeDuration / MaxDuration)
Reward = RemainingSupply × (StakeAmount / TotalSupply) × MintingRate × (StakeDuration / MaxDuration)
```
### Reward Config Parameters
| Parameter | Mainnet Value |
|-----------|---------------|
| MinConsumptionRate | 10% annually |
| MaxConsumptionRate | 12% annually |
| MintingPeriod | 365 days |
| SupplyCap | 2 TLUX |
## Staking Requirements
### Validators
- **Minimum Stake**: 2,000 LUX
- **Maximum Stake**: 3,000,000 LUX
- **Minimum Duration**: 2 weeks
- **Maximum Duration**: 1 year
- **Uptime Requirement**: 80%
### Delegators
- **Minimum Stake**: 25 LUX
- **Delegation Fee**: Minimum 2%
## Transaction Fees
| Operation | Fee |
|-----------|-----|
| Standard Transaction | 0.001 LUX (1 mLUX) |
| Create Asset | 0.01 LUX (10 mLUX) |
## Code References
The denomination constants are defined in:
- **Node**: `node/utils/units/lux.go`
- **Genesis**: `genesis/pkg/genesis/params.go`
```go
// LUX uses 6 decimals (1 LUX = 10^6 microLUX)
const (
MicroLux uint64 = 1 // 0.000001 LUX
MilliLux uint64 = 1000 * MicroLux // 0.001 LUX
Lux uint64 = 1000 * MilliLux // 1 LUX
KiloLux uint64 = 1000 * Lux // 1,000 LUX
MegaLux uint64 = 1000 * KiloLux // 1,000,000 LUX
GigaLux uint64 = 1000 * MegaLux // 1 billion LUX
TeraLux uint64 = 1000 * GigaLux // 1 trillion LUX
)
```
+1 -1
View File
@@ -1,4 +1,4 @@
import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
import type { BaseLayoutProps } from '@hanzo/docs/ui/layouts/shared';
import { BookOpenIcon, CodeIcon, ServerIcon, WalletIcon, ShieldIcon, NetworkIcon } from 'lucide-react';
// Lux Network Icon
+2 -2
View File
@@ -1,5 +1,5 @@
import { docs } from '@/.source';
import { loader } from 'fumadocs-core/source';
import { docs } from '@/.docs/server';
import { loader } from '@hanzo/docs/core/source';
export const source = loader({
baseUrl: '/docs',
+4 -1
View File
@@ -1,9 +1,12 @@
import defaultComponents from 'fumadocs-ui/mdx';
import defaultComponents from '@hanzo/docs/ui/mdx';
import { Steps, Step } from '@hanzo/docs/ui/components/steps';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function useMDXComponents(components: Record<string, any>): Record<string, any> {
return {
...defaultComponents,
Steps,
Step,
...components,
};
}
+4 -2
View File
@@ -1,4 +1,4 @@
import { createMDX } from 'fumadocs-mdx/next';
import { createMDX } from '@hanzo/docs/mdx/next';
import type { NextConfig } from 'next';
const config: NextConfig = {
@@ -14,6 +14,8 @@ const config: NextConfig = {
},
};
const withMDX = createMDX();
const withMDX = createMDX({
outDir: '.docs',
});
export default withMDX(config);
+27 -25
View File
@@ -5,35 +5,37 @@
"scripts": {
"build": "next build",
"dev": "next dev",
"lint": "fumadocs-mdx && next lint",
"lint": "hanzo-docs-mdx && next lint",
"start": "next start",
"types:check": "fumadocs-mdx && tsc --noEmit"
"types:check": "hanzo-docs-mdx && tsc --noEmit"
},
"dependencies": {
"@luxfi/brand": "file:../brand",
"@fumadocs/mdx-remote": "^1.2.0",
"fumadocs-core": "16.2.5",
"fumadocs-mdx": "14.1.0",
"fumadocs-ui": "16.2.5",
"lucide-react": "^0.469.0",
"next": "^15.1.0",
"next-themes": "^0.4.4",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"shiki": "^3.0.0",
"tailwind-merge": "^2.6.0",
"zod": "^3.24.0"
"@hanzo/docs": "^16.2.9",
"@hanzo/docs-core": "^16.4.3",
"@hanzo/docs-base-ui": "^16.4.3",
"@hanzo/docs-ui": "^16.4.3",
"@hanzo/docs-mdx": "^14.2.5",
"@hanzo/docs-openapi": "^10.2.3",
"@hanzo/docs-typescript": "^5.0.1",
"@hanzo/docs-twoslash": "^3.1.11",
"@hanzo/docs-docgen": "^3.0.5",
"lucide-react": "^0.561.0",
"next": "^16.0.10",
"next-themes": "^0.4.6",
"react": "^19.2.3",
"react-dom": "^19.2.3",
"shiki": "^3.20.0",
"tailwind-merge": "^3.4.0",
"zod": "^4.1.13"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.0.0",
"@types/node": "^22.10.0",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"postcss": "^8.4.49",
"tailwindcss": "^4.0.0",
"typescript": "^5.7.0"
},
"browserslist": [
"extends browserslist-config-baseline/2024"
]
"@tailwindcss/postcss": "^4.1.18",
"@types/node": "^24.10.2",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
"postcss": "^8.5.6",
"tailwindcss": "^4.1.18",
"typescript": "^5.9.3"
}
}
+2752 -487
View File
File diff suppressed because it is too large Load Diff
+3 -18
View File
@@ -1,31 +1,16 @@
import {
defineConfig,
defineDocs,
frontmatterSchema,
metaSchema,
} from 'fumadocs-mdx/config';
import { z } from 'zod';
import { defineConfig, defineDocs } from '@hanzo/docs/mdx/config';
export const docs = defineDocs({
docs: {
schema: frontmatterSchema.extend({
preview: z.string().optional(),
index: z.boolean().default(false),
method: z.string().optional(),
}),
async: true,
},
meta: {
schema: metaSchema.extend({
description: z.string().optional(),
}),
},
meta: {},
});
export default defineConfig({
mdxOptions: async () => {
const { rehypeCodeDefaultOptions } = await import(
'fumadocs-core/mdx-plugins/rehype-code'
'@hanzo/docs/core/mdx-plugins/rehype-code'
);
return {
+1 -1
View File
@@ -32,7 +32,7 @@
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".source/**/*.ts",
".docs/**/*.ts",
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
],