Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 737bc01081 |
@@ -39,8 +39,6 @@ jobs:
|
||||
|
||||
- name: Install project dependencies
|
||||
run: pnpm i
|
||||
- name: Generate llms-full.txt
|
||||
run: pnpm run generate:llms
|
||||
- name: Build project
|
||||
run: pnpm run build
|
||||
- name: Generate sitemap
|
||||
|
||||
@@ -90,7 +90,7 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: --workspace --all-targets --exclude nym-gateway-probe --exclude nym-node-status-api --exclude nym-node-status-agent --exclude nym-node-status-client -- -D warnings
|
||||
args: --workspace --all-targets --exclude nym-gateway-probe --exclude nym-node-status-api -- -D warnings
|
||||
|
||||
- name: Clippy (non-macos)
|
||||
if: contains(matrix.os, 'linux') || contains(matrix.os, 'windows')
|
||||
@@ -104,15 +104,14 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --workspace --exclude nym-gateway-probe --exclude nym-node-status-api --exclude nym-node-status-agent --exclude nym-node-status-client
|
||||
|
||||
# Build Go FFI-dependent crates separately (requires Go, only available on Linux CI)
|
||||
- name: Build nym-node-status-api and nym-node-status-agent (linux only)
|
||||
# only build on linux because of wg FFI bindings of its dependency (network probe)
|
||||
- name: Build nym-node-status-api (linux only)
|
||||
if: runner.os == 'Linux'
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: -p nym-node-status-api -p nym-node-status-agent
|
||||
args: -p nym-node-status-api
|
||||
|
||||
- name: Build all examples
|
||||
if: contains(matrix.os, 'linux')
|
||||
|
||||
@@ -6,8 +6,6 @@ on:
|
||||
branches-ignore: [master]
|
||||
paths:
|
||||
- "documentation/docs/**"
|
||||
- "sdk/typescript/packages/sdk/src/**"
|
||||
- "sdk/typescript/packages/mix-fetch/src/**"
|
||||
- ".github/workflows/ci-docs.yml"
|
||||
|
||||
jobs:
|
||||
@@ -44,27 +42,8 @@ jobs:
|
||||
command: build
|
||||
args: --workspace --release
|
||||
|
||||
- name: Check if TypeScript SDK source changed
|
||||
id: check-ts-sdk
|
||||
run: |
|
||||
if git diff --name-only ${{ github.event.before }} ${{ github.sha }} | grep -qE '^sdk/typescript/packages/(sdk|mix-fetch)/src/'; then
|
||||
echo "changed=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "changed=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
working-directory: ${{ github.workspace }}
|
||||
|
||||
- name: Regenerate TypeDoc API reference
|
||||
if: steps.check-ts-sdk.outputs.changed == 'true'
|
||||
run: |
|
||||
npm install -g typedoc@0.25.13 typedoc-plugin-markdown@4.0.3
|
||||
cd ${{ github.workspace }}/sdk/typescript/packages/sdk && typedoc --skipErrorChecking
|
||||
cd ${{ github.workspace }}/sdk/typescript/packages/mix-fetch && typedoc --skipErrorChecking
|
||||
|
||||
- name: Install project dependencies
|
||||
run: pnpm i
|
||||
- name: Generate llms-full.txt
|
||||
run: pnpm run generate:llms
|
||||
- name: Build project
|
||||
run: pnpm run build
|
||||
- name: Generate sitemap
|
||||
|
||||
@@ -4,28 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2026.7-tola] (2026-04-07)
|
||||
|
||||
- Simon/ecash contract serde fix ([#6634])
|
||||
- Update Fallback IP for Nym API ([#6622])
|
||||
- Nym Node spam logging ([#6621])
|
||||
- feat: multiple deposit prices ([#6608])
|
||||
- move format_debug_bytes in common crate ([#6580])
|
||||
- bugfix: make sure client keys are generated before requesting credentials ([#6579])
|
||||
- Fix socks5 GW probe regression ([#6576])
|
||||
- Max/lp stream framing ([#6573])
|
||||
- HTTP domain rotation conditions ([#6570])
|
||||
|
||||
[#6634]: https://github.com/nymtech/nym/pull/6634
|
||||
[#6622]: https://github.com/nymtech/nym/pull/6622
|
||||
[#6621]: https://github.com/nymtech/nym/pull/6621
|
||||
[#6608]: https://github.com/nymtech/nym/pull/6608
|
||||
[#6580]: https://github.com/nymtech/nym/pull/6580
|
||||
[#6579]: https://github.com/nymtech/nym/pull/6579
|
||||
[#6576]: https://github.com/nymtech/nym/pull/6576
|
||||
[#6573]: https://github.com/nymtech/nym/pull/6573
|
||||
[#6570]: https://github.com/nymtech/nym/pull/6570
|
||||
|
||||
## [2026.6-stilton] (2026-03-25)
|
||||
|
||||
- lp fixes ([#6601])
|
||||
|
||||
Generated
+34
-179
@@ -1691,8 +1691,7 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
[[package]]
|
||||
name = "core-models"
|
||||
version = "0.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "657f625ff361906f779745d08375ae3cc9fef87a35fba5f22874cf773010daf4"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"hax-lib",
|
||||
"pastey 0.2.1",
|
||||
@@ -2351,47 +2350,6 @@ dependencies = [
|
||||
"x25519-dalek",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt"
|
||||
version = "0.3.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad"
|
||||
dependencies = [
|
||||
"defmt 1.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"defmt-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt-macros"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e"
|
||||
dependencies = [
|
||||
"defmt-parser",
|
||||
"proc-macro-error2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt-parser"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e"
|
||||
dependencies = [
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "delegate-display"
|
||||
version = "3.0.0"
|
||||
@@ -3440,15 +3398,6 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hash32"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
@@ -3574,16 +3523,6 @@ dependencies = [
|
||||
"http 1.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
|
||||
dependencies = [
|
||||
"hash32",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
@@ -4672,8 +4611,7 @@ checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
|
||||
[[package]]
|
||||
name = "libcrux-aesgcm"
|
||||
version = "0.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99f2a019dab4097585a7d4f5b9deebe46cd1e628b16a5bc4cb0ce35e1da334e6"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"libcrux-intrinsics",
|
||||
"libcrux-platform",
|
||||
@@ -4683,9 +4621,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-chacha20poly1305"
|
||||
version = "0.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc08d044676af21343b32b988411fa98dbb5cf65a03c9df478ced221bbdfdb1b"
|
||||
version = "0.0.6"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"libcrux-hacl-rs",
|
||||
"libcrux-macros",
|
||||
@@ -4697,8 +4634,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libcrux-curve25519"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb1e5fd8476a6ed609d24ef42aee5ab6f99f7c65d054f92412da9f499e423299"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"libcrux-hacl-rs",
|
||||
"libcrux-macros",
|
||||
@@ -4709,8 +4645,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libcrux-ecdh"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b65f73ce79337c762eb38bbac91e4c9b9e60cf318e8501b812750c640814d45e"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"libcrux-curve25519",
|
||||
"libcrux-p256",
|
||||
@@ -4720,9 +4655,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-ed25519"
|
||||
version = "0.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "835919315b7042fe9e03b6458efe0db94bf2aa7b873934dbee5b5463a8124b43"
|
||||
version = "0.0.6"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"libcrux-hacl-rs",
|
||||
"libcrux-macros",
|
||||
@@ -4734,8 +4668,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libcrux-hacl-rs"
|
||||
version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2637dc87d158e1f1b550fd9b226443e84153fded4de69028d897b534d16d22e6"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"libcrux-macros",
|
||||
]
|
||||
@@ -4743,8 +4676,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libcrux-hkdf"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c1a89ca0c89be3a268a921e47105fb7873badf7267f5e3ebf4ea46baedd73ef"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"libcrux-hacl-rs",
|
||||
"libcrux-hmac",
|
||||
@@ -4754,8 +4686,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libcrux-hmac"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a7a242707d65960770bd7e14e4f18a92bdf0b967777dd404887db8d087a643b"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"libcrux-hacl-rs",
|
||||
"libcrux-macros",
|
||||
@@ -4765,8 +4696,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libcrux-intrinsics"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1b5db005ff8001e026b73a6842ee81bbef8ec5ff0e1915a67ae65fd2a9fafa5"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"core-models",
|
||||
"hax-lib",
|
||||
@@ -4774,9 +4704,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-kem"
|
||||
version = "0.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12631592f491d22fd1a176d32b2c6edfb673998fd3987e9d95f8fa79ad2a737b"
|
||||
version = "0.0.6"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"libcrux-curve25519",
|
||||
"libcrux-ecdh",
|
||||
@@ -4791,8 +4720,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libcrux-macros"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffd6aa2dcd5be681662001b81d493f1569c6d49a32361f470b0c955465cd0338"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.106",
|
||||
@@ -4800,9 +4728,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-ml-dsa"
|
||||
version = "0.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a72929ed421cc3bf16a946b3e7d2a58d215b0b5c2a12be26b53629f081bf49b2"
|
||||
version = "0.0.7"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"core-models",
|
||||
"hax-lib",
|
||||
@@ -4815,9 +4742,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-ml-kem"
|
||||
version = "0.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a14ab3e477de9df6ee1273a114018ff62c4996ca9220070c4e5cb1743f94a67d"
|
||||
version = "0.0.7"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"hax-lib",
|
||||
"libcrux-intrinsics",
|
||||
@@ -4832,8 +4758,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libcrux-p256"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4778ba25cb08bb8a96bd100e19ed9aecf78337198fd176036e21042b2dd99bc"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"libcrux-hacl-rs",
|
||||
"libcrux-macros",
|
||||
@@ -4845,17 +4770,15 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libcrux-platform"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d9e21d7ed31a92ac539bd69a8c970b183ee883872d2d19ce27036e24cb8ecc4"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-poly1305"
|
||||
version = "0.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02491808ee5b9db8cb65fad64ae0be812db64beef179d945c00c7787dc7dfcf9"
|
||||
version = "0.0.4"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"libcrux-hacl-rs",
|
||||
"libcrux-macros",
|
||||
@@ -4863,9 +4786,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-psq"
|
||||
version = "0.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "779ade7aa5e1b4b400c716b313cbf69070988dd005f92e961c2da4c3c42fbea4"
|
||||
version = "0.0.7"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"classic-mceliece-rust",
|
||||
"libcrux-aesgcm",
|
||||
@@ -4887,8 +4809,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libcrux-secrets"
|
||||
version = "0.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ce650f3041b44ba40d4263852347d007cd2cd9d1cc856a6f6c8b2e10c3fd40b"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"hax-lib",
|
||||
]
|
||||
@@ -4896,8 +4817,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libcrux-sha2"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9d253473f259fc74a280c43f29c464f7e374abdf28b4942234dc707f529d4b7"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"libcrux-hacl-rs",
|
||||
"libcrux-macros",
|
||||
@@ -4906,9 +4826,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-sha3"
|
||||
version = "0.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1ae0b7d0e1cc4793a609fd0ff2ca3b3a3fabae523770c619a3d4bc86417b0d7"
|
||||
version = "0.0.7"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"hax-lib",
|
||||
"libcrux-intrinsics",
|
||||
@@ -4919,8 +4838,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libcrux-traits"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "812e4fa89f3f5e34b47f928b22b1b78395a0d4ec23b1f583db635f128159d65f"
|
||||
source = "git+https://github.com/cryspen/libcrux?rev=b17f8687b67cdcfc10b55aeecc998bbbca28f775#b17f8687b67cdcfc10b55aeecc998bbbca28f775"
|
||||
dependencies = [
|
||||
"libcrux-secrets",
|
||||
"rand 0.9.2",
|
||||
@@ -5129,12 +5047,6 @@ dependencies = [
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "managed"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d"
|
||||
|
||||
[[package]]
|
||||
name = "maplit"
|
||||
version = "1.0.2"
|
||||
@@ -6775,7 +6687,6 @@ version = "1.20.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.22.1",
|
||||
"bs58",
|
||||
"bytes",
|
||||
"clap",
|
||||
"futures",
|
||||
@@ -6800,6 +6711,7 @@ dependencies = [
|
||||
"nym-lp",
|
||||
"nym-network-defaults",
|
||||
"nym-node-requests",
|
||||
"nym-node-status-client",
|
||||
"nym-registration-client",
|
||||
"nym-registration-common",
|
||||
"nym-sdk",
|
||||
@@ -7559,16 +7471,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-node-status-agent"
|
||||
version = "2.0.0"
|
||||
version = "1.1.5"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"futures",
|
||||
"nym-bin-common",
|
||||
"nym-crypto",
|
||||
"nym-gateway-probe",
|
||||
"nym-node-status-client",
|
||||
"nym-sdk",
|
||||
"rand 0.8.5",
|
||||
"regex",
|
||||
"serde_json",
|
||||
@@ -7580,7 +7490,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-node-status-api"
|
||||
version = "4.5.0"
|
||||
version = "4.3.1"
|
||||
dependencies = [
|
||||
"ammonia",
|
||||
"anyhow",
|
||||
@@ -7645,9 +7555,9 @@ version = "0.3.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
"bs58",
|
||||
"nym-credentials",
|
||||
"nym-crypto",
|
||||
"nym-gateway-probe",
|
||||
"reqwest 0.13.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -11162,47 +11072,6 @@ dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smolmix"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"hickory-proto",
|
||||
"hickory-resolver",
|
||||
"http-body-util",
|
||||
"hyper 1.6.0",
|
||||
"hyper-util",
|
||||
"nym-bin-common",
|
||||
"nym-ip-packet-requests",
|
||||
"nym-sdk",
|
||||
"reqwest 0.13.1",
|
||||
"rustls 0.23.37",
|
||||
"smoltcp",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
"tokio-rustls 0.26.2",
|
||||
"tokio-smoltcp",
|
||||
"tokio-tungstenite",
|
||||
"tracing",
|
||||
"webpki-roots 0.26.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smoltcp"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dad095989c1533c1c266d9b1e8d70a1329dd3723c3edac6d03bbd67e7bf6f4bb"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"byteorder",
|
||||
"cfg-if",
|
||||
"defmt 0.3.100",
|
||||
"heapless",
|
||||
"libc",
|
||||
"log",
|
||||
"managed",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "snafu"
|
||||
version = "0.7.5"
|
||||
@@ -12169,20 +12038,6 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-smoltcp"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5f5d53da1c3095663a8900d86c2abb0ffe02d3f6aa86527b066148fcb33e65e"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"smoltcp",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.17"
|
||||
|
||||
+9
-15
@@ -147,7 +147,6 @@ members = [
|
||||
"sdk/ffi/go",
|
||||
"sdk/ffi/shared",
|
||||
"sdk/rust/nym-sdk",
|
||||
"smolmix/core",
|
||||
"service-providers/common",
|
||||
"service-providers/ip-packet-router",
|
||||
"service-providers/network-requester",
|
||||
@@ -185,6 +184,7 @@ default-members = [
|
||||
"nym-api",
|
||||
"nym-credential-proxy/nym-credential-proxy",
|
||||
"nym-node",
|
||||
"nym-node-status-api/nym-node-status-agent",
|
||||
"nym-statistics-api",
|
||||
"nym-validator-rewarder",
|
||||
"nyx-chain-watcher",
|
||||
@@ -280,7 +280,6 @@ getrandom03 = { package = "getrandom", version = "=0.3.3" }
|
||||
glob = "0.3"
|
||||
handlebars = "3.5.5"
|
||||
hex = "0.4.3"
|
||||
hickory-proto = "0.25.2"
|
||||
hickory-resolver = "0.25.2"
|
||||
hkdf = "0.12.3"
|
||||
hmac = "0.12.1"
|
||||
@@ -349,8 +348,6 @@ serde_yaml = "0.9.25"
|
||||
serde_plain = "1.0.2"
|
||||
sha2 = "0.10.3"
|
||||
si-scale = "0.2.3"
|
||||
smolmix = { version = "0.0.1", path = "smolmix/core" }
|
||||
smoltcp = "0.12"
|
||||
snow = "0.9.6"
|
||||
sphinx-packet = "=0.6.0"
|
||||
sqlx = "0.8.6"
|
||||
@@ -371,8 +368,6 @@ tokio-postgres = "0.7"
|
||||
tokio-stream = "0.1.17"
|
||||
tokio-test = "0.4.4"
|
||||
tokio-tun = "0.11.5"
|
||||
tokio-rustls = "0.26"
|
||||
tokio-smoltcp = "0.5"
|
||||
tokio-tungstenite = { version = "0.20.1" }
|
||||
tokio-util = "0.7.15"
|
||||
toml = "0.8.22"
|
||||
@@ -404,14 +399,14 @@ prometheus = { version = "0.14.0" }
|
||||
|
||||
|
||||
# libcrux
|
||||
libcrux-kem = "0.0.7"
|
||||
libcrux-ecdh = "0.0.6"
|
||||
libcrux-curve25519 = "0.0.6"
|
||||
libcrux-chacha20poly1305 = "0.0.7"
|
||||
libcrux-psq = "0.0.8"
|
||||
libcrux-ml-kem = "0.0.8"
|
||||
libcrux-sha3 = "0.0.8"
|
||||
libcrux-traits = "0.0.8"
|
||||
libcrux-kem = { git = "https://github.com/cryspen/libcrux", rev = "b17f8687b67cdcfc10b55aeecc998bbbca28f775" }
|
||||
libcrux-ecdh = { git = "https://github.com/cryspen/libcrux", rev = "b17f8687b67cdcfc10b55aeecc998bbbca28f775" }
|
||||
libcrux-curve25519 = { git = "https://github.com/cryspen/libcrux", rev = "b17f8687b67cdcfc10b55aeecc998bbbca28f775" }
|
||||
libcrux-chacha20poly1305 = { git = "https://github.com/cryspen/libcrux", rev = "b17f8687b67cdcfc10b55aeecc998bbbca28f775" }
|
||||
libcrux-psq = { git = "https://github.com/cryspen/libcrux", rev = "b17f8687b67cdcfc10b55aeecc998bbbca28f775" }
|
||||
libcrux-ml-kem = { git = "https://github.com/cryspen/libcrux", rev = "b17f8687b67cdcfc10b55aeecc998bbbca28f775" }
|
||||
libcrux-sha3 = { git = "https://github.com/cryspen/libcrux", rev = "b17f8687b67cdcfc10b55aeecc998bbbca28f775" }
|
||||
libcrux-traits = { git = "https://github.com/cryspen/libcrux", rev = "b17f8687b67cdcfc10b55aeecc998bbbca28f775" }
|
||||
|
||||
# Workspace dep definitions required by crates.io publication - we need a workspace version since `cargo workspaces` doesn't work with path imports from crate manifests
|
||||
nym-api-requests = { version = "1.20.4", path = "nym-api/nym-api-requests" }
|
||||
@@ -565,7 +560,6 @@ wasm-bindgen = "0.2.99"
|
||||
wasm-bindgen-futures = "0.4.49"
|
||||
wasm-bindgen-test = "0.3.49"
|
||||
wasmtimer = "0.4.1"
|
||||
webpki-roots = "0.26"
|
||||
web-sys = "0.3.76"
|
||||
|
||||
# for local development:
|
||||
|
||||
@@ -60,8 +60,7 @@ packages:
|
||||
## SYSTEM MAINTENANCE PLAYBOOK KNOBS
|
||||
###############################################################################
|
||||
|
||||
# To use particular version instead of Latest, provide in such form:
|
||||
# nym_version: "nym-binaries-v2026.7-tola"
|
||||
# nym_version: "v2025.21-mozzarella"
|
||||
|
||||
## NOTE:
|
||||
## if you want to pin Nym to a specific version instead of using the
|
||||
@@ -118,4 +117,4 @@ packages:
|
||||
|
||||
# enable_writeback_tuning: true
|
||||
# writeback_dirty_writeback_centisecs: 1500
|
||||
# writeback_dirty_expire_centisecs: 6000
|
||||
# writeback_dirty_expire_centisecs: 6000
|
||||
@@ -1,30 +1,11 @@
|
||||
---
|
||||
- name: Ensure nym binaries directory exists
|
||||
file:
|
||||
path: /root/nym-binaries
|
||||
state: directory
|
||||
mode: "0755"
|
||||
- name: Configure tunnel manager
|
||||
tags:
|
||||
- tunnel
|
||||
- network_tunnel_manager
|
||||
- ntm
|
||||
|
||||
- name: Download network tunnel manager
|
||||
get_url:
|
||||
url: "{{ tunnel_manager_url }}"
|
||||
dest: /root/nym-binaries/network-tunnel-manager.sh
|
||||
mode: "0755"
|
||||
force: yes
|
||||
tags:
|
||||
- tunnel
|
||||
- network_tunnel_manager
|
||||
- ntm
|
||||
|
||||
- name: Run network tunnel manager
|
||||
command: "/root/nym-binaries/network-tunnel-manager.sh {{ item }}"
|
||||
become: true
|
||||
command:
|
||||
cmd: "/root/nym-binaries/network-tunnel-manager.sh {{ item }}"
|
||||
loop:
|
||||
- complete_networking_configuration
|
||||
tags:
|
||||
- tunnel
|
||||
- network_tunnel_manager
|
||||
- ntm
|
||||
register: tunnel_mgr
|
||||
failed_when: false
|
||||
|
||||
@@ -38,7 +38,6 @@ default = []
|
||||
openapi = ["utoipa"]
|
||||
output_format = ["serde_json", "dep:clap"]
|
||||
bin_info_schema = ["schemars"]
|
||||
ip_check = []
|
||||
basic_tracing = ["dep:tracing", "dep:tracing-subscriber"]
|
||||
otel-otlp = [
|
||||
"basic_tracing",
|
||||
|
||||
@@ -9,6 +9,3 @@ pub mod completions;
|
||||
|
||||
#[cfg(feature = "output_format")]
|
||||
pub mod output_format;
|
||||
|
||||
#[cfg(feature = "ip_check")]
|
||||
pub mod ip_check;
|
||||
|
||||
@@ -186,18 +186,14 @@ impl NymEcashContract {
|
||||
}
|
||||
|
||||
#[sv::msg(query)]
|
||||
#[sv::attr(serde(alias = "get_required_deposit_amount"))]
|
||||
#[sv::attr(serde(alias = "GetRequiredDepositAmount"))]
|
||||
pub fn get_default_deposit_amount(&self, ctx: QueryCtx) -> StdResult<Coin> {
|
||||
let deposit_amount = self.config.load(ctx.deps.storage)?.deposit_amount;
|
||||
|
||||
Ok(deposit_amount)
|
||||
}
|
||||
|
||||
// Poor man's alias for backwards compatibility as sv::attr didn't seem to work
|
||||
#[sv::msg(query)]
|
||||
pub fn get_required_deposit_amount(&self, ctx: QueryCtx) -> StdResult<Coin> {
|
||||
self.get_default_deposit_amount(ctx)
|
||||
}
|
||||
|
||||
#[sv::msg(query)]
|
||||
pub fn get_reduced_deposit_amount(
|
||||
&self,
|
||||
@@ -673,7 +669,7 @@ impl NymEcashContract {
|
||||
set_build_information!(ctx.deps.storage)?;
|
||||
cw2::ensure_from_older_version(ctx.deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
|
||||
|
||||
queued_migrations::add_tiered_pricing(ctx.deps, initial_whitelist)?;
|
||||
// queued_migrations::add_tiered_pricing(ctx.deps, initial_whitelist)?;
|
||||
|
||||
Ok(Response::new())
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ Our `prebuild` script relies on the following:
|
||||
- [`tabulate`](https://pypi.org/project/tabulate/)
|
||||
- `jq`
|
||||
|
||||
Otherwise make sure to have `node` and `rust` installed.
|
||||
Otherwise make sure to have `node` installed.
|
||||
|
||||
### Link checking (optional)
|
||||
We use [lychee](https://github.com/lycheeverse/lychee) to check for broken links. Install via your package manager or `cargo install lychee`, then run:
|
||||
@@ -89,13 +89,6 @@ NEXT_PUBLIC_SITE_URL=https://nym.com/docs
|
||||
| HowTo | Step-by-step install/setup guides |
|
||||
| FAQPage | Question-answer pages |
|
||||
|
||||
## LLM-readability
|
||||
Two files are generated in the deployment workflow: `llms.txt` and `llms-full.txt`. These files follow [Cloudflare's approach](https://developers.cloudflare.com/style-guide/how-we-docs/ai-consumability/) to generation and use.
|
||||
|
||||
When running locally can you find these at `http://localhost:3000/docs/llms.txt` and `http://localhost:3000/docs/llms-full.txt`.
|
||||
|
||||
When deployed to production, these can be found at [https://nym.com/docs/llms.txt](https://nym.com/docs/llms.txt) and [https://nym.com/docs/llms-full.txt](https://nym.com/docs/llms-full.txt).
|
||||
|
||||
## Licensing and copyright information
|
||||
This is a monorepo and components that make up Nym as a system are licensed individually, so for accurate information, please check individual files.
|
||||
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import { Callout } from "nextra/components";
|
||||
|
||||
const COMMIT_SHORT = "97068b2";
|
||||
const COMMIT_FULL = "97068b2aa";
|
||||
const EXAMPLES_URL =
|
||||
"https://github.com/nymtech/nym/tree/develop/sdk/rust/nym-sdk/examples";
|
||||
|
||||
export const CodeVerified = () => (
|
||||
<Callout type="info">
|
||||
Code verified against commit{" "}
|
||||
<a
|
||||
href={`https://github.com/nymtech/nym/commit/${COMMIT_FULL}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<code>{COMMIT_SHORT}</code>
|
||||
</a>
|
||||
. If the API has changed since then, check the{" "}
|
||||
<a href={EXAMPLES_URL} target="_blank" rel="noopener noreferrer">
|
||||
examples in the repo
|
||||
</a>{" "}
|
||||
for the latest usage.
|
||||
</Callout>
|
||||
);
|
||||
@@ -1,13 +0,0 @@
|
||||
import { Callout } from "nextra/components";
|
||||
|
||||
const CRATES_VERSION = "1.20.4";
|
||||
const INSTALL_PATH = "/developers/rust/importing";
|
||||
|
||||
export const CratesPaused = () => (
|
||||
<Callout type="warning">
|
||||
<strong>Crate publication is paused.</strong> The crates.io release (v
|
||||
{CRATES_VERSION}) doesn't include the Stream module or other recent work.
|
||||
Publication resumes with the Lewes Protocol. Import from Git for now — see{" "}
|
||||
<a href={INSTALL_PATH}>Installation</a>.
|
||||
</Callout>
|
||||
);
|
||||
@@ -5,7 +5,7 @@
|
||||
},
|
||||
"mixmining_reserve": {
|
||||
"denom": "unym",
|
||||
"amount": "168575020719057"
|
||||
"amount": "170550581010206"
|
||||
},
|
||||
"vesting_tokens": {
|
||||
"denom": "unym",
|
||||
@@ -13,6 +13,6 @@
|
||||
},
|
||||
"circulating_supply": {
|
||||
"denom": "unym",
|
||||
"amount": "831424979280943"
|
||||
"amount": "829449418989794"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"nodes": 752,
|
||||
"locations": 76,
|
||||
"mixnodes": 273,
|
||||
"exit_gateways": 470
|
||||
}
|
||||
+1
-1
@@ -1 +1 @@
|
||||
831_424_979
|
||||
829_449_418
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
4_682
|
||||
4_737
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
0.95%
|
||||
0.90%
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
30.134
|
||||
31.932
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
254_377
|
||||
253_773
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
61_050_638
|
||||
60_905_575
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
61_050_637
|
||||
60_905_574
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
| **Item** | **Description** | **Amount in NYM** |
|
||||
|:-------------------|:------------------------------------------------------|--------------------:|
|
||||
| Total Supply | Maximum amount of NYM token in existence | 1_000_000_000 |
|
||||
| Mixmining Reserve | Tokens releasing for operators rewards | 168_575_020 |
|
||||
| Mixmining Reserve | Tokens releasing for operators rewards | 170_550_581 |
|
||||
| Vesting Tokens | Tokens locked outside of circulation for future claim | 0 |
|
||||
| Circulating Supply | Amount of unlocked tokens | 831_424_979 |
|
||||
| Stake Saturation | Optimal size of node self-bond + delegation | 254_377 |
|
||||
| Circulating Supply | Amount of unlocked tokens | 829_449_418 |
|
||||
| Stake Saturation | Optimal size of node self-bond + delegation | 253_773 |
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"interval": {
|
||||
"reward_pool": "168575020719057.456153922699547282",
|
||||
"staking_supply": "61050637328128.353993717821521057",
|
||||
"reward_pool": "170550581010206.362081368363611499",
|
||||
"staking_supply": "60905574069554.404272283888050139",
|
||||
"staking_supply_scale_factor": "0.07342892",
|
||||
"epoch_reward_budget": "4682639464.418262670942297209",
|
||||
"stake_saturation_point": "254377655533.868141640490923004",
|
||||
"epoch_reward_budget": "4737516139.172398946704676766",
|
||||
"stake_saturation_point": "253773225289.810017801182866875",
|
||||
"sybil_resistance": "0.3",
|
||||
"active_set_work_factor": "10",
|
||||
"interval_pool_emission": "0.02"
|
||||
|
||||
@@ -1 +1 @@
|
||||
Thursday, April 9th 2026, 15:33:24 UTC
|
||||
Thursday, March 26th 2026, 11:17:59 UTC
|
||||
|
||||
@@ -11,7 +11,7 @@ options:
|
||||
--no_routing_history Display node stats without routing history
|
||||
--no_verloc_metrics Display node stats without verloc metrics
|
||||
-m, --markdown Display results in markdown format
|
||||
-o, --output [OUTPUT]
|
||||
-o [OUTPUT], --output [OUTPUT]
|
||||
Save results to file (in current dir or supply with
|
||||
path without filename)
|
||||
```
|
||||
|
||||
@@ -8,8 +8,12 @@ Commands:
|
||||
help Print this message or the help of the given subcommand(s)
|
||||
|
||||
Options:
|
||||
-c, --config-env-file <CONFIG_ENV_FILE> Path pointing to an env file that configures the Nym API [env: NYMAPI_CONFIG_ENV_FILE_ARG=]
|
||||
--no-banner A no-op flag included for consistency with other binaries (and compatibility with nymvisor, oops) [env: NYMAPI_NO_BANNER_ARG=]
|
||||
-h, --help Print help
|
||||
-V, --version Print version
|
||||
-c, --config-env-file <CONFIG_ENV_FILE>
|
||||
Path pointing to an env file that configures the Nym API [env: NYMAPI_CONFIG_ENV_FILE_ARG=]
|
||||
--no-banner
|
||||
A no-op flag included for consistency with other binaries (and compatibility with nymvisor, oops) [env: NYMAPI_NO_BANNER_ARG=]
|
||||
-h, --help
|
||||
Print help
|
||||
-V, --version
|
||||
Print version
|
||||
```
|
||||
|
||||
@@ -12,7 +12,8 @@ usage: nym-node-cli install [-h] [-V] [-d BRANCH] [-v]
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
-V, --version show program's version number and exit
|
||||
-d, --dev BRANCH Define github branch (default: develop)
|
||||
-d BRANCH, --dev BRANCH
|
||||
Define github branch (default: develop)
|
||||
-v, --verbose Show full error tracebacks
|
||||
--mode {mixnode,entry-gateway,exit-gateway}
|
||||
Node mode: 'mixnode', 'entry-gateway', or 'exit-
|
||||
|
||||
@@ -12,8 +12,12 @@ Commands:
|
||||
help Print this message or the help of the given subcommand(s)
|
||||
|
||||
Options:
|
||||
-c, --config-env-file <CONFIG_ENV_FILE> Path pointing to an env file that configures the nym-node and overrides any preconfigured values [env: NYMNODE_CONFIG_ENV_FILE_ARG=]
|
||||
--no-banner Flag used for disabling the printed banner in tty [env: NYMNODE_NO_BANNER=]
|
||||
-h, --help Print help
|
||||
-V, --version Print version
|
||||
-c, --config-env-file <CONFIG_ENV_FILE>
|
||||
Path pointing to an env file that configures the nym-node and overrides any preconfigured values [env: NYMNODE_CONFIG_ENV_FILE_ARG=]
|
||||
--no-banner
|
||||
Flag used for disabling the printed banner in tty [env: NYMNODE_NO_BANNER=]
|
||||
-h, --help
|
||||
Print help
|
||||
-V, --version
|
||||
Print version
|
||||
```
|
||||
|
||||
@@ -4,56 +4,98 @@ Start this nym-node
|
||||
Usage: nym-node run [OPTIONS]
|
||||
|
||||
Options:
|
||||
--id <ID> Id of the nym-node to use [env: NYMNODE_ID=] [default: default-nym-node]
|
||||
--config-file <CONFIG_FILE> Path to a configuration file of this node [env: NYMNODE_CONFIG=]
|
||||
--accept-operator-terms-and-conditions Explicitly specify whether you agree with the terms and conditions of a nym node operator as defined at <https://nymtech.net/terms-and-conditions/operators/v1.0.0> [env: NYMNODE_ACCEPT_OPERATOR_TERMS=]
|
||||
--deny-init Forbid a new node from being initialised if configuration file for the provided specification doesn't already exist [env: NYMNODE_DENY_INIT=]
|
||||
--init-only If this is a brand new nym-node, specify whether it should only be initialised without actually running the subprocesses [env: NYMNODE_INIT_ONLY=]
|
||||
--local Flag specifying this node will be running in a local setting [env: NYMNODE_LOCAL=]
|
||||
--mode [<MODE>...] Specifies the current mode(s) of this nym-node [env: NYMNODE_MODE=] [possible values: mixnode, entry-gateway, exit-gateway, exit-providers-only]
|
||||
--modes <MODES> Specifies the current mode(s) of this nym-node as a single flag [env: NYMNODE_MODES=] [possible values: mixnode, entry-gateway, exit-gateway, exit-providers-only]
|
||||
-w, --write-changes If this node has been initialised before, specify whether to write any new changes to the config file [env: NYMNODE_WRITE_CONFIG_CHANGES=]
|
||||
--bonding-information-output <BONDING_INFORMATION_OUTPUT> Specify output file for bonding information of this nym-node, i.e. its encoded keys. NOTE: the required bonding information is still a subject to change and this argument should be treated only as a preview of
|
||||
future features [env: NYMNODE_BONDING_INFORMATION_OUTPUT=]
|
||||
-o, --output <OUTPUT> Specify the output format of the bonding information (`text` or `json`) [env: NYMNODE_OUTPUT=] [default: text] [possible values: text, json]
|
||||
--public-ips <PUBLIC_IPS> Comma separated list of public ip addresses that will be announced to the nym-api and subsequently to the clients. In nearly all circumstances, it's going to be identical to the address you're going to use for
|
||||
bonding [env: NYMNODE_PUBLIC_IPS=]
|
||||
--hostname <HOSTNAME> Optional hostname associated with this gateway that will be announced to the nym-api and subsequently to the clients [env: NYMNODE_HOSTNAME=]
|
||||
--location <LOCATION> Optional **physical** location of this node's server. Either full country name (e.g. 'Poland'), two-letter alpha2 (e.g. 'PL'), three-letter alpha3 (e.g. 'POL') or three-digit numeric-3 (e.g. '616') can be
|
||||
provided [env: NYMNODE_LOCATION=]
|
||||
--http-bind-address <HTTP_BIND_ADDRESS> Socket address this node will use for binding its http API. default: `[::]:8080` [env: NYMNODE_HTTP_BIND_ADDRESS=]
|
||||
--landing-page-assets-path <LANDING_PAGE_ASSETS_PATH> Path to assets directory of custom landing page of this node [env: NYMNODE_HTTP_LANDING_ASSETS=]
|
||||
--http-access-token <HTTP_ACCESS_TOKEN> An optional bearer token for accessing certain http endpoints. Currently only used for prometheus metrics [env: NYMNODE_HTTP_ACCESS_TOKEN=]
|
||||
--expose-system-info <EXPOSE_SYSTEM_INFO> Specify whether basic system information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_SYSTEM_INFO=] [possible values: true, false]
|
||||
--expose-system-hardware <EXPOSE_SYSTEM_HARDWARE> Specify whether basic system hardware information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_SYSTEM_HARDWARE=] [possible values: true, false]
|
||||
--expose-crypto-hardware <EXPOSE_CRYPTO_HARDWARE> Specify whether detailed system crypto hardware information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_CRYPTO_HARDWARE=] [possible values: true, false]
|
||||
--mixnet-bind-address <MIXNET_BIND_ADDRESS> Address this node will bind to for listening for mixnet packets default: `[::]:1789` [env: NYMNODE_MIXNET_BIND_ADDRESS=]
|
||||
--mixnet-announce-port <MIXNET_ANNOUNCE_PORT> If applicable, custom port announced in the self-described API that other clients and nodes will use. Useful when the node is behind a proxy [env: NYMNODE_MIXNET_ANNOUNCE_PORT=]
|
||||
--nym-api-urls <NYM_API_URLS> Addresses to nym APIs from which the node gets the view of the network [env: NYMNODE_NYM_APIS=]
|
||||
--nyxd-urls <NYXD_URLS> Addresses to nyxd chain endpoint which the node will use for chain interactions [env: NYMNODE_NYXD=]
|
||||
--enable-console-logging <ENABLE_CONSOLE_LOGGING> Specify whether running statistics of this node should be logged to the console [env: NYMNODE_ENABLE_CONSOLE_LOGGING=] [possible values: true, false]
|
||||
--wireguard-enabled <WIREGUARD_ENABLED> Specifies whether the wireguard service is enabled on this node [env: NYMNODE_WG_ENABLED=] [possible values: true, false]
|
||||
--wireguard-bind-address <WIREGUARD_BIND_ADDRESS> Socket address this node will use for binding its wireguard interface. default: `[::]:51822` [env: NYMNODE_WG_BIND_ADDRESS=]
|
||||
--wireguard-tunnel-announced-port <WIREGUARD_TUNNEL_ANNOUNCED_PORT> Tunnel port announced to external clients wishing to connect to the wireguard interface. Useful in the instances where the node is behind a proxy [env: NYMNODE_WG_ANNOUNCED_PORT=]
|
||||
--wireguard-private-network-prefix <WIREGUARD_PRIVATE_NETWORK_PREFIX> The prefix denoting the maximum number of the clients that can be connected via Wireguard. The maximum value for IPv4 is 32 and for IPv6 is 128 [env: NYMNODE_WG_PRIVATE_NETWORK_PREFIX=]
|
||||
--wireguard-userspace <WIREGUARD_USERSPACE> Use userspace implementation of WireGuard (wireguard-go) instead of kernel module. Useful in containerized environments without kernel WireGuard support [env: NYMNODE_WG_USERSPACE=] [possible values: true,
|
||||
false]
|
||||
--verloc-bind-address <VERLOC_BIND_ADDRESS> Socket address this node will use for binding its verloc API. default: `[::]:1790` [env: NYMNODE_VERLOC_BIND_ADDRESS=]
|
||||
--verloc-announce-port <VERLOC_ANNOUNCE_PORT> If applicable, custom port announced in the self-described API that other clients and nodes will use. Useful when the node is behind a proxy [env: NYMNODE_VERLOC_ANNOUNCE_PORT=]
|
||||
--entry-bind-address <ENTRY_BIND_ADDRESS> Socket address this node will use for binding its client websocket API. default: `[::]:9000` [env: NYMNODE_ENTRY_BIND_ADDRESS=]
|
||||
--announce-ws-port <ANNOUNCE_WS_PORT> Custom announced port for listening for websocket client traffic. If unspecified, the value from the `bind_address` will be used instead [env: NYMNODE_ENTRY_ANNOUNCE_WS_PORT=]
|
||||
--announce-wss-port <ANNOUNCE_WSS_PORT> If applicable, announced port for listening for secure websocket client traffic [env: NYMNODE_ENTRY_ANNOUNCE_WSS_PORT=]
|
||||
--enforce-zk-nyms <ENFORCE_ZK_NYMS> Indicates whether this gateway is accepting only coconut credentials for accessing the mixnet or if it also accepts non-paying clients [env: NYMNODE_ENFORCE_ZK_NYMS=] [possible values: true, false]
|
||||
--mnemonic <MNEMONIC> Custom cosmos wallet mnemonic used for zk-nym redemption. If no value is provided, a fresh mnemonic is going to be generated [env: NYMNODE_MNEMONIC=]
|
||||
--upgrade-mode-attestation-url <UPGRADE_MODE_ATTESTATION_URL> Endpoint to query to retrieve current upgrade mode attestation. This argument should never be set outside testnets and local networks [env: NYMNODE_UPGRADE_MODE_ATTESTATION_URL=]
|
||||
--upgrade-mode-attester-public-key <UPGRADE_MODE_ATTESTER_PUBLIC_KEY> Expected public key of the entity signing the published attestation. This argument should never be set outside testnets and local networks [env: NYMNODE_UPGRADE_MODE_ATTESTER_PUBKEY=]
|
||||
--upstream-exit-policy-url <UPSTREAM_EXIT_POLICY_URL> Specifies the url for an upstream source of the exit policy used by this node [env: NYMNODE_UPSTREAM_EXIT_POLICY=]
|
||||
--open-proxy <OPEN_PROXY> Specifies whether this exit node should run in 'open-proxy' mode and thus would attempt to resolve **ANY** request it receives [env: NYMNODE_OPEN_PROXY=] [possible values: true, false]
|
||||
--lp-control-bind-address <LP_CONTROL_BIND_ADDRESS> Bind address for the TCP LP control traffic. default: `[::]:41264` [env: NYMNODE_LP_CONTROL_BIND_ADDRESS=]
|
||||
--lp-control-announce-port <LP_CONTROL_ANNOUNCE_PORT> Custom announced port for listening for the TCP LP control traffic. If unspecified, the value from the `lp_control_bind_address` will be used instead [env: NYMNODE_LP_CONTROL_ANNOUNCE_PORT=]
|
||||
--lp-data-bind-address <LP_DATA_BIND_ADDRESS> Bind address for the UDP LP data traffic. default: `[::]:51264` [env: NYMNODE_LP_DATA_BIND_ADDRESS=]
|
||||
--lp-data-announce-port <LP_DATA_ANNOUNCE_PORT> Custom announced port for listening for the UDP LP data traffic. If unspecified, the value from the `lp_data_bind_address` will be used instead [env: NYMNODE_LP_DATA_ANNOUNCE_PORT=]
|
||||
--lp-use-mock-ecash <LP_USE_MOCK_ECASH> Use mock ecash manager for LP testing. WARNING: Only use this for local testing! Never enable in production. When enabled, the LP listener will accept any credential without blockchain verification [env:
|
||||
NYMNODE_LP_USE_MOCK_ECASH=] [possible values: true, false]
|
||||
-h, --help Print help
|
||||
--id <ID>
|
||||
Id of the nym-node to use [env: NYMNODE_ID=] [default: default-nym-node]
|
||||
--config-file <CONFIG_FILE>
|
||||
Path to a configuration file of this node [env: NYMNODE_CONFIG=]
|
||||
--accept-operator-terms-and-conditions
|
||||
Explicitly specify whether you agree with the terms and conditions of a nym node operator as defined at <https://nymtech.net/terms-and-conditions/operators/v1.0.0> [env: NYMNODE_ACCEPT_OPERATOR_TERMS=]
|
||||
--deny-init
|
||||
Forbid a new node from being initialised if configuration file for the provided specification doesn't already exist [env: NYMNODE_DENY_INIT=]
|
||||
--init-only
|
||||
If this is a brand new nym-node, specify whether it should only be initialised without actually running the subprocesses [env: NYMNODE_INIT_ONLY=]
|
||||
--local
|
||||
Flag specifying this node will be running in a local setting [env: NYMNODE_LOCAL=]
|
||||
--mode [<MODE>...]
|
||||
Specifies the current mode(s) of this nym-node [env: NYMNODE_MODE=] [possible values: mixnode, entry-gateway, exit-gateway, exit-providers-only]
|
||||
--modes <MODES>
|
||||
Specifies the current mode(s) of this nym-node as a single flag [env: NYMNODE_MODES=] [possible values: mixnode, entry-gateway, exit-gateway, exit-providers-only]
|
||||
-w, --write-changes
|
||||
If this node has been initialised before, specify whether to write any new changes to the config file [env: NYMNODE_WRITE_CONFIG_CHANGES=]
|
||||
--bonding-information-output <BONDING_INFORMATION_OUTPUT>
|
||||
Specify output file for bonding information of this nym-node, i.e. its encoded keys. NOTE: the required bonding information is still a subject to change and this argument should be treated only as a preview of future features [env: NYMNODE_BONDING_INFORMATION_OUTPUT=]
|
||||
-o, --output <OUTPUT>
|
||||
Specify the output format of the bonding information (`text` or `json`) [env: NYMNODE_OUTPUT=] [default: text] [possible values: text, json]
|
||||
--public-ips <PUBLIC_IPS>
|
||||
Comma separated list of public ip addresses that will be announced to the nym-api and subsequently to the clients. In nearly all circumstances, it's going to be identical to the address you're going to use for bonding [env: NYMNODE_PUBLIC_IPS=]
|
||||
--hostname <HOSTNAME>
|
||||
Optional hostname associated with this gateway that will be announced to the nym-api and subsequently to the clients [env: NYMNODE_HOSTNAME=]
|
||||
--location <LOCATION>
|
||||
Optional **physical** location of this node's server. Either full country name (e.g. 'Poland'), two-letter alpha2 (e.g. 'PL'), three-letter alpha3 (e.g. 'POL') or three-digit numeric-3 (e.g. '616') can be provided [env: NYMNODE_LOCATION=]
|
||||
--http-bind-address <HTTP_BIND_ADDRESS>
|
||||
Socket address this node will use for binding its http API. default: `[::]:8080` [env: NYMNODE_HTTP_BIND_ADDRESS=]
|
||||
--landing-page-assets-path <LANDING_PAGE_ASSETS_PATH>
|
||||
Path to assets directory of custom landing page of this node [env: NYMNODE_HTTP_LANDING_ASSETS=]
|
||||
--http-access-token <HTTP_ACCESS_TOKEN>
|
||||
An optional bearer token for accessing certain http endpoints. Currently only used for prometheus metrics [env: NYMNODE_HTTP_ACCESS_TOKEN=]
|
||||
--expose-system-info <EXPOSE_SYSTEM_INFO>
|
||||
Specify whether basic system information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_SYSTEM_INFO=] [possible values: true, false]
|
||||
--expose-system-hardware <EXPOSE_SYSTEM_HARDWARE>
|
||||
Specify whether basic system hardware information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_SYSTEM_HARDWARE=] [possible values: true, false]
|
||||
--expose-crypto-hardware <EXPOSE_CRYPTO_HARDWARE>
|
||||
Specify whether detailed system crypto hardware information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_CRYPTO_HARDWARE=] [possible values: true, false]
|
||||
--mixnet-bind-address <MIXNET_BIND_ADDRESS>
|
||||
Address this node will bind to for listening for mixnet packets default: `[::]:1789` [env: NYMNODE_MIXNET_BIND_ADDRESS=]
|
||||
--mixnet-announce-port <MIXNET_ANNOUNCE_PORT>
|
||||
If applicable, custom port announced in the self-described API that other clients and nodes will use. Useful when the node is behind a proxy [env: NYMNODE_MIXNET_ANNOUNCE_PORT=]
|
||||
--nym-api-urls <NYM_API_URLS>
|
||||
Addresses to nym APIs from which the node gets the view of the network [env: NYMNODE_NYM_APIS=]
|
||||
--nyxd-urls <NYXD_URLS>
|
||||
Addresses to nyxd chain endpoint which the node will use for chain interactions [env: NYMNODE_NYXD=]
|
||||
--enable-console-logging <ENABLE_CONSOLE_LOGGING>
|
||||
Specify whether running statistics of this node should be logged to the console [env: NYMNODE_ENABLE_CONSOLE_LOGGING=] [possible values: true, false]
|
||||
--wireguard-enabled <WIREGUARD_ENABLED>
|
||||
Specifies whether the wireguard service is enabled on this node [env: NYMNODE_WG_ENABLED=] [possible values: true, false]
|
||||
--wireguard-bind-address <WIREGUARD_BIND_ADDRESS>
|
||||
Socket address this node will use for binding its wireguard interface. default: `[::]:51822` [env: NYMNODE_WG_BIND_ADDRESS=]
|
||||
--wireguard-tunnel-announced-port <WIREGUARD_TUNNEL_ANNOUNCED_PORT>
|
||||
Tunnel port announced to external clients wishing to connect to the wireguard interface. Useful in the instances where the node is behind a proxy [env: NYMNODE_WG_ANNOUNCED_PORT=]
|
||||
--wireguard-private-network-prefix <WIREGUARD_PRIVATE_NETWORK_PREFIX>
|
||||
The prefix denoting the maximum number of the clients that can be connected via Wireguard. The maximum value for IPv4 is 32 and for IPv6 is 128 [env: NYMNODE_WG_PRIVATE_NETWORK_PREFIX=]
|
||||
--wireguard-userspace <WIREGUARD_USERSPACE>
|
||||
Use userspace implementation of WireGuard (wireguard-go) instead of kernel module. Useful in containerized environments without kernel WireGuard support [env: NYMNODE_WG_USERSPACE=] [possible values: true, false]
|
||||
--verloc-bind-address <VERLOC_BIND_ADDRESS>
|
||||
Socket address this node will use for binding its verloc API. default: `[::]:1790` [env: NYMNODE_VERLOC_BIND_ADDRESS=]
|
||||
--verloc-announce-port <VERLOC_ANNOUNCE_PORT>
|
||||
If applicable, custom port announced in the self-described API that other clients and nodes will use. Useful when the node is behind a proxy [env: NYMNODE_VERLOC_ANNOUNCE_PORT=]
|
||||
--entry-bind-address <ENTRY_BIND_ADDRESS>
|
||||
Socket address this node will use for binding its client websocket API. default: `[::]:9000` [env: NYMNODE_ENTRY_BIND_ADDRESS=]
|
||||
--announce-ws-port <ANNOUNCE_WS_PORT>
|
||||
Custom announced port for listening for websocket client traffic. If unspecified, the value from the `bind_address` will be used instead [env: NYMNODE_ENTRY_ANNOUNCE_WS_PORT=]
|
||||
--announce-wss-port <ANNOUNCE_WSS_PORT>
|
||||
If applicable, announced port for listening for secure websocket client traffic [env: NYMNODE_ENTRY_ANNOUNCE_WSS_PORT=]
|
||||
--enforce-zk-nyms <ENFORCE_ZK_NYMS>
|
||||
Indicates whether this gateway is accepting only coconut credentials for accessing the mixnet or if it also accepts non-paying clients [env: NYMNODE_ENFORCE_ZK_NYMS=] [possible values: true, false]
|
||||
--mnemonic <MNEMONIC>
|
||||
Custom cosmos wallet mnemonic used for zk-nym redemption. If no value is provided, a fresh mnemonic is going to be generated [env: NYMNODE_MNEMONIC=]
|
||||
--upgrade-mode-attestation-url <UPGRADE_MODE_ATTESTATION_URL>
|
||||
Endpoint to query to retrieve current upgrade mode attestation. This argument should never be set outside testnets and local networks [env: NYMNODE_UPGRADE_MODE_ATTESTATION_URL=]
|
||||
--upgrade-mode-attester-public-key <UPGRADE_MODE_ATTESTER_PUBLIC_KEY>
|
||||
Expected public key of the entity signing the published attestation. This argument should never be set outside testnets and local networks [env: NYMNODE_UPGRADE_MODE_ATTESTER_PUBKEY=]
|
||||
--upstream-exit-policy-url <UPSTREAM_EXIT_POLICY_URL>
|
||||
Specifies the url for an upstream source of the exit policy used by this node [env: NYMNODE_UPSTREAM_EXIT_POLICY=]
|
||||
--open-proxy <OPEN_PROXY>
|
||||
Specifies whether this exit node should run in 'open-proxy' mode and thus would attempt to resolve **ANY** request it receives [env: NYMNODE_OPEN_PROXY=] [possible values: true, false]
|
||||
--lp-control-bind-address <LP_CONTROL_BIND_ADDRESS>
|
||||
Bind address for the TCP LP control traffic. default: `[::]:41264` [env: NYMNODE_LP_CONTROL_BIND_ADDRESS=]
|
||||
--lp-control-announce-port <LP_CONTROL_ANNOUNCE_PORT>
|
||||
Custom announced port for listening for the TCP LP control traffic. If unspecified, the value from the `lp_control_bind_address` will be used instead [env: NYMNODE_LP_CONTROL_ANNOUNCE_PORT=]
|
||||
--lp-data-bind-address <LP_DATA_BIND_ADDRESS>
|
||||
Bind address for the UDP LP data traffic. default: `[::]:51264` [env: NYMNODE_LP_DATA_BIND_ADDRESS=]
|
||||
--lp-data-announce-port <LP_DATA_ANNOUNCE_PORT>
|
||||
Custom announced port for listening for the UDP LP data traffic. If unspecified, the value from the `lp_data_bind_address` will be used instead [env: NYMNODE_LP_DATA_ANNOUNCE_PORT=]
|
||||
--lp-use-mock-ecash <LP_USE_MOCK_ECASH>
|
||||
Use mock ecash manager for LP testing. WARNING: Only use this for local testing! Never enable in production. When enabled, the LP listener will accept any credential without blockchain verification [env: NYMNODE_LP_USE_MOCK_ECASH=] [possible values: true, false]
|
||||
-h, --help
|
||||
Print help
|
||||
```
|
||||
|
||||
@@ -11,7 +11,10 @@ Commands:
|
||||
help Print this message or the help of the given subcommand(s)
|
||||
|
||||
Options:
|
||||
-c, --config-env-file <CONFIG_ENV_FILE> Path pointing to an env file that configures the nymvisor and overrides any preconfigured values
|
||||
-h, --help Print help
|
||||
-V, --version Print version
|
||||
-c, --config-env-file <CONFIG_ENV_FILE>
|
||||
Path pointing to an env file that configures the nymvisor and overrides any preconfigured values
|
||||
-h, --help
|
||||
Print help
|
||||
-V, --version
|
||||
Print version
|
||||
```
|
||||
|
||||
@@ -64,19 +64,19 @@ const config = {
|
||||
},
|
||||
{
|
||||
source: "/docs/architecture/nym-vs-others.html",
|
||||
destination: "/docs/network/overview/comparisons",
|
||||
destination: "/docs/network/architecture/nym-vs-others",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/architecture/traffic-flow.html",
|
||||
destination: "/docs/network/mixnet-mode/traffic-flow",
|
||||
destination: "/docs/network/traffic", // testing difference
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/architecture/addressing-system.html",
|
||||
destination: "/docs/network/reference/addressing",
|
||||
destination: "/docs/network/traffic/addressing-system",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
@@ -100,7 +100,7 @@ const config = {
|
||||
},
|
||||
{
|
||||
source: "/docs/nodes/overview.html ",
|
||||
destination: "/docs/network/infrastructure/nym-nodes",
|
||||
destination: "/docs/network/architecture/mixnet#nym-nodes",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
@@ -132,19 +132,19 @@ const config = {
|
||||
},
|
||||
{
|
||||
source: "/docs/nyx/smart-contracts.html",
|
||||
destination: "/docs/network/infrastructure/nyx#smart-contracts",
|
||||
destination: "/docs/network/architecture/nyx#smart-contracts",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/nyx/mixnet-contract.html",
|
||||
destination: "/docs/network/infrastructure/nyx#mixnet-contract",
|
||||
destination: "/docs/network/architecture/nyx#mixnet-contract",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/nyx/vesting-contract.html",
|
||||
destination: "/docs/network/infrastructure/nyx#vesting-contract",
|
||||
destination: "/docs/network/architecture/nyx#vesting-contract",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
@@ -616,7 +616,7 @@ const config = {
|
||||
},
|
||||
{
|
||||
source: "/docs/architecture/network-overview.html",
|
||||
destination: "/docs/network/overview",
|
||||
destination: "/docs/network/architecture",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
@@ -634,7 +634,7 @@ const config = {
|
||||
},
|
||||
{
|
||||
source: "/docs/network/architecture/nyx/smart-contracts/ecash",
|
||||
destination: "/docs/network/infrastructure/nyx#zk-nym-contract",
|
||||
destination: "/docs/network/architecture/nyx#zk-nym-contract",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
@@ -1073,236 +1073,6 @@ const config = {
|
||||
// destination: "https://www.<TODO_EDIT_DESTINATION_BASE>/developers/typescript/FAQ",
|
||||
// permanent: true,
|
||||
// },
|
||||
|
||||
// ==========================================
|
||||
// Docs rework redirects (2026)
|
||||
// ==========================================
|
||||
|
||||
// --- Network overview: deleted pages ---
|
||||
{
|
||||
source: "/docs/network/overview/two-modes",
|
||||
destination: "/docs/network/overview/choosing-a-mode",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/network/overview/network-components",
|
||||
destination: "/docs/network/infrastructure",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
|
||||
// --- TypeScript SDK: merged pages ---
|
||||
{
|
||||
source: "/docs/developers/typescript/overview",
|
||||
destination: "/docs/developers/typescript",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/developers/typescript/installation",
|
||||
destination: "/docs/developers/typescript",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/developers/typescript/start",
|
||||
destination: "/docs/developers/typescript",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/developers/typescript/FAQ",
|
||||
destination: "/docs/developers/typescript/bundling/bundling",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
|
||||
// --- Rust SDK: deleted mixnet example subpages ---
|
||||
{
|
||||
source: "/docs/developers/rust/mixnet/examples/:path+",
|
||||
destination: "/docs/developers/rust/mixnet/examples",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/developers/rust/mixnet/message-helpers",
|
||||
destination: "/docs/developers/rust/mixnet",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/developers/rust/mixnet/message-types",
|
||||
destination: "/docs/developers/rust/mixnet",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
|
||||
// --- Rust SDK: deleted client-pool subpages ---
|
||||
{
|
||||
source: "/docs/developers/rust/client-pool/architecture",
|
||||
destination: "/docs/developers/rust/client-pool",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/developers/rust/client-pool/example",
|
||||
destination: "/docs/developers/rust/client-pool",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
|
||||
// --- Rust SDK: collapsed TcpProxy subpages ---
|
||||
{
|
||||
source: "/docs/developers/rust/tcpproxy/troubleshooting",
|
||||
destination: "/docs/developers/rust/tcpproxy",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/developers/rust/tcpproxy/tutorial",
|
||||
destination: "/docs/developers/rust/tcpproxy",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/developers/rust/tcpproxy/architecture",
|
||||
destination: "/docs/developers/rust/tcpproxy",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/developers/rust/tcpproxy/examples",
|
||||
destination: "/docs/developers/rust/tcpproxy",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
|
||||
// --- Directory index redirects (directories without index pages) ---
|
||||
{
|
||||
source: "/docs/developers/typescript/bundling",
|
||||
destination: "/docs/developers/typescript/bundling/bundling",
|
||||
permanent: false,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/developers/typescript/examples",
|
||||
destination: "/docs/developers/typescript/examples/mix-fetch",
|
||||
permanent: false,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/developers/typescript/playground",
|
||||
destination: "/docs/developers/typescript/playground/mixfetch",
|
||||
permanent: false,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/developers/typescript/api",
|
||||
destination: "/docs/developers/typescript/api/sdk",
|
||||
permanent: false,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/developers/clients",
|
||||
destination: "/docs/developers/clients/socks5",
|
||||
permanent: false,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/developers/rust/importing",
|
||||
destination: "/docs/developers/rust/importing",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
|
||||
// --- APIs: flattened structure ---
|
||||
{
|
||||
source: "/docs/apis/ns-api/mainnet",
|
||||
destination: "/docs/apis/ns-api",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/apis/ns-api/sandbox",
|
||||
destination: "/docs/apis/ns-api",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/apis/ns-api/ns-api-run-deploy",
|
||||
destination: "/docs/operators/performance-and-testing/ns-api-deployment",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/apis/nym-api/mainnet",
|
||||
destination: "/docs/apis/nym-api",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/apis/explorer-api/mainnet",
|
||||
destination: "/docs/apis/explorer-api",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/apis/explorer-api/sandbox",
|
||||
destination: "/docs/apis/explorer-api",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/apis/cosmos-sdk-nyx/mainnet",
|
||||
destination: "/docs/apis/cosmos-sdk-nyx",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/apis/cosmos-sdk-nyx/sandbox",
|
||||
destination: "/docs/apis/cosmos-sdk-nyx",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
|
||||
// --- Network: archived sections ---
|
||||
{
|
||||
source: "/docs/network/architecture",
|
||||
destination: "/docs/network/overview",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/network/architecture/:path*",
|
||||
destination: "/docs/network/overview",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/network/concepts",
|
||||
destination: "/docs/network/overview",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/network/concepts/:path*",
|
||||
destination: "/docs/network/overview",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/network/traffic",
|
||||
destination: "/docs/network/overview",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/network/traffic/:path*",
|
||||
destination: "/docs/network/overview",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
];
|
||||
},
|
||||
images: {
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
"generate:commands": "../scripts/next-scripts/autodoc.sh",
|
||||
"generate:tables": "../scripts/next-scripts/python-prebuild.sh",
|
||||
"predev": "../scripts/next-scripts/python-prebuild.sh",
|
||||
"generate:llms": "node ../scripts/next-scripts/generate-llms-txt.mjs",
|
||||
"build": "node ../scripts/next-scripts/generate-llms-txt.mjs && next build && next-sitemap",
|
||||
"build": "next build && next-sitemap",
|
||||
"dev": " next dev",
|
||||
"lint": "next lint",
|
||||
"lint:fix": "next lint --fix",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"introduction": "Introduction",
|
||||
"ns-api": "Node Status API",
|
||||
"nym-api": "NymAPI",
|
||||
"nym-api": "NymAPI Validator Sidecar",
|
||||
"explorer-api": "Explorer API",
|
||||
"cosmos-sdk-nyx": "Validator REST API",
|
||||
"explorer-api": "Explorer API (Deprecated)",
|
||||
"---": {
|
||||
"type": "separator"
|
||||
},
|
||||
|
||||
@@ -1,57 +1,3 @@
|
||||
---
|
||||
title: "Nyx Validator REST API - Cosmos SDK Endpoints"
|
||||
description: "Reference for the Nyx Validator REST API, providing Cosmos SDK endpoints for account balances, staking, governance, and CosmWasm smart contract queries."
|
||||
schemaType: "TechArticle"
|
||||
section: "APIs"
|
||||
lastUpdated: "2026-03-15"
|
||||
---
|
||||
|
||||
import { RedocStandalone } from 'redoc'
|
||||
|
||||
# Validator REST API
|
||||
|
||||
Nyx Validators are built with the [Cosmos SDK](https://docs.cosmos.network/) and expose a standard [REST API](https://docs.cosmos.network/api) for querying chain state directly.
|
||||
|
||||
**Key endpoint categories:**
|
||||
- **Accounts**: balances, transaction history
|
||||
- **Staking**: validators, delegations, rewards
|
||||
- **Governance**: proposals, votes
|
||||
- **CosmWasm**: smart contract queries
|
||||
|
||||
For validator setup instructions, see the [Nyx Validator Setup Guide](/operators/nodes/validator-setup).
|
||||
|
||||
Other validator endpoints are listed at [cosmos.directory/nyx](https://cosmos.directory/nyx).
|
||||
|
||||
## Quick examples
|
||||
|
||||
**Query an account balance:**
|
||||
```bash
|
||||
curl https://api.nymtech.net/cosmos/bank/v1beta1/balances/n1...
|
||||
```
|
||||
|
||||
**List active validators:**
|
||||
```bash
|
||||
curl https://api.nymtech.net/cosmos/staking/v1beta1/validators?status=BOND_STATUS_BONDED
|
||||
```
|
||||
|
||||
## Mainnet endpoints
|
||||
|
||||
- **OpenAPI spec:** [api.nymtech.net/swagger/swagger.yaml](https://api.nymtech.net/swagger/swagger.yaml)
|
||||
- **Swagger UI:** [api.nymtech.net/swagger/](https://api.nymtech.net/swagger/)
|
||||
|
||||
## Full API reference
|
||||
|
||||
<br />
|
||||
|
||||
<RedocStandalone
|
||||
specUrl="https://api.nymtech.net/swagger/swagger.yaml"
|
||||
options={{
|
||||
nativeScrollbars: true,
|
||||
theme: {
|
||||
sidebar: {
|
||||
backgroundColor: '#273239',
|
||||
textColor: '#FCFDFE'
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
Since the [Nyx validators](/operators/nodes/validator-setup) are built with the Cosmos SDK, they by default expose a [REST API](https://docs.cosmos.network/api) which can be used to query the state of the chain.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
{
|
||||
"mainnet":"Mainnet Endpoints",
|
||||
"sandbox":"Sandbox Endpoints"
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { RedocStandalone } from 'redoc';
|
||||
|
||||
The information below is generated with [Redoc](https://redocly.com/docs/redoc) consuming the OpenAPI spec found at [https://api.nymtech.net/swagger/swagger.yaml](https://api.nymtech.net/swagger/swagger.yaml) which is also used to generate the Swagger docs deployed at [https://api.nymtech.net/swagger/](https://api.nymtech.net/swagger/).
|
||||
|
||||
There is also an overview of other Validator endpoints at [https://cosmos.directory/nyx](https://cosmos.directory/nyx).
|
||||
|
||||
<br /><br />
|
||||
|
||||
<RedocStandalone
|
||||
specUrl="https://api.nymtech.net/swagger/swagger.yaml"
|
||||
options={{
|
||||
nativeScrollbars: true,
|
||||
theme: {
|
||||
sidebar: {
|
||||
backgroundColor: '#273239',
|
||||
textColor: '#FCFDFE'
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -0,0 +1,18 @@
|
||||
import { RedocStandalone } from 'redoc';
|
||||
|
||||
The information below is generated with [Redoc](https://redocly.com/docs/redoc) consuming the OpenAPI spec found at [https://api.sandbox.nymtech.net/swagger/swagger.yaml](https://api.sandbox.nymtech.net/swagger/swagger.yaml).
|
||||
|
||||
<br /><br />
|
||||
|
||||
<RedocStandalone
|
||||
specUrl="https://api.sandbox.nymtech.net/swagger/swagger.yaml"
|
||||
options={{
|
||||
nativeScrollbars: true,
|
||||
theme: {
|
||||
sidebar: {
|
||||
backgroundColor: '#273239',
|
||||
textColor: '#FCFDFE'
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -1,39 +1,8 @@
|
||||
---
|
||||
title: "Explorer API (Deprecated)"
|
||||
description: "Legacy Explorer API reference for the Nym Mixnet Explorer. Deprecated in favor of the Node Status API."
|
||||
schemaType: "TechArticle"
|
||||
section: "APIs"
|
||||
lastUpdated: "2026-03-15"
|
||||
---
|
||||
|
||||
import { RedocStandalone } from 'redoc'
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
# Explorer API
|
||||
|
||||
<Callout type="warning">
|
||||
The Explorer API is deprecated. Use the [Node Status API](/apis/ns-api) instead, which provides the same data and more.
|
||||
</Callout>
|
||||
The Explorer API is the backend for the [Mixnet Explorer](https://nym.com/explorer).
|
||||
|
||||
The Explorer API is the legacy backend for the [Mixnet Explorer](https://nym.com/explorer).
|
||||
|
||||
## Mainnet endpoints
|
||||
|
||||
- **OpenAPI spec:** [explorer.nymtech.net/api/v1/openapi.json](https://explorer.nymtech.net/api/v1/openapi.json)
|
||||
- **Swagger UI:** [explorer.nymtech.net/api/swagger/index.html](https://explorer.nymtech.net/api/swagger/index.html)
|
||||
|
||||
<br />
|
||||
|
||||
<RedocStandalone
|
||||
specUrl="https://explorer.nymtech.net/api/v1/openapi.json"
|
||||
options={{
|
||||
nativeScrollbars: true,
|
||||
theme: {
|
||||
sidebar: {
|
||||
backgroundColor: '#273239',
|
||||
textColor: '#FCFDFE'
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
**This will soon be deprecated in favour of the [Node Status API](ns-api.mdx).**
|
||||
|
||||
The code for this service can be found [in our monorepo](https://github.com/nymtech/nym/tree/develop/explorer).
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
{
|
||||
"mainnet":"Mainnet Endpoints",
|
||||
"sandbox":"Sandbox Endpoints"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
import { RedocStandalone } from 'redoc';
|
||||
|
||||
The information below is generated with [Redoc](https://redocly.com/docs/redoc) consuming the OpenAPI spec found at [https://explorer.nymtech.net/api/v1/openapi.json](https://explorer.nymtech.net/api/v1/openapi.json) which is also used to generate the Swagger docs deployed at [https://explorer.nymtech.net/api/swagger/index.html](https://explorer.nymtech.net/api/swagger/index.html).
|
||||
|
||||
<br /><br />
|
||||
|
||||
<RedocStandalone
|
||||
specUrl="https://sandbox-explorer.nymtech.net/api/v1/openapi.json"
|
||||
options={{
|
||||
nativeScrollbars: true,
|
||||
theme: {
|
||||
sidebar: {
|
||||
backgroundColor: '#273239',
|
||||
textColor: '#FCFDFE'
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -0,0 +1,18 @@
|
||||
import { RedocStandalone } from 'redoc';
|
||||
|
||||
The information below is generated with [Redoc](https://redocly.com/docs/redoc) consuming the OpenAPI spec found at [https://sandbox-explorer.nymtech.net/api/v1/openapi.json](https://sandbox-explorer.nymtech.net/api/v1/openapi.json) which is also used to generate the Swagger docs deployed at [https://sandbox-explorer.nymtech.net/api/swagger/index.html](https://sandbox-explorer.nymtech.net/api/swagger/index.html).
|
||||
|
||||
<br /><br />
|
||||
|
||||
<RedocStandalone
|
||||
specUrl="https://sandbox-explorer.nymtech.net/api/v1/openapi.json"
|
||||
options={{
|
||||
nativeScrollbars: true,
|
||||
theme: {
|
||||
sidebar: {
|
||||
backgroundColor: '#273239',
|
||||
textColor: '#FCFDFE'
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -1,58 +1,13 @@
|
||||
---
|
||||
title: "Nym Network APIs Overview"
|
||||
description: "Overview of Nym HTTP APIs for querying node performance, token supply, credential data, and blockchain state, with guidance on which API to use."
|
||||
title: "Nym API Reference: Network Infrastructure"
|
||||
description: "Interactive API documentation for Nym network infrastructure. Query node status, network topology, blockchain state & mixnet performance programmatically."
|
||||
schemaType: "TechArticle"
|
||||
section: "APIs"
|
||||
lastUpdated: "2026-03-15"
|
||||
lastUpdated: "2026-02-01"
|
||||
---
|
||||
|
||||
import { Callout } from 'nextra/components'
|
||||
# Introduction
|
||||
|
||||
# APIs
|
||||
This site contains interactive APIs generated from the OpenAPI specs of various API endpoints offered by bits of Nym infrastructure run both by Nym and community operators for both Mainnet and the Sandbox testnet.
|
||||
|
||||
The Nym network exposes several HTTP APIs for querying network state, node performance, blockchain data, and credential information, with each API serving a different purpose.
|
||||
|
||||
## Which API should I use?
|
||||
|
||||
| I want to... | API |
|
||||
|---|---|
|
||||
| Query node performance, roles, and mixnet statistics | [Node Status API](/apis/ns-api) |
|
||||
| Query circulating NYM supply or zk-nym credential data | [NymAPI](/apis/nym-api) |
|
||||
| Query blockchain state, account balances, or transactions | [Validator REST API](/apis/cosmos-sdk-nyx) |
|
||||
| Query legacy explorer data | [Explorer API](/apis/explorer-api) *(deprecated)* |
|
||||
|
||||
## Node Status API
|
||||
|
||||
The primary API for querying node information. It serves data about individual `nym-node` instances: roles, statistics, Network Requester services, and overall mixnet summaries. If you're building an explorer, analytics dashboard, or monitoring tool, start here.
|
||||
|
||||
<Callout type="info">
|
||||
If you're building a service that makes heavy use of the Node Status API, consider [running your own instance](/operators/performance-and-testing/ns-api-deployment) to distribute load across the network.
|
||||
</Callout>
|
||||
|
||||
**Endpoints:** [OpenAPI spec](https://mainnet-node-status-api.nymtech.cc/api-docs/openapi.json) · [Swagger](https://mainnet-node-status-api.nymtech.cc/swagger/)
|
||||
|
||||
## NymAPI
|
||||
|
||||
A sidecar binary operated by Nyx Validators. It caches smart contract data and exposes endpoints for circulating NYM supply, zk-nym credential data, and ticketbook information. Use this when you need token economics or credential data.
|
||||
|
||||
**Endpoints:** [OpenAPI spec](https://validator.nymtech.net/api-docs/openapi.json) · [Swagger](https://validator.nymtech.net/api/swagger/index.html)
|
||||
|
||||
Other NymAPI instances are listed at [cosmos.directory/nyx](https://cosmos.directory/nyx).
|
||||
|
||||
## Validator REST API
|
||||
|
||||
The standard Cosmos SDK REST API exposed by Nyx Validators. Use this for direct chain queries: account balances, transaction history, governance proposals, and staking information.
|
||||
|
||||
**Endpoints:** [OpenAPI spec](https://api.nymtech.net/swagger/swagger.yaml) · [Swagger](https://api.nymtech.net/swagger/)
|
||||
|
||||
Other validator endpoints are listed at [cosmos.directory/nyx](https://cosmos.directory/nyx).
|
||||
|
||||
## Explorer API
|
||||
|
||||
<Callout type="warning">
|
||||
The Explorer API is deprecated. Use the [Node Status API](/apis/ns-api) instead.
|
||||
</Callout>
|
||||
|
||||
The legacy backend for the [Mixnet Explorer](https://nym.com/explorer). This API is being replaced by the Node Status API, which provides the same data and more.
|
||||
|
||||
**Endpoints:** [OpenAPI spec](https://explorer.nymtech.net/api/v1/openapi.json) · [Swagger](https://explorer.nymtech.net/api/swagger/index.html)
|
||||
You can find links to the generated specs for each API on their respective pages as well as their different uses for operators and developers.
|
||||
|
||||
@@ -1,57 +1,8 @@
|
||||
---
|
||||
title: "Node Status API - Nym Node Performance and Mixnet Stats"
|
||||
description: "Reference for the Node Status API, which provides nym-node identity, performance scores, role assignments, and mixnet health summaries."
|
||||
schemaType: "TechArticle"
|
||||
section: "APIs"
|
||||
lastUpdated: "2026-03-15"
|
||||
---
|
||||
|
||||
import { RedocStandalone } from 'redoc'
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
# Node Status API
|
||||
|
||||
The Node Status API serves information about individual `nym-node` instances in the Nym network: which role they are operating in, performance statistics, Network Requester services, and summaries of the overall mixnet state. It is the primary API for anyone building explorers, analytics dashboards, or monitoring tools.
|
||||
|
||||
**Key endpoint categories:**
|
||||
- **Node information**: identity, bonding status, declared roles, build version, host details
|
||||
- **Performance scores**: routing reliability, configuration scores, probe results
|
||||
- **Mixnet summaries**: active set composition, role distribution, network health
|
||||
The Node Status API serves information about individual `nym-nodes` in the Mixnet, such as which role they are operating in, statistics about them, services such as Network Requesters, as well as summaries of the state of the Mixnet.
|
||||
|
||||
<Callout type="info">
|
||||
If you're building a service that makes heavy use of this API, consider [running your own instance](/operators/performance-and-testing/ns-api-deployment) to distribute load and promote a robust network of downstream services.
|
||||
We recommend that developers building applications such as explorers or analytics interfaces about the Mixnet run their own instance of the API, in order to promote a robust network of downstream services, and spread the load of API calls amongst as many endpoints as possible.
|
||||
</Callout>
|
||||
|
||||
## Quick examples
|
||||
|
||||
**Get a summary of all gateways:**
|
||||
```bash
|
||||
curl https://mainnet-node-status-api.nymtech.cc/api/v1/gateways
|
||||
```
|
||||
|
||||
**Get details for a specific node by identity key:**
|
||||
```bash
|
||||
curl https://mainnet-node-status-api.nymtech.cc/api/v1/gateways/23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb
|
||||
```
|
||||
|
||||
## Mainnet endpoints
|
||||
|
||||
- **OpenAPI spec:** [mainnet-node-status-api.nymtech.cc/api-docs/openapi.json](https://mainnet-node-status-api.nymtech.cc/api-docs/openapi.json)
|
||||
- **Swagger UI:** [mainnet-node-status-api.nymtech.cc/swagger/](https://mainnet-node-status-api.nymtech.cc/swagger/)
|
||||
|
||||
## Full API reference
|
||||
|
||||
<br />
|
||||
|
||||
<RedocStandalone
|
||||
specUrl="https://mainnet-node-status-api.nymtech.cc/api-docs/openapi.json"
|
||||
options={{
|
||||
nativeScrollbars: true,
|
||||
theme: {
|
||||
sidebar: {
|
||||
backgroundColor: '#273239',
|
||||
textColor: '#FCFDFE'
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"ns-api-run-deploy":"Run Instance",
|
||||
"mainnet":"Mainnet Endpoints",
|
||||
"sandbox":"Sandbox Endpoints"
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { RedocStandalone } from 'redoc';
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
The information below is generated with [Redoc](https://redocly.com/docs/redoc) consuming the OpenAPI spec found at [https://mainnet-node-status-api.nymtech.cc/api-docs/openapi.json](https://mainnet-node-status-api.nymtech.cc/api-docs/openapi.json) which is also used to generate the Swagger docs deployed at [https://mainnet-node-status-api.nymtech.cc/swagger/](https://mainnet-node-status-api.nymtech.cc/swagger/).
|
||||
|
||||
<br /><br />
|
||||
|
||||
|
||||
<RedocStandalone
|
||||
specUrl="https://mainnet-node-status-api.nymtech.cc/api-docs/openapi.json"
|
||||
options={{
|
||||
nativeScrollbars: true,
|
||||
theme: {
|
||||
sidebar: {
|
||||
backgroundColor: '#273239',
|
||||
textColor: '#FCFDFE'
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
+3
-3
@@ -9,7 +9,7 @@ The Node Status API is made up of 3 components:
|
||||
- `nym-node-status-client`
|
||||
- `nym-node-status-agent`
|
||||
|
||||
The API stores its data in a local SQLite database. It periodically gets most of its data from a [NymAPI](/apis/nym-api) instance, and for instances also running with the Gateway Probe, uses the stored topology to conduct performance probe tests.
|
||||
The API stores its data in a local SQLite database. It periodically gets most of its data from a [NymAPI](../nym-api) instance, and for instances also running with the Gateway Probe, uses the stored topology to conduct performance probe tests.
|
||||
|
||||
## Gateway Probe
|
||||
You can run the `nym-node-status-api` alone, but if you want to run probes for `nym-node`s running as Gateways, you have to also run the `nym-node-status-agent` (which consumes the `nym-node-status-client` lib). The probe will run a set of tests per Gateway node, and return the sort of results seen [here](https://harbourmaster.nymtech.net/gateway/23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb).
|
||||
@@ -171,7 +171,7 @@ If you have already run the API before, make sure to add the following to your s
|
||||
If you want to enable Gateway node probes and have the NS API store that data, you need to periodically run the `nym-node-status-agent`, authenticated with your `nym-node-status-api` instance. Authentication is to make sure that only the `-agent` you are operating (or others you trust) are submitting data to your API instance.
|
||||
|
||||
#### Compile Gateway Probe
|
||||
The `nym-node-status-agent` is a thin wrapper around the Gateway Probe binary which lives in the [Nym monorepo](https://github.com/nymtech/nym/tree/develop/nym-gateway-probe). Compile the probe by following the readme instructions there. You will point the `-agent` at this binary when doing Probe testruns.
|
||||
The `nym-node-status-agent` is a thin wrapper around the Gateway Probe binary which currently is in the NymVPN repo. `git checkout` to the most recent [release](https://github.com/nymtech/nym-vpn-client/releases), and compile the probe by following the [readme instructions](https://github.com/nymtech/nym-vpn-client/tree/develop/nym-vpn-core/crates/nym-gateway-probe). You will point the `-agent` at this binary when doing Probe testruns.
|
||||
|
||||
#### Generate Keypair
|
||||
```shell
|
||||
@@ -316,7 +316,7 @@ function swarm() {
|
||||
local workers=$1
|
||||
|
||||
for ((i = 1; i <= workers; i++)); do
|
||||
${monorepo_root}/target/release/nym-node-status-agent run-probe --probe-path ${monorepo_root}/target/release/nym-gateway-probe &
|
||||
${monorepo_root}/target/release/nym-node-status-agent run-probe --probe-path ~/<PATH/TO>/nym-vpn-client/nym-vpn-core/target/debug/nym-gateway-probe &
|
||||
done
|
||||
|
||||
wait
|
||||
@@ -0,0 +1,18 @@
|
||||
import { RedocStandalone } from 'redoc';
|
||||
|
||||
The information below is generated with [Redoc](https://redocly.com/docs/redoc) consuming the OpenAPI spec found at [https://sandbox-node-status-api.nymte.ch/api-docs/openapi.json](https://sandbox-node-status-api.nymte.ch/api-docs/openapi.json) which is also used to generate the Swagger docs deployed at [https://sandbox-node-status-api.nymte.ch/swagger/](https://sandbox-node-status-api.nymte.ch/swagger/).
|
||||
|
||||
<br /><br />
|
||||
|
||||
<RedocStandalone
|
||||
specUrl="https://sandbox-node-status-api.nymte.ch/api-docs/openapi.json"
|
||||
options={{
|
||||
nativeScrollbars: true,
|
||||
theme: {
|
||||
sidebar: {
|
||||
backgroundColor: '#273239',
|
||||
textColor: '#FCFDFE'
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -1,63 +1,5 @@
|
||||
---
|
||||
title: "NymAPI - Token Supply and Credential Endpoints"
|
||||
description: "Reference for the NymAPI, a validator sidecar that caches Nyx blockchain data and exposes endpoints for circulating NYM supply, zk-nym credentials, and network topology."
|
||||
schemaType: "TechArticle"
|
||||
section: "APIs"
|
||||
lastUpdated: "2026-03-15"
|
||||
---
|
||||
|
||||
import APITable from 'components/api-table.tsx'
|
||||
import { RedocStandalone } from 'redoc'
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
# NymAPI
|
||||
|
||||
The NymAPI is a sidecar binary operated by members of the Nyx Validator set that caches smart contract data from the Nyx blockchain and exposes it via HTTP endpoints, making queries faster and more scalable than querying the chain directly.
|
||||
The [NymAPI](/operators/nodes/validator-setup/nym-api) is a sidecar binary operated by members of the Nym Validator set. Amongst other things, the API offers endpoints to query regarding circulating `NYM` supply, and global and ticketbook-specific [zk-nym](/network/cryptography/zk-nym) data. This is all information contained in various smart contracts on the Nyx blockchain; the NymAPI caches this information periodically to make queries faster and more scalable.
|
||||
|
||||
**Key endpoint categories:**
|
||||
- **Token economics:** circulating NYM supply, staking information
|
||||
- **Credential data:** zk-nym ticketbook information, global and per-ticketbook data
|
||||
- **Network topology:** cached node and mixnet data from on-chain contracts
|
||||
|
||||
For operator setup instructions, see the [NymAPI Operator Guide](/operators/nodes/validator-setup/nym-api).
|
||||
|
||||
## Quick examples
|
||||
|
||||
**Get the circulating NYM supply:**
|
||||
```bash
|
||||
curl https://validator.nymtech.net/api/v1/circulating-supply
|
||||
```
|
||||
|
||||
**Get the current network topology (Mix Nodes and gateways):**
|
||||
```bash
|
||||
curl https://validator.nymtech.net/api/v1/mixnodes/active
|
||||
```
|
||||
|
||||
## Mainnet endpoints
|
||||
|
||||
- **OpenAPI spec:** [validator.nymtech.net/api-docs/openapi.json](https://validator.nymtech.net/api-docs/openapi.json)
|
||||
- **Swagger UI:** [validator.nymtech.net/api/swagger/index.html](https://validator.nymtech.net/api/swagger/index.html)
|
||||
|
||||
<Callout type="info">
|
||||
Other NymAPI instances are available. You can find their Swagger endpoints here:
|
||||
<APITable endpoint="https://api.nymtech.net/cosmwasm/wasm/v1/contract/n19604yflqggs9mk2z26mqygq43q2kr3n932egxx630svywd5mpxjsztfpvx/smart/eyJnZXRfY3VycmVudF9kZWFsZXJzIjogeyJsaW1pdCI6IDMwfX0=" />
|
||||
|
||||
There is also an overview of endpoints at [cosmos.directory/nyx](https://cosmos.directory/nyx).
|
||||
</Callout>
|
||||
|
||||
## Full API reference
|
||||
|
||||
<br />
|
||||
|
||||
<RedocStandalone
|
||||
specUrl="https://validator.nymtech.net/api-docs/openapi.json"
|
||||
options={{
|
||||
nativeScrollbars: true,
|
||||
theme: {
|
||||
sidebar: {
|
||||
backgroundColor: '#273239',
|
||||
textColor: '#FCFDFE'
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
The code for this service can be found [in our monorepo](https://github.com/nymtech/nym/tree/develop/nym-api).
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"mainnet":"Mainnet Endpoints"
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import APITable from 'components/api-table.tsx';
|
||||
import { RedocStandalone } from 'redoc';
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
You can find the OpenAPI spec found at [https://validator.nymtech.net/api-docs/openapi.json](https://validator.nymtech.net/api-docs/openapi.json) which is also used to generate the Swagger docs deployed at [https://validator.nymtech.net/api/swagger/index.html](https://validator.nymtech.net/api/swagger/index.html).
|
||||
|
||||
<Callout type="info" emoji="ℹ️">
|
||||
You can find the Swagger endpoints of other NymAPI instances at the following endpoints:
|
||||
<APITable endpoint="https://api.nymtech.net/cosmwasm/wasm/v1/contract/n19604yflqggs9mk2z26mqygq43q2kr3n932egxx630svywd5mpxjsztfpvx/smart/eyJnZXRfY3VycmVudF9kZWFsZXJzIjogeyJsaW1pdCI6IDMwfX0=" />
|
||||
|
||||
There is also an overview of endpoints at [https://cosmos.directory/nyx](https://cosmos.directory/nyx).
|
||||
</Callout>
|
||||
|
||||
<br /><br />
|
||||
|
||||
<RedocStandalone
|
||||
specUrl="https://validator.nymtech.net/api-docs/openapi.json"
|
||||
options={{
|
||||
nativeScrollbars: true,
|
||||
theme: {
|
||||
sidebar: {
|
||||
backgroundColor: '#273239',
|
||||
textColor: '#FCFDFE'
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -16,12 +16,12 @@
|
||||
"typescript": "Typescript SDK",
|
||||
"---": {
|
||||
"type": "separator",
|
||||
"title": "Extras"
|
||||
"title": "Misc"
|
||||
},
|
||||
"nymvpncli": "Nym VPN CLI",
|
||||
"chain": "Interacting with Nyx Blockchain",
|
||||
"tools": "Tools",
|
||||
"clients": "Standalone Clients",
|
||||
"nymvpncli": "Nym VPN CLI",
|
||||
"clients": "Standlone Clients",
|
||||
"----": {
|
||||
"type": "separator"
|
||||
},
|
||||
|
||||
+4
-6
@@ -1,11 +1,9 @@
|
||||
# Archive page: NymConnect Setup
|
||||
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
<Callout type="warning">
|
||||
NymConnect is no longer maintained as of early 2024. Nym is developing a new client called [NymVPN](https://nymvpn.com), an application routing all user traffic through the Mixnet.
|
||||
If you want to route traffic through SOCKS5, use the maintained [Nym Socks5 Client](../clients/socks5/setup).
|
||||
</Callout>
|
||||
```admonish warning
|
||||
Since the beginning of 2024 NymConnect is no longer maintained. Nym is developing a new client called [NymVPN](https://nymvpn.com), an application routing all users traffic thorugh the mixnet.
|
||||
If users want to route their traffic through socks5 we advice to use maintained [Nym Socks5 Client](../clients/socks5/setup).
|
||||
```
|
||||
|
||||
In case you want to run deprecated NymConnect, follow these steps:
|
||||
|
||||
@@ -1,43 +1,45 @@
|
||||
---
|
||||
title: "Browser-Based App Integration"
|
||||
description: "Build privacy-preserving browser apps with mixFetch and the Nym WASM SDK. Route HTTP requests and messages through the mixnet from the browser."
|
||||
schemaType: "TechArticle"
|
||||
section: "Developers"
|
||||
lastUpdated: "2026-04-07"
|
||||
---
|
||||
|
||||
import { Callout } from 'nextra/components';
|
||||
|
||||
# Browser-Based Apps
|
||||
Browsers are a very restricted environment to work in, with limited options for external communications (websockets, Web Transport API, WebRTC), mixed content restrictions (HTTPS-only), and no access to the file system or any syscalls. These aside, the main issue when trying to capture traffic and send it via a different transport - such as the Mixnet - is the lack of access to browser TLS negotiation from JS or the CA certificate store.
|
||||
|
||||
Browsers are a restricted environment: communication is limited to WebSockets, Web Transport, and WebRTC; mixed content policies enforce HTTPS-only; and there is no access to the filesystem or system calls. The main obstacle for routing traffic through the Mixnet is the lack of access to browser TLS negotiation or the CA certificate store from JavaScript.
|
||||
|
||||
Two integration options are available, both delivered as packages bundled into your web application.
|
||||
This means that the functionality offered by our current browser-based solutions are quite restricted / specific. There are currently two options for interacting with the Mixnet from the browser: `mixFetch`, and the WASM SDK.
|
||||
|
||||

|
||||
|
||||
Both `mixFetch` and the WASM client are delivered to the client bundled into a web application.
|
||||
|
||||
## mixFetch
|
||||
Drop-in replacement for browser's `fetch` API that makes HTTP(S) requests via Exit Gateways using the SOCKS Network Requester.
|
||||
|
||||
A drop-in replacement for the browser `fetch` API that makes HTTP(S) requests via Exit Gateways using the SOCKS Network Requester. It ships with an embedded CA certificate store to establish a TLS session between `mixFetch` and the remote host, creating a secure channel from the browser to the destination over the Mixnet.
|
||||
Uses an embedded CA certificate store to establish TLS session between `mixFetch` and the remote host, creating a client-host secure channel from the browser to the host over the Mixnet.
|
||||
|
||||
Internally, `mixFetch` uses the WASM client.
|
||||
Internally it uses the WASM client.
|
||||
|
||||
- [Docs](./typescript#mixfetch)
|
||||
- [Example](./typescript/playground/mixfetch)
|
||||
- [docs](./typescript/start#mixfetch)
|
||||
- [example](./typescript/playground/mixfetch)
|
||||
|
||||
<Callout type="info">
|
||||
`mixFetch` currently supports a maximum of 10 concurrent in-flight requests. `mixFetchv2`, which will function as a general-purpose userspace IP stack, is in development.
|
||||
|
||||
### Current Limitations of `mixFetch`
|
||||
|
||||
`mixFetch` can currently only perform 10 concurrent requests (i.e. in-flight requests where a request has been sent to a remote endpoint, but no result has been recieved).
|
||||
|
||||
`mixFetchv2` - which will act more like a general-purpose userspace IP stack - is currently in development.
|
||||
|
||||
It is shipped with a pre-bundled CA store.
|
||||
|
||||
</Callout>
|
||||
|
||||
|
||||
## WASM Client
|
||||
Makes Sphinx packets and cover traffic using WASM and sent over a Websocket to the Entry Gateway and receive responses.
|
||||
|
||||
Constructs Sphinx packets and cover traffic in WASM, sent over a WebSocket to the Entry Gateway. Responses arrive the same way.
|
||||
This only works in messaging mode (i.e. messages sent either as text or binary data), and currently doesn’t support making IP packets that are routed to the Internet by an Exit Gateway IPR, nor does it currently expose any stream-like API. If you want to send HTTP(S) requests, use `mixFetch`.
|
||||
|
||||
This operates in messaging mode only (text or binary payloads) and does not currently support IP packet routing via the Exit Gateway IPR or any stream-like API. For HTTP(S) requests, use `mixFetch`.
|
||||
Note that the limitations of CSPs and Mixed Content restrictions (i.e HTTPS only) apply to the Websocket connection as normal in browsers or embedded WebViews.
|
||||
|
||||
Standard browser CSP and mixed content restrictions (HTTPS only) apply to the WebSocket connection, including in embedded WebViews.
|
||||
Runs in a web worker to leave UI thread free for the user.
|
||||
|
||||
The client runs in a web worker to keep the UI thread free.
|
||||
|
||||
- [Docs](./typescript#mixnet-client)
|
||||
- [Example](./typescript/playground/traffic)
|
||||
- [docs](./typescript/start#mixnet-client)
|
||||
- [example](./typescript/playground/traffic)
|
||||
|
||||
@@ -13,7 +13,7 @@ There are two options for interacting with the blockchain to send tokens or inte
|
||||
* `nyxd` binary
|
||||
|
||||
## Nym-CLI tool (recommended in most cases)
|
||||
The `nym-cli` tool is a binary offering a simple interface for interacting with deployed smart contract (for instance, bonding and unbonding a Mix Node from the CLI), as well as creating and managing accounts and keypairs, sending tokens, and querying the blockchain.
|
||||
The `nym-cli` tool is a binary offering a simple interface for interacting with deployed smart contract (for instance, bonding and unbonding a mix node from the CLI), as well as creating and managing accounts and keypairs, sending tokens, and querying the blockchain.
|
||||
|
||||
Instructions on how to do so can be found on the [`nym-cli` docs page](./tools/nym-cli)
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ nyxd tx bank send ledger_account $DESTINATION_ACCOOUNT 1000000unym --ledger --no
|
||||
> When a command is run, the transaction will appear on the Ledger device and will require physical confirmation from the device before being signed.
|
||||
|
||||
## Nym-specific transactions
|
||||
Nym-specific commands and queries, like bonding a Mix Node or delegating unvested tokens, are available in the `wasm` module, and follow the following pattern:
|
||||
Nym-specific commands and queries, like bonding a mix node or delegating unvested tokens, are available in the `wasm` module, and follow the following pattern:
|
||||
|
||||
```
|
||||
# Executing commands
|
||||
@@ -59,8 +59,8 @@ You can find the value of `$CONTRACT_ADDRESS` in the [`network defaults`](https:
|
||||
The value of `$JSON_MSG` will be a blog of `json` formatted as defined for each command and query. You can find these definitions for the mixnet smart contract [here](https://github.com/nymtech/nym/blob/master/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs) and for the vesting contract [here](https://github.com/nymtech/nym/blob/master/common/cosmwasm-smart-contracts/vesting-contract/src/messages.rs) under `ExecuteMsg` and `QueryMsg`.
|
||||
|
||||
### Example command execution:
|
||||
#### Delegate to a Mix Node
|
||||
You can delegate to a Mix Node from the CLI using `nyxd` and signing the transaction with your ledger by filling in the values of this example:
|
||||
#### Delegate to a mix node
|
||||
You can delegate to a mix node from the CLI using `nyxd` and signing the transaction with your ledger by filling in the values of this example:
|
||||
```
|
||||
CONTRACT_ADDRESS=mixnet_contract_address
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ Before you can use the client, you need to initalise a new instance of it, which
|
||||
|
||||
The `--id` in the example above is a local identifier so that you can name your clients and keep track of them on your local system; it is **never** transmitted over the network.
|
||||
|
||||
The `--use-reply-surbs` field denotes whether you wish to send [SURBs](/network/mixnet-mode/anonymous-replies) along with your request. It defaults to `false`, we are explicitly setting it as `true`. It defaults to `false` for compatibility with versions of the pre-smoosh `nym-network-requester` binary which will soon be deprecated.
|
||||
The `--use-reply-surbs` field denotes whether you wish to send [SURBs](/network/concepts/anonymous-replies) along with your request. It defaults to `false`, we are explicitly setting it as `true`. It defaults to `false` for compatibility with versions of the pre-smoosh `nym-network-requester` binary which will soon be deprecated.
|
||||
|
||||
The `--provider` field needs to be filled with the Nym address of an Exit Gateway that can make network requests on your behalf. You can select one from the [mixnet explorer](https://nym.com/explorer) by copying its `Client ID` and using this as the value of the `--provider` flag. Alternatively, you could use [Harbourmaster](https://harbourmaster.nymtech.net/).
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ Here is an example of setting the proxy connecting in Blockstream Green:
|
||||
|
||||

|
||||
|
||||
Most wallets and other applications work the same way: find the network proxy settings and enter the proxy url (host: **localhost**, port: **1080**).
|
||||
Most wallets and other applications will work basically the same way: find the network proxy settings, enter the proxy url (host: **localhost**, port: **1080**).
|
||||
|
||||
In some other applications, this might be written as **localhost:1080** if there's only one proxy entry field.
|
||||
|
||||
|
||||
@@ -1,52 +1,13 @@
|
||||
# WebSocket Client (Standalone)
|
||||
# Websocket Client (Standalone)
|
||||
|
||||
> This client can also be used via the [Rust SDK](../rust) and [Go/C++ FFI](../rust/ffi).
|
||||
> This client can also be utilised via the [Rust SDK](../rust) and [Go/C++ FFI](../rust/ffi).
|
||||
|
||||
The standalone WebSocket client connects to the Nym Mixnet and exposes a WebSocket interface on localhost, allowing applications in any language to send and receive messages through the Mixnet.
|
||||
You can run this client as a standalone process and pipe traffic into it to be sent through the mixnet. This is useful if you're building an application in a language other than Typescript or Rust and cannot utilise one of the SDKs.
|
||||
|
||||
This is useful if you're building an application in a language other than TypeScript or Rust and cannot use one of the SDKs directly. Your application connects to the local WebSocket, and the client handles Sphinx packet construction, gateway registration, and key management.
|
||||
You can find the code for this client [here](https://github.com/nymtech/nym/tree/master/clients/native).
|
||||
|
||||
## Download or compile
|
||||
## Download or compile client
|
||||
|
||||
Pre-built binaries for macOS and Debian-based Linux are available on the [GitHub releases page](https://github.com/nymtech/nym/releases). Look for the `nym-client` binary.
|
||||
If you are using OSX or a Debian-based operating system, you can download the `nym-socks5-client` binary from our [Github releases page](https://github.com/nymtech/nym/releases).
|
||||
|
||||
To build from source:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/nymtech/nym.git
|
||||
cd nym
|
||||
cargo build --release -p nym-client
|
||||
```
|
||||
|
||||
The binary will be at `target/release/nym-client`.
|
||||
|
||||
## Initialize and run
|
||||
|
||||
```bash
|
||||
# Create a new client identity
|
||||
./nym-client init --id my-client
|
||||
|
||||
# Start the client
|
||||
./nym-client run --id my-client
|
||||
```
|
||||
|
||||
The client prints its Nym address on startup and opens a WebSocket on `ws://127.0.0.1:1977`.
|
||||
|
||||
## Sending and receiving
|
||||
|
||||
Connect to `ws://127.0.0.1:1977` from your application. Messages are JSON-formatted:
|
||||
|
||||
**Send a message:**
|
||||
```json
|
||||
{
|
||||
"type": "send",
|
||||
"message": "hello",
|
||||
"recipient": "<recipient-nym-address>"
|
||||
}
|
||||
```
|
||||
|
||||
**Receive messages:** The client pushes incoming messages to your WebSocket connection as they arrive through the Mixnet.
|
||||
|
||||
## Source code
|
||||
|
||||
The client source is in the [Nym monorepo](https://github.com/nymtech/nym/tree/master/clients/native).
|
||||
If you are using a different operating system, or want to build from source, simply use `cargo build --release` from the root of the Nym monorepo.
|
||||
|
||||
@@ -13,5 +13,5 @@ All of these code examples will do the following:
|
||||
By varying the message content, you can easily build sophisticated service provider apps. For example, instead of printing the response received from the mixnet, your service provider might take some action on behalf of the user - perhaps initiating a network request, a blockchain transaction, or writing to a local data store.
|
||||
|
||||
<!-- THIS PAGE IS NOT WORKING AT THE MOMENT:
|
||||
> You can find an example of building both frontend and service provider code with the websocket client in the [Simple Service Provider Tutorial](https://nym.com/developers/tutorials/simple-service-provider/simple-service-provider.html) in the Developer Portal.
|
||||
> You can find an example of building both frontend and service provider code with the websocket client in the [Simple Service Provider Tutorial](https://nymtech.net/developers/tutorials/simple-service-provider/simple-service-provider.html) in the Developer Portal.
|
||||
-->
|
||||
|
||||
@@ -54,7 +54,7 @@ In some applications, e.g. where people are chatting with friends who they know,
|
||||
|
||||
**If that fits your security model, good. However, will probably be the case that you want to send anonymous replies using Single Use Reply Blocks (SURBs)**.
|
||||
|
||||
You can read more about SURBs [here](/network/mixnet-mode/anonymous-replies) but in short they are ways for the receiver of this message to anonymously reply to you - the sender - **without them having to know your client address**.
|
||||
You can read more about SURBs [here](/network/concepts/anonymous-replies) but in short they are ways for the receiver of this message to anonymously reply to you - the sender - **without them having to know your client address**.
|
||||
|
||||
Your client will send along a number of `replySurbs` to the recipient of the message. These are pre-addressed Sphinx packets that the recipient can write to the payload of (i.e. write response data to), but not view the final destination of. If the recipient is unable to fit the response data into the bucket of SURBs sent to it, it will use a SURB to request more SURBs be sent to it from your client.
|
||||
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
---
|
||||
title: "Nym Client Message Queue and Cover Traffic"
|
||||
description: "How the Nym client queues messages, sends cover traffic via Poisson processes, and manages Sphinx packet streams to prevent timing attacks."
|
||||
schemaType: "TechArticle"
|
||||
section: "Developers"
|
||||
lastUpdated: "2026-03-15"
|
||||
---
|
||||
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
# Message Queue
|
||||
|
||||
<Callout type="info">
|
||||
Although useful for understanding how the Nym Client works internally, this information is only of practical use if you are using the [`Mixnet`](../rust/mixnet) module of the Rust SDK and interacting with the client at a low level. Most of this is abstracted away by the [`Stream`](../rust/stream) module (`AsyncRead + AsyncWrite` channels) and the [`TcpProxy`](../rust/tcpproxy) module (TCP tunnelling with message ordering).
|
||||
Although good to understand how the Nym Client works under the hood, this information is only of practical use if you're using the `Mixnet` module of the RustSDK and interacting with the SDK Mixnet Client at a low level. This is all mostly abstracted away with the `MixSocket`, `MixStream`, and `IpMixStream` abstractions.
|
||||
</Callout>
|
||||
|
||||
## Sphinx Packet Streams
|
||||
Clients, once connected to the Mixnet, **are always sending traffic into the Mixnet**; as well as the packets that you as a developer are sending from your application logic, they send [cover traffic](/network/mixnet-mode/cover-traffic) at a constant rate defined by a Poisson process. This is part of the network's mitigation of timing attacks.
|
||||
Clients, once connected to the Mixnet, **are always sending traffic into the Mixnet**; as well as the packets that you as a developer are sending from your application logic, they send [cover traffic](../../network/concepts/cover-traffic) at a constant rate defined by a Poisson process. This is part of the network's mitigation of timing attacks.
|
||||
|
||||
There are two constant streams of sphinx packets leaving the client at the rate defined by the Poisson process.
|
||||
- one that is solely cover traffic
|
||||
|
||||
@@ -6,22 +6,5 @@ section: "Developers"
|
||||
lastUpdated: "2026-02-01"
|
||||
---
|
||||
|
||||
# Developer Documentation
|
||||
|
||||
Build applications that protect user metadata using the Nym Mixnet. This section covers SDK integration, blockchain interaction, and developer tools.
|
||||
|
||||
## Where to start
|
||||
|
||||
**Choosing an integration approach:** read [Integrations](/developers/integrations) to understand the architectural trade-offs (native SDK vs proxy vs mixFetch), then pick your path:
|
||||
|
||||
- **[Rust SDK](/developers/rust):** full-featured SDK with message passing, `AsyncRead`/`AsyncWrite` streams, and client pooling. Start with the [Tour](/developers/rust/tour).
|
||||
- **[TypeScript SDK](/developers/typescript):** browser and Node.js SDK for mixFetch, Mixnet client, and smart contract interaction.
|
||||
- **[Standalone Clients](/developers/clients):** language-agnostic SOCKS5 and WebSocket proxies for piping traffic through the Mixnet without an SDK.
|
||||
|
||||
## Blockchain interaction
|
||||
|
||||
The Nym Network is coordinated by the [Nyx blockchain](/network/infrastructure/nyx). To query chain state, submit transactions, or interact with smart contracts, see [Chain Interaction](/developers/chain).
|
||||
|
||||
## API reference
|
||||
|
||||
Auto-generated API specs for Nym infrastructure endpoints are in the [APIs section](/apis/introduction).
|
||||
# Introduction
|
||||
Nym's developer documentation covering core concepts of integrating with the Mixnet, interacting with the Nyx blockchain, an overview of the avaliable tools, and our SDK docs.
|
||||
|
||||
@@ -1,34 +1,16 @@
|
||||
---
|
||||
title: "Integrating With Nym"
|
||||
description: "Choose an integration path for sending application traffic through the Nym mixnet, depending on your runtime environment and architecture."
|
||||
schemaType: "TechArticle"
|
||||
section: "Developers"
|
||||
lastUpdated: "2026-04-07"
|
||||
---
|
||||
|
||||
import { Callout } from 'nextra/components';
|
||||
|
||||
# Integrating With Nym
|
||||
Any application that wants to integrate with Nym involves sending its application traffic through the Mixnet using one of the available Nym Clients. There is no single solution for this, as different environments offer different access and transport options (e.g. if operating in a web browser, you do not have access to syscalls or sockets, have to deal with content security policies, etc).
|
||||
|
||||
Any application that integrates with Nym sends its traffic through the Mixnet via a Nym client. The right integration path depends on two factors: **environment** and **architecture**.
|
||||
As such, we have several solutions available for developers to choose from depending on the **environment** their application is expected to run in: native apps which are running on a desktop, or webapps running in a browser.
|
||||
|
||||
## Environment
|
||||
|
||||
Different runtimes have different transport constraints: a browser cannot open raw sockets or access the filesystem, while a desktop app can.
|
||||
|
||||
- **Native / Desktop**: full access to system networking and persistent storage. Use the [Rust SDK](./rust).
|
||||
- **Browser**: restricted to WebSockets, Web Transport, and `fetch`, with HTTPS-only mixed content rules and no filesystem access. Use the [TypeScript SDK](./typescript).
|
||||
|
||||
## Architecture
|
||||
|
||||
The second factor is whether you control both sides of the communication.
|
||||
|
||||
**End-to-end (E2E)**: both sides run Nym clients. All traffic stays Sphinx-encrypted the entire way. Appropriate for peer-to-peer setups or any case where you control both endpoints.
|
||||
|
||||
**Proxy**: only the client side runs Nym. Traffic exits the Mixnet at an Exit Gateway and continues to the destination as normal internet traffic. Appropriate when connecting to third-party services (blockchain RPCs, external APIs) that you do not control.
|
||||
|
||||
<Callout type="warning">
|
||||
In proxy mode, the last hop from Exit Gateway to the remote host travels as standard internet traffic. This is weaker than E2E against a global passive adversary, but still provides timing obfuscation and sender-receiver unlinkability.
|
||||
<Callout type="info" emoji="ℹ️">
|
||||
The list of current options available to developers to do not cover all environments and setups - we are working on expanding this list and approaching more general solutions, but there is no one-size-fits-all approach when dealing with rerouting network traffic.
|
||||
</Callout>
|
||||
|
||||
See the [Native / Desktop](./native) and [Browser](./browsers) pages for the specific modules available in each environment.
|
||||
Integration options are then further subdivided by app **architecture**; whether the application interacts with remote hosts on the public internet running independently of the app (e.g. public blockchain RPC endpoints, third-party APIs) or whether app developers have some control over the versions of the software being run on both sides of an interaction (e.g. peer to peer apps running the same software version, or client-server architectures which are running software written by the same team).
|
||||
|
||||
<Callout type="info" emoji="ℹ️">
|
||||
This is because of the different security considerations each option offers. These are detailed in the following pages.
|
||||
</Callout>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Licensing
|
||||
|
||||
As a general approach, licensing follows this pattern:
|
||||
As a general approach, licensing is as follows this pattern:
|
||||
|
||||
* [Nym Documentation](https://nym.com/docs) by [Nym Technologies](https://nym.com) is licensed under [CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)    
|
||||
* <p xmlns:cc="http://creativecommons.org/ns#" xmlns:dct="http://purl.org/dc/terms/"><a property="dct:title" rel="cc:attributionURL" href="https://nym.com/docs">Nym Documentation</a> by <a rel="cc:attributionURL dct:creator" property="cc:attributionName" href="https://nym.com">Nym Technologies</a> is licensed under <a href="http://creativecommons.org/licenses/by-nc-sa/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">CC BY-NC-SA 4.0<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/nc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/sa.svg?ref=chooser-v1"></a></p>
|
||||
|
||||
* Nym applications and binaries are [GPL-3.0-only](https://www.gnu.org/licenses/)
|
||||
|
||||
|
||||
@@ -1,63 +1,86 @@
|
||||
---
|
||||
title: "Native and Desktop App Integration"
|
||||
description: "Integrate privacy into native desktop apps and CLIs using the Nym Rust SDK. Choose between end-to-end mixnet messaging or TCP proxy approaches."
|
||||
schemaType: "TechArticle"
|
||||
section: "Developers"
|
||||
lastUpdated: "2026-03-15"
|
||||
---
|
||||
|
||||
import { Callout } from 'nextra/components';
|
||||
|
||||
# Native / Desktop Apps
|
||||
|
||||
Desktop apps and CLIs integrate via the [Rust SDK](./rust), with two broad approaches: embedding Nym clients on both sides of the communication (E2E), or using the Mixnet as a proxy to reach external services.
|
||||
Developers wanting to integrate into desktop apps & CLIs can use our Rust SDK. There are two broad approaches to using the Mixnet (E2E or as a proxy), with different modules suited for each, each with their own specific usecase and limitations.
|
||||
|
||||
## Option 1: Mixnet End-To-End
|
||||
Both sides of your app run Nym clients. All traffic stays Sphinx-encrypted the entire way. Works for peer-to-peer setups or any case where you control both ends.
|
||||
You might want to embed Nym Clients in both sides of your app, and have them send all of your app network traffic through the Mixnet: maybe two clients in a peer to peer setup, or a client and a server where it is possible for you as a developer to release both the client and server side code, and have some ability to make sure that it is being run.
|
||||
|
||||

|
||||
|
||||
### Stream Module
|
||||
The [Stream module](./rust/stream) provides `AsyncRead + AsyncWrite` byte streams multiplexed over the mixnet, the closest analogue to TCP sockets.
|
||||
There are several options available:
|
||||
|
||||
- [docs](./rust/stream)
|
||||
- [tutorial](./rust/stream/tutorial)
|
||||
{ /* ### Stream Wrapper Module
|
||||
Exposes `MixSocket`/`MixStream` abstractions that can be split a reader/writer halves that consumes bytes, with an interface inspired by `std::net::TcpStream`. For developers who just want to read/write bytes to/from the Mixnet working with something socket-like.
|
||||
|
||||
- docs TODO LINK
|
||||
- example TODO LINK */ }
|
||||
|
||||
### Mixnet & Client Pool Modules
|
||||
The [Mixnet module](./rust/mixnet) exposes the raw message API and `MixnetClient`. The [Client Pool](./rust/client-pool) maintains pre-connected clients for bursty workloads. These are appropriate when you need full control over the communication model.
|
||||
The Mixnet module of the SDK exposes low level connection functionality and the Mixnet Client. The Client Pool is one answer to concurrency, and allows developers to run several Nym Clients at once which can be quickly used.
|
||||
|
||||
{ /* This approach might be useful if you want to build custom connection logic, but **`MixSocket`/`MixStream` will probably be sufficient for the majority of usecases** where developers just want to send and receive traffic as streams. */ }
|
||||
|
||||
This approach might be useful if you want to build custom connection logic, but the TcpProxy Module will probably be sufficient for the majority of usecases where developers just want to send and receive traffic as streams.
|
||||
|
||||
- [docs](./rust/mixnet)
|
||||
- [tutorial](./rust/mixnet/tutorial)
|
||||
- [examples](./rust/mixnet/examples)
|
||||
|
||||
### TcpProxy Module (Unmaintained)
|
||||
|
||||
<Callout type="error">
|
||||
**This module is unmaintained.** Use the [Stream module](./rust/stream) for new projects. Existing users should plan to migrate when possible.
|
||||
</Callout>
|
||||
|
||||
Exposes localhost TCP sockets that proxy traffic through the mixnet.
|
||||
### TcpProxy Module
|
||||
{ /* <Callout type="warning" emoji="⚠️">
|
||||
This module has been superseded by the Stream Wrapper module, and will soon be deprecated. **New features will not be added to it.** The main drawback of this (which is fixed with `MixSocket`/`MixStream`) is that TLS is impossible, as it exposes a localhost port for the consuming process to communicate with.
|
||||
</Callout> */ }
|
||||
A pair of abstractions built for use in a client-server setup, which both expose a `localhost` TCP Socket which apps can read/write bytes to/from.
|
||||
|
||||
- [docs](./rust/tcpproxy)
|
||||
- [examples](./rust/tcpproxy/examples/singleconn)
|
||||
|
||||
<Callout type="info" emoji="ℹ️">
|
||||
There is a new abstraction coming soon mirroring the interface and use of a TCP Socket, making it easier for developers to use the Mixnet, and also perform TLS through a Mixnet connection. Stay tuned.
|
||||
</Callout>
|
||||
|
||||
## Option 2: Mixnet-As-Proxy
|
||||
For cases where you only control the client side and need to reach a third-party service such as a blockchain RPC or remote API.
|
||||
For developers who are only able to control the client-side code, and/or need to communicate with a 3rd party service, such as a public blockchain RPC or a remote host they do not control.
|
||||
|
||||

|
||||
|
||||
<Callout type="warning">
|
||||
|
||||
### Security Considerations
|
||||
### Security Considerations
|
||||
|
||||
Traffic is Sphinx-encrypted until the Exit Gateway, where it's unwrapped into HTTPS (Network Requester) or raw IP (IP Packet Router). The last hop to the remote host **travels as normal internet traffic**.
|
||||
Since traffic is only packaged as Sphinx until it gets to the Exit Gateway, where it is unwrapped into either HTTPS packets (by a Network Requester) or IP packets (by an IP Packet Router), the last hop between the Gateway and the remote host **travels as normal internet traffic**.
|
||||
|
||||
Weaker than E2E against a global passive adversary, but you still get timing obfuscation and sender-receiver unlinkability between your client and the remote service.
|
||||
As such, this option has fewer protections than the E2E option against a global passive adversary, but still grants you timing obfuscation and sender-receiver unlinkability between your client software and whatever service it is interacting with.
|
||||
</Callout>
|
||||
|
||||
### SOCKS Client
|
||||
Applications that support SOCKS4, 4a, or 5 can use the Socks Client exposed by the Mixnet module. Traffic is routed through the Exit Gateway's Network Requester, which uses SURBs to reply to the sender anonymously.
|
||||
Developers with apps that support SOCKS4,4a, or 5 can use the Socks Client exposed by the Mixnet module. This uses the Network Requester service of the chosen Exit Gateway to interact with the remote host via the chosen SOCKS proxy protocol. The Network Requester uses SURBs to anonymously reply to the original sender with whatever response it gets from the remote host.
|
||||
|
||||
- [docs](./rust/mixnet)
|
||||
- [docs](./rust/mixnet/examples/socks)
|
||||
- [example](./rust/mixnet/examples/socks)
|
||||
|
||||
<Callout type="info">
|
||||
Development is in progress to allow for this proxy method from native Rust, C, and Go without requiring a separate SOCKS client. Stay tuned.
|
||||
<Callout type="info" emoji="ℹ️">
|
||||
There is a new abstraction coming soon that will allow the SDK to send IP packets, the beginning of a longer project to make a native Rust version of [`mixFetch`](./typescript/start#mixfetch). Stay tuned.
|
||||
</Callout>
|
||||
|
||||
|
||||
{ /* ### `IPMixStream`
|
||||
This is a version of the `MixSocket` that consumes IP packets before wrapping them in Sphinx and forwarding through the Mixnet to the IP Packet Router of the chosen Exit Gateway, where they are unwrapped and treated as normal IP packets. The IPR uses SURBs to anonymously reply to the original sender with whatever response it gets from the remote host.
|
||||
|
||||
<Callout type="info" emoji="ℹ️">
|
||||
Currently only consumes IP packets - those who do not want to work with IP packets directly should check `mixtcp` below for doing something with HTTP(S).
|
||||
</Callout>
|
||||
|
||||
- docs TODO LINK
|
||||
- examples TODO LINK
|
||||
|
||||
### `MixTCP`
|
||||
A proof of concept TCP/IP crate containing a [`smoltcp`](https://docs.rs/smoltcp/latest/smoltcp/index.html) `device` that uses the Mixnet for transport. Examples of using this to make a TLS handshake and perform an HTTPS request can be found linked below.
|
||||
|
||||
<Callout type="info" emoji="ℹ️">
|
||||
This crate is currently a proof of concept which is in active development. This crate will become the basis of a general-purpose HTTP-through-Mixnet crate in the near future.
|
||||
</Callout>
|
||||
|
||||
- docs TODO LINK
|
||||
- example TODO LINK */ }
|
||||
|
||||
@@ -173,13 +173,13 @@ Print current tunnel configuration:
|
||||
nym-vpnc tunnel get
|
||||
```
|
||||
|
||||
Enable two-hop mode (WireGuard): traffic jumps directly from entry gateway to exit gateway:
|
||||
Enable two-hop mode (WireGuard) — traffic jumps directly from entry gateway to exit gateway:
|
||||
|
||||
```sh
|
||||
nym-vpnc tunnel set --two-hop on
|
||||
```
|
||||
|
||||
Enable Mixnet (5-hop): disable two-hop to route traffic through the full mixnet for maximum privacy:
|
||||
Enable Mixnet (5-hop) — disable two-hop to route traffic through the full mixnet for maximum privacy:
|
||||
|
||||
```sh
|
||||
nym-vpnc tunnel set --two-hop off
|
||||
@@ -293,7 +293,7 @@ nym-vpnc ad-block set disabled
|
||||
```
|
||||
|
||||
<Callout type="info">
|
||||
You can test ad-blocking with [adblock.turtlecute.org](https://adblock.turtlecute.org/). Some browsers cache DNS internally, so toggling ad-block on/off at runtime may not have an immediate effect; a browser restart may be needed. Use `nslookup` or `dig` to verify that domains are being blocked.
|
||||
You can test ad-blocking with [adblock.turtlecute.org](https://adblock.turtlecute.org/). Some browsers cache DNS internally, so toggling ad-block on/off at runtime may not have an immediate effect — a browser restart may be needed. Use `nslookup` or `dig` to verify that domains are being blocked.
|
||||
</Callout>
|
||||
|
||||
## DNS
|
||||
|
||||
@@ -1,34 +1,11 @@
|
||||
---
|
||||
title: "Nym Rust SDK: Privacy Apps for the Mixnet"
|
||||
description: "Rust SDK reference for building privacy applications on the Nym mixnet. Covers the Mixnet client, Stream multiplexing, Client Pool, and code examples."
|
||||
description: "Rust SDK reference for building privacy applications on the Nym mixnet. Covers TcpProxy, Mixnet module, Client Pool, FFI bindings, and code examples."
|
||||
schemaType: "TechArticle"
|
||||
section: "Developers"
|
||||
lastUpdated: "2026-03-13"
|
||||
lastUpdated: "2026-02-01"
|
||||
---
|
||||
|
||||
# Rust SDK
|
||||
# Introduction
|
||||
|
||||
import { Callout } from 'nextra/components'
|
||||
import { CratesPaused } from '../../components/crates-paused'
|
||||
|
||||
All modules share a common `MixnetClient` that manages gateway connections, Sphinx packet encryption, routing, and cover traffic.
|
||||
|
||||
<Callout type="info">
|
||||
Full API reference: [**docs.rs/nym-sdk**](https://docs.rs/nym-sdk/latest/nym_sdk/)
|
||||
</Callout>
|
||||
|
||||
<CratesPaused />
|
||||
|
||||
For an overview of what the SDK can do, see the **[Tour](./rust/tour)**. For setup instructions, see [Installation](./rust/importing).
|
||||
|
||||
## Modules
|
||||
|
||||
- **[Stream](./rust/stream)**: multiplexed `AsyncRead + AsyncWrite` byte streams over the Mixnet. **If you're used to TCP sockets, start here.**
|
||||
|
||||
- **[Mixnet](./rust/mixnet)**: raw message payloads, independently routed, no connections or ordering. Use this when you want full control over the communication model.
|
||||
|
||||
- **[Client Pool](./rust/client-pool)**: keeps ready-to-use `MixnetClient` instances warm for bursty workloads.
|
||||
|
||||
- **[TcpProxy](./rust/tcpproxy)** *(deprecated)*: TCP socket proxying with session management and message ordering. Use Stream for new projects.
|
||||
|
||||
- **[FFI](./rust/ffi)**: Go and C/C++ bindings.
|
||||
The Rust SDK allows exposes a few different modules, some more plug and play than others. Each of which handles exposes a Nym Client, which handles finding and using a route for packets through the Mixnet, encryption, and cover traffic, all under the hood.
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
{
|
||||
"tour": "Tour",
|
||||
"importing": "Installation",
|
||||
"importing": "Importing",
|
||||
"tcpproxy": "TcpProxy Module",
|
||||
"mixnet": "Mixnet Module",
|
||||
"stream": "Stream Module",
|
||||
"tcpproxy": "TcpProxy Module (Deprecated)",
|
||||
"client-pool": "Client Pool Module",
|
||||
"ffi": "FFI"
|
||||
}
|
||||
|
||||
@@ -1,73 +1,9 @@
|
||||
---
|
||||
title: "Client Pool: Pre-Connected Mixnet Clients"
|
||||
description: "The Nym ClientPool maintains ready-to-use MixnetClient instances, eliminating connection latency for bursty traffic patterns."
|
||||
schemaType: "TechArticle"
|
||||
section: "Developers"
|
||||
lastUpdated: "2026-03-15"
|
||||
---
|
||||
|
||||
# Client Pool
|
||||
|
||||
import { Callout } from 'nextra/components'
|
||||
import { Callout } from 'nextra/components';
|
||||
|
||||
The `ClientPool` maintains a configurable number of connected ephemeral `MixnetClient` instances, ready for immediate use. This eliminates the connection latency that comes with creating a new client on each request: the gateway handshake, key generation, and topology fetch all happen ahead of time.
|
||||
We have a configurable-size Client Pool for processes that require multiple clients in quick succession (this is used by default by the [`TcpProxyClient`](./tcpproxy) for instance)
|
||||
|
||||
## How it works
|
||||
This will be useful for developers looking to build connection logic, or just are using raw SDK clients in a sitatuation where there are multiple connections with a lot of churn.
|
||||
|
||||
```mermaid
|
||||
---
|
||||
config:
|
||||
theme: neo-dark
|
||||
---
|
||||
flowchart LR
|
||||
BG["Background loop"] -->|creates clients| P["Pool (Vec)"]
|
||||
P -->|"get_mixnet_client()"| APP["Your application"]
|
||||
APP -->|uses and disconnects| D["Done"]
|
||||
BG -->|"pool < reserve? create another"| P
|
||||
```
|
||||
|
||||
1. **Create** the pool with a target reserve size: `ClientPool::new(5)`
|
||||
2. **Start** the background loop: `pool.start()`. It immediately begins connecting clients
|
||||
3. **Pop** a client when needed: `pool.get_mixnet_client()` returns `Some(client)` or `None` if the pool is empty
|
||||
4. **Use** the client normally: send messages, open streams, etc.
|
||||
5. **Disconnect** the client when done. The background loop notices the pool is below reserve and creates a replacement
|
||||
|
||||
Clients are **consumed, not returned**. The pool creates new ones to maintain the reserve. If the pool is empty, you can fall back to `MixnetClient::connect_new()` (slower, but keeps things working).
|
||||
|
||||
<Callout type="info">
|
||||
The `NymProxyClient` (TcpProxy) uses a `ClientPool` internally: one client per incoming TCP connection.
|
||||
</Callout>
|
||||
|
||||
## Quick example
|
||||
|
||||
```rust
|
||||
use nym_sdk::client_pool::ClientPool;
|
||||
use nym_network_defaults::setup_env;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
nym_bin_common::logging::setup_tracing_logger();
|
||||
// Load mainnet network defaults into env vars (required by ClientPool)
|
||||
setup_env(None::<String>);
|
||||
|
||||
let pool = ClientPool::new(5); // maintain 5 clients in reserve
|
||||
|
||||
let pool_clone = pool.clone();
|
||||
tokio::spawn(async move { pool_clone.start().await });
|
||||
|
||||
// Get a client when needed
|
||||
if let Some(client) = pool.get_mixnet_client().await {
|
||||
println!("Got client: {}", client.nym_address());
|
||||
client.disconnect().await;
|
||||
}
|
||||
|
||||
pool.disconnect_pool().await;
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
## Further reading
|
||||
|
||||
- [Tutorial: Handle bursty traffic](./client-pool/tutorial): step-by-step guide covering pool creation, burst handling, and fallback logic
|
||||
- [API reference on docs.rs](https://docs.rs/nym-sdk/latest/nym_sdk/client_pool/): type details, method signatures, and architecture docs
|
||||
- [Example source on GitHub](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/client_pool.rs): complete working example
|
||||
> You can find this code [here](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/client_pool.rs)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"tutorial": "Tutorial",
|
||||
"examples": "Examples"
|
||||
"architecture": "Architecture",
|
||||
"example": "Example"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# Client Pool Architecture
|
||||
|
||||
|
||||
import { Callout } from 'nextra/components';
|
||||
|
||||
<Callout type="warning">
|
||||
There will be a breaking SDK upgrade in the coming months. This upgrade will make the SDK a lot easier to build with.
|
||||
|
||||
This upgrade will affect the interface of the SDK dramatically, and will be coupled with a protocol change - stay tuned for information on early access to the new protocol testnet.
|
||||
|
||||
It will also be coupled with the documentation of the SDK on [crates.io](https://crates.io/).
|
||||
</Callout>
|
||||
|
||||
|
||||
## Motivations
|
||||
In situations where multiple connections are expected, and the number of connections can vary greatly, the Client Pool reduces time spent waiting for the creation of a Mixnet Client blocking your code sending traffic through the Mixnet. Instead, a configurable number of Clients can be generated and run in the background which can be very quickly grabbed, used, and disconnected.
|
||||
|
||||
The Pool can be simply run as a background process for the runtime of your program.
|
||||
|
||||
## Clients & Lifetimes
|
||||
The Client Pool creates **ephemeral Mixnet Clients** which are used and then disconnected. Using the [`TcpProxy`](../tcpproxy) as an example, Clients are used for the lifetime of a single incoming TCP connection; after the TCP connection is closed, the Mixnet client is disconnected.
|
||||
|
||||
Clients are popped from the pool when in use, and another Client is created to take its place. If connections are coming in faster than Clients are replenished, you can instead generate an ephemeral Client on the fly, or wait; this is up to the developer to decide. You can see an example of this logic in the example on the next page.
|
||||
|
||||
## Runtime Loop
|
||||
Aside from a few helper / getter functions and a graceful `disconnect_pool()`, the Client Pool is mostly made up of a very simple loop around some conditional logic making up `start()`:
|
||||
- if the number of Clients in the pool is `< client_pool_reserve_number` (set on `new()`) then create more,
|
||||
- if the number of Clients in the pool `== client_pool_reserve_number` (set on `new()`) then `sleep`,
|
||||
- if `client_pool_reserve_number == 0` just `sleep`.
|
||||
|
||||
`disconnect_pool()` will cause this loop to `break` via cancellation token.
|
||||
@@ -0,0 +1,110 @@
|
||||
# Client Pool Example
|
||||
|
||||
import { Callout } from 'nextra/components';
|
||||
|
||||
<Callout type="warning">
|
||||
There will be a breaking SDK upgrade in the coming months. This upgrade will make the SDK a lot easier to build with.
|
||||
|
||||
This upgrade will affect the interface of the SDK dramatically, and will be coupled with a protocol change - stay tuned for information on early access to the new protocol testnet.
|
||||
|
||||
It will also be coupled with the documentation of the SDK on [crates.io](https://crates.io/).
|
||||
</Callout>
|
||||
|
||||
> You can find this code [here](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/client_pool.rs)
|
||||
|
||||
```rust
|
||||
use anyhow::Result;
|
||||
use nym_network_defaults::setup_env;
|
||||
use nym_sdk::client_pool::ClientPool;
|
||||
use nym_sdk::mixnet::{MixnetClientBuilder, NymNetworkDetails};
|
||||
use tokio::signal::ctrl_c;
|
||||
|
||||
// This client pool is used internally by the TcpProxyClient but can also be used by the Mixnet module, in case you're quickly swapping clients in and out but won't want to use the TcpProxy module.
|
||||
//
|
||||
// Run with: cargo run --example client_pool -- ../../../envs/<NETWORK>.env
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
nym_bin_common::logging::setup_logging();
|
||||
setup_env(std::env::args().nth(1));
|
||||
|
||||
let conn_pool = ClientPool::new(2); // Start the Client Pool with 2 Clients always being kept in reserve
|
||||
let client_maker = conn_pool.clone();
|
||||
tokio::spawn(async move {
|
||||
client_maker.start().await?;
|
||||
Ok::<(), anyhow::Error>(())
|
||||
});
|
||||
|
||||
println!("\n\nWaiting a few seconds to fill pool\n\n");
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
|
||||
|
||||
let pool_clone_one = conn_pool.clone();
|
||||
let pool_clone_two = conn_pool.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let client_one = match pool_clone_one.get_mixnet_client().await {
|
||||
Some(client) => {
|
||||
println!("Grabbed client {} from pool", client.nym_address());
|
||||
client
|
||||
}
|
||||
None => {
|
||||
println!("Not enough clients in pool, creating ephemeral client");
|
||||
let net = NymNetworkDetails::new_from_env();
|
||||
let client = MixnetClientBuilder::new_ephemeral()
|
||||
.network_details(net)
|
||||
.build()?
|
||||
.connect_to_mixnet()
|
||||
.await?;
|
||||
println!(
|
||||
"Using {} for the moment, created outside of the connection pool",
|
||||
client.nym_address()
|
||||
);
|
||||
client
|
||||
}
|
||||
};
|
||||
let our_address = client_one.nym_address();
|
||||
println!("\n\nClient 1: {our_address}\n\n");
|
||||
client_one.disconnect().await;
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await; // Emulate doing something
|
||||
return Ok::<(), anyhow::Error>(());
|
||||
});
|
||||
|
||||
tokio::spawn(async move {
|
||||
let client_two = match pool_clone_two.get_mixnet_client().await {
|
||||
Some(client) => {
|
||||
println!("Grabbed client {} from pool", client.nym_address());
|
||||
client
|
||||
}
|
||||
None => {
|
||||
println!("Not enough clients in pool, creating ephemeral client");
|
||||
let net = NymNetworkDetails::new_from_env();
|
||||
let client = MixnetClientBuilder::new_ephemeral()
|
||||
.network_details(net)
|
||||
.build()?
|
||||
.connect_to_mixnet()
|
||||
.await?;
|
||||
println!(
|
||||
"Using {} for the moment, created outside of the connection pool",
|
||||
client.nym_address()
|
||||
);
|
||||
client
|
||||
}
|
||||
};
|
||||
let our_address = *client_two.nym_address();
|
||||
println!("\n\nClient 2: {our_address}\n\n");
|
||||
client_two.disconnect().await;
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await; // Emulate doing something
|
||||
return Ok::<(), anyhow::Error>(());
|
||||
});
|
||||
|
||||
wait_for_ctrl_c(conn_pool).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn wait_for_ctrl_c(pool: ClientPool) -> Result<()> {
|
||||
println!("\n\nPress CTRL_C to disconnect pool\n\n");
|
||||
ctrl_c().await?;
|
||||
println!("CTRL_C received. Killing client pool");
|
||||
pool.disconnect_pool().await;
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
@@ -1,19 +0,0 @@
|
||||
---
|
||||
title: "Client Pool Examples"
|
||||
description: "Runnable Rust example for the Nym Client Pool: managing multiple MixnetClients with ephemeral fallback."
|
||||
schemaType: "TechArticle"
|
||||
section: "Developers"
|
||||
lastUpdated: "2026-03-26"
|
||||
---
|
||||
|
||||
# Examples
|
||||
|
||||
Runnable examples in [`sdk/rust/nym-sdk/examples/`](https://github.com/nymtech/nym/tree/develop/sdk/rust/nym-sdk/examples). Each file is self-contained with step-by-step comments.
|
||||
|
||||
```bash
|
||||
cargo run --example <name>
|
||||
```
|
||||
|
||||
| Example | Source | What it demonstrates |
|
||||
|---|---|---|
|
||||
| Client Pool | [`client_pool.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/client_pool.rs) | Creating a pool of `MixnetClient`s, retrieving clients from the pool, and falling back to ephemeral clients when the pool is empty |
|
||||
@@ -1,277 +0,0 @@
|
||||
---
|
||||
title: "Client Pool Tutorial: Handle Bursty Traffic"
|
||||
description: "Step-by-step Rust tutorial to use Nym ClientPool for handling bursts of concurrent mixnet operations without blocking on client creation."
|
||||
schemaType: "HowTo"
|
||||
section: "Developers"
|
||||
lastUpdated: "2026-03-26"
|
||||
---
|
||||
|
||||
# Tutorial: Handle Bursty Traffic with Client Pool
|
||||
|
||||
import { Callout } from 'nextra/components'
|
||||
import { CodeVerified } from '../../../../components/code-verified'
|
||||
|
||||
In this tutorial you'll build a program that uses `ClientPool` to handle bursts of concurrent Mixnet operations without blocking on client creation. You'll see how the pool pre-creates clients in the background, how to pop them under load, and what happens when demand exceeds supply.
|
||||
|
||||
## What you'll learn
|
||||
|
||||
- Creating and starting a `ClientPool`
|
||||
- Popping clients from the pool for concurrent operations
|
||||
- Falling back to on-demand client creation when the pool is empty
|
||||
- Observing pool replenishment
|
||||
- Graceful shutdown
|
||||
|
||||
<CodeVerified />
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Rust toolchain (1.70+)
|
||||
- A working internet connection
|
||||
|
||||
## Step 1: Set up the project
|
||||
|
||||
```sh
|
||||
cargo init nym-pool-demo
|
||||
cd nym-pool-demo
|
||||
```
|
||||
|
||||
Add dependencies to `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
nym-sdk = { git = "https://github.com/nymtech/nym", rev = "97068b2" }
|
||||
nym-network-defaults = { git = "https://github.com/nymtech/nym", rev = "97068b2" }
|
||||
nym-bin-common = { git = "https://github.com/nymtech/nym", rev = "97068b2", features = ["basic_tracing"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
blake3 = "=1.7.0" # required pin — see https://nymtech.net/docs/developers/rust/importing
|
||||
```
|
||||
|
||||
## Step 2: Create and start the pool
|
||||
|
||||
The pool is created with a **reserve size**: the number of connected clients it tries to maintain at all times. The `start()` method runs a background loop that creates clients whenever the pool drops below the reserve.
|
||||
|
||||
Create `src/main.rs`:
|
||||
|
||||
```rust
|
||||
use nym_sdk::client_pool::ClientPool;
|
||||
use nym_sdk::mixnet::MixnetMessageSender;
|
||||
use nym_network_defaults::setup_env;
|
||||
use std::time::Duration;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
nym_bin_common::logging::setup_tracing_logger();
|
||||
|
||||
// Load mainnet network defaults into env vars (required by ClientPool)
|
||||
setup_env(None::<String>);
|
||||
|
||||
// Create a pool that maintains 3 clients in reserve
|
||||
let pool = ClientPool::new(3);
|
||||
|
||||
// Start the pool in a background task.
|
||||
// It immediately begins connecting clients.
|
||||
let pool_bg = pool.clone();
|
||||
tokio::spawn(async move {
|
||||
pool_bg.start().await.unwrap();
|
||||
});
|
||||
|
||||
println!("Pool started — waiting for clients to connect...");
|
||||
tokio::time::sleep(Duration::from_secs(15)).await;
|
||||
|
||||
// Check how many are ready
|
||||
let count = pool.get_client_count().await;
|
||||
println!("Pool has {count} clients ready");
|
||||
```
|
||||
|
||||
<Callout type="info">
|
||||
Creating a `MixnetClient` takes several seconds (gateway handshake, key generation, topology fetch). The pool does this work ahead of time so your application doesn't block when it needs a client.
|
||||
</Callout>
|
||||
|
||||
## Step 3: Pop clients and use them
|
||||
|
||||
When you call `get_mixnet_client()`, the pool removes a client and returns it. The background loop notices the shortfall and starts creating a replacement.
|
||||
|
||||
```rust
|
||||
// Simulate a burst of 3 concurrent tasks, each needing a client
|
||||
let mut handles = vec![];
|
||||
|
||||
for i in 1..=3 {
|
||||
let pool = pool.clone();
|
||||
|
||||
let handle = tokio::spawn(async move {
|
||||
// Pop a client from the pool
|
||||
let mut client = match pool.get_mixnet_client().await {
|
||||
Some(c) => {
|
||||
println!("Task {i}: got client {} from pool", c.nym_address());
|
||||
c
|
||||
}
|
||||
None => {
|
||||
// Pool is empty — fall back to creating one on the fly.
|
||||
// This is slower but keeps things working.
|
||||
println!("Task {i}: pool empty, creating client on the fly...");
|
||||
nym_sdk::mixnet::MixnetClient::connect_new().await.unwrap()
|
||||
}
|
||||
};
|
||||
|
||||
// Do something with the client — here, send a message to ourselves
|
||||
let addr = *client.nym_address();
|
||||
client
|
||||
.send_plain_message(addr, format!("hello from task {i}"))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Wait for the message to arrive
|
||||
if let Some(msgs) = client.wait_for_messages().await {
|
||||
for msg in msgs {
|
||||
if !msg.message.is_empty() {
|
||||
println!(
|
||||
"Task {i}: received {:?}",
|
||||
String::from_utf8_lossy(&msg.message)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Disconnect when done — the pool will create a replacement
|
||||
client.disconnect().await;
|
||||
println!("Task {i}: done");
|
||||
});
|
||||
|
||||
handles.push(handle);
|
||||
}
|
||||
|
||||
// Wait for all tasks to finish
|
||||
for h in handles {
|
||||
h.await.unwrap();
|
||||
}
|
||||
```
|
||||
|
||||
## Step 4: Observe replenishment
|
||||
|
||||
After popping all 3 clients, the pool background loop starts creating replacements. Give it time and check:
|
||||
|
||||
```rust
|
||||
// Pool should be replenishing
|
||||
println!("\nWaiting for pool to replenish...");
|
||||
tokio::time::sleep(Duration::from_secs(15)).await;
|
||||
|
||||
let count = pool.get_client_count().await;
|
||||
println!("Pool has {count} clients ready again");
|
||||
```
|
||||
|
||||
## Step 5: Shut down gracefully
|
||||
|
||||
```rust
|
||||
// Disconnect all remaining clients and stop the background loop
|
||||
pool.disconnect_pool().await;
|
||||
println!("Pool shut down");
|
||||
}
|
||||
```
|
||||
|
||||
## Step 6: Run it
|
||||
|
||||
```sh
|
||||
RUST_LOG=info cargo run
|
||||
```
|
||||
|
||||
You'll see output like:
|
||||
|
||||
```
|
||||
Pool started — waiting for clients to connect...
|
||||
Pool has 3 clients ready
|
||||
Task 1: got client 8gk4Y...@2xU4d... from pool
|
||||
Task 2: got client F3qR7...@9nK2m... from pool
|
||||
Task 3: got client A7bN2...@4pL8w... from pool
|
||||
Task 1: received "hello from task 1"
|
||||
Task 2: received "hello from task 2"
|
||||
Task 3: received "hello from task 3"
|
||||
Task 1: done
|
||||
Task 2: done
|
||||
Task 3: done
|
||||
|
||||
Waiting for pool to replenish...
|
||||
Pool has 3 clients ready again
|
||||
Pool shut down
|
||||
```
|
||||
|
||||
## When to use the pool
|
||||
|
||||
The pool is most useful when:
|
||||
|
||||
- **You have bursty traffic:** many concurrent operations that each need their own client
|
||||
- **Latency matters:** you can't afford the several-second delay of creating a client on each request
|
||||
- **You're building a service:** an API endpoint that creates a client per request would benefit from pre-warmed clients
|
||||
|
||||
If your application only ever needs one client at a time, just use `MixnetClient::connect_new()` directly.
|
||||
|
||||
<Callout type="info">
|
||||
The `NymProxyClient` (TcpProxy module) uses a `ClientPool` internally: one client per incoming TCP connection.
|
||||
</Callout>
|
||||
|
||||
## What you've learned
|
||||
|
||||
- **`ClientPool::new(n)`** creates a pool targeting `n` reserve clients
|
||||
- **`pool.start()`** runs a background loop that creates clients whenever the pool is below reserve
|
||||
- **`pool.get_mixnet_client()`** pops a client; returns `None` if the pool is empty
|
||||
- **Clients are consumed, not returned.** The pool automatically creates replacements
|
||||
- **`pool.disconnect_pool()`** shuts down all remaining clients and stops the background loop
|
||||
- **Fall back to on-demand creation** when the pool is empty for resilience
|
||||
|
||||
## Complete code
|
||||
|
||||
```rust
|
||||
use nym_sdk::client_pool::ClientPool;
|
||||
use nym_sdk::mixnet::MixnetMessageSender;
|
||||
use nym_network_defaults::setup_env;
|
||||
use std::time::Duration;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
nym_bin_common::logging::setup_tracing_logger();
|
||||
setup_env(None::<String>);
|
||||
|
||||
let pool = ClientPool::new(3);
|
||||
let pool_bg = pool.clone();
|
||||
tokio::spawn(async move { pool_bg.start().await.unwrap() });
|
||||
|
||||
println!("Waiting for pool to fill...");
|
||||
tokio::time::sleep(Duration::from_secs(15)).await;
|
||||
println!("Pool has {} clients", pool.get_client_count().await);
|
||||
|
||||
let mut handles = vec![];
|
||||
for i in 1..=3 {
|
||||
let pool = pool.clone();
|
||||
handles.push(tokio::spawn(async move {
|
||||
let mut client = match pool.get_mixnet_client().await {
|
||||
Some(c) => c,
|
||||
None => nym_sdk::mixnet::MixnetClient::connect_new().await.unwrap(),
|
||||
};
|
||||
|
||||
let addr = *client.nym_address();
|
||||
client
|
||||
.send_plain_message(addr, format!("hello from task {i}"))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
if let Some(msgs) = client.wait_for_messages().await {
|
||||
for msg in msgs.iter().filter(|m| !m.message.is_empty()) {
|
||||
println!("Task {i}: {}", String::from_utf8_lossy(&msg.message));
|
||||
}
|
||||
}
|
||||
|
||||
client.disconnect().await;
|
||||
}));
|
||||
}
|
||||
|
||||
for h in handles {
|
||||
h.await.unwrap();
|
||||
}
|
||||
|
||||
println!("Waiting for replenishment...");
|
||||
tokio::time::sleep(Duration::from_secs(15)).await;
|
||||
println!("Pool has {} clients", pool.get_client_count().await);
|
||||
|
||||
pool.disconnect_pool().await;
|
||||
println!("Done");
|
||||
}
|
||||
```
|
||||
@@ -1,105 +1,59 @@
|
||||
---
|
||||
title: "FFI Bindings: Go and C/C++"
|
||||
description: "Use the Nym SDK from Go and C/C++ via FFI bindings. Covers mixnet messaging, anonymous replies, and TcpProxy lifecycle from non-Rust languages."
|
||||
schemaType: "TechArticle"
|
||||
section: "Developers"
|
||||
lastUpdated: "2026-03-15"
|
||||
---
|
||||
|
||||
# FFI Bindings
|
||||
import { Callout } from 'nextra/components';
|
||||
|
||||
import { Callout } from 'nextra/components'
|
||||
We currently have FFI bindings for Go and C/C++. See the table below to check the coverage of functionality we expect devs would like to see.
|
||||
|
||||
The SDK exposes FFI bindings for Go and C/C++. The source lives in [`sdk/ffi`](https://github.com/nymtech/nym/tree/develop/sdk/ffi):
|
||||
The [`nym/sdk/ffi`](https://github.com/nymtech/nym/tree/master/sdk/ffi) directory has the following structure:
|
||||
|
||||
```
|
||||
ffi
|
||||
├── cpp # C/C++ bindings (manual C FFI)
|
||||
├── go # Go bindings (via uniffi-bindgen-go)
|
||||
└── shared # Shared Rust implementation
|
||||
├── cpp
|
||||
├── go
|
||||
├── README.md
|
||||
└── shared
|
||||
```
|
||||
|
||||
Core logic lives in `shared/` and is imported into language-specific wrappers. The shared layer handles thread safety and ensures client operations run on blocking threads on the Rust side of the FFI boundary.
|
||||
The main functionality of exposed functions will be imported from `sdk/ffi/shared` into `sdk/ffi/<LANGUAGE>` in order to cut down on code duplication, and so that the imported bindings can be language-specific with regards to types and any `unsafe` code that is required, as well as allowing for the use of language-specific FFI libraries in the future (e.g. we are using `uniffi-bindgen-go` for Go, and at the moment have custom C/C++ bindings, which we might in the future replace with `cxx`).
|
||||
|
||||
## What's exposed
|
||||
Furthermore, the `shared/` code makes sure that client access is thread-safe, and that client actions happen in blocking threads on the Rust side of the FFI boundary.
|
||||
|
||||
**Mixnet** (Go and C/C++): ephemeral and persistent client creation, sending messages, anonymous replies via SURBs, listening for incoming messages.
|
||||
## Mixnet Module
|
||||
This is the basic mixnet component of the SDK, exposing client functionality with which people can build custom interfaces with the Mixnet. These functions are exposed to both Go and C/C++ via the `sdk/ffi/shared/` crate.
|
||||
|
||||
**TcpProxy** (Go only): client and server creation and lifecycle.
|
||||
| `shared/lib.rs` function | Rust Function |
|
||||
| ------------------------------------------------------------- | ----------------------------------------------------------------------- |
|
||||
| `init_ephemeral_internal()` | `MixnetClient::connect_new()` |
|
||||
| `init_default_storage_internal(config_dir: PathBuf)` | `MixnetClientBuilder::new_with_default_storage(config_dir)` |
|
||||
| `get_self_address_internal()` | `MixnetClient.nym_address()` |
|
||||
| `send_message_internal(recipient: Recipient, message: &str)` | `MixnetClient.send_plain_message(recipient, message)` |
|
||||
| `reply_internal(recipient: AnonymousSenderTag, message: &str)`| `MixnetClient.send_reply(recipient, message)` |
|
||||
|
||||
<Callout type="warning">
|
||||
The TcpProxy module is deprecated. For new projects, use the [Stream module](./stream) instead.
|
||||
|
||||
> We have also implemented `listen_for_incoming_internal()` which is a wrapper around the Mixnet client's `wait_for_messages()`. This is a helper method for listening out for and handling incoming messages.
|
||||
|
||||
### Currently Unsupported Functionality
|
||||
At the time of writing the following functionality is not exposed to the shared FFI library:
|
||||
- `split_sender()`: the ability to [split a client into sender and receiver](./mixnet/examples/split-send) for concurrent send/receive.
|
||||
- The use of [custom network topologies](./mixnet/examples/custom-topology).
|
||||
- `Socks5::new()`: creation and use of the [socks5/4a/4 proxy client](./mixnet/examples/socks).
|
||||
|
||||
## TcpProxy Module
|
||||
A connection abstraction which exposes a local TCP socket which developers are able to interact with basically as expected, being able to read/write to/from a bytestream, without really having to take into account the workings of the Mixnet/Sphinx/the message-based format of the underlying client.
|
||||
|
||||
<Callout type="info" emoji="ℹ️">
|
||||
At the time of writing this functionality is **only** exposed to Go. C/C++ bindings will follow in the future in a larger update to the C FFI.
|
||||
</Callout>
|
||||
|
||||
**Client Pool and Stream** have no standalone FFI bindings yet. The TcpProxy bindings use the Client Pool internally.
|
||||
|
||||
## Quick example (Go)
|
||||
| `shared/lib.rs` function | Rust Function |
|
||||
| --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
||||
| `proxy_client_new_internal(server_address: Recipient, listen_address: &str, listen_port: &str, close_timeout: u64, env: Option<String>)`| `NymProxyClient::new(server_address, listen_address, listen_port, close_timeout, env)`|
|
||||
| `proxy_client_new_defaults_internal(server_address, env)` | `NymProxyClient::new_with_defaults(server_address, env)` |
|
||||
| `proxy_client_run_internal()` | `NymProxyClient.run()` |
|
||||
| `proxy_server_new_internal(upstream_address: &str, config_dir: &str, env: Option<String>)` | `NymProxyServer::new(upstream_address, config_dir, env)` |
|
||||
| `proxy_server_run_internal()` | `NymProxyServer.run_with_shutdown()` |
|
||||
| `proxy_server_address_internal()` | `NymProxyServer.nym_address()` |
|
||||
|
||||
```go
|
||||
// Initialize an ephemeral client
|
||||
bindings.InitEphemeral()
|
||||
|
||||
// Get our Nym address
|
||||
addr, _ := bindings.GetSelfAddress()
|
||||
|
||||
// Send a message through the Mixnet
|
||||
bindings.SendMessage(addr, "hello from Go")
|
||||
|
||||
// Listen for incoming messages
|
||||
msg, _ := bindings.ListenForIncoming()
|
||||
fmt.Println("Received:", msg.Message)
|
||||
|
||||
// Reply anonymously via SURBs
|
||||
bindings.Reply(msg.Sender, "reply from Go")
|
||||
```
|
||||
|
||||
## Quick example (C++)
|
||||
|
||||
The C++ bindings use callbacks for return values and a `ReceivedMessage` struct for incoming data:
|
||||
|
||||
```cpp
|
||||
extern "C" {
|
||||
struct ReceivedMessage {
|
||||
const uint8_t* message;
|
||||
size_t size;
|
||||
const char* sender_tag;
|
||||
};
|
||||
|
||||
void init_logging();
|
||||
char init_ephemeral();
|
||||
char get_self_address(void (*callback)(const char*));
|
||||
char send_message(const char*, const char*);
|
||||
char listen_for_incoming(void (*callback)(ReceivedMessage));
|
||||
char reply(const char*, const char*);
|
||||
}
|
||||
|
||||
// Get address via callback
|
||||
char addr[134];
|
||||
void on_address(const char* s) { strcpy(addr, s); }
|
||||
|
||||
// Receive message via callback
|
||||
char sender_tag[22];
|
||||
void on_message(ReceivedMessage msg) {
|
||||
std::cout << "Received: " << msg.message << std::endl;
|
||||
strcpy(sender_tag, msg.sender_tag);
|
||||
}
|
||||
|
||||
int main() {
|
||||
init_ephemeral();
|
||||
get_self_address(on_address);
|
||||
send_message(addr, "hello from C++");
|
||||
listen_for_incoming(on_message);
|
||||
reply(sender_tag, "reply from C++");
|
||||
}
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
Each language has a `build.sh` script that compiles the Rust shared library and generates bindings. See the README in each directory for prerequisites.
|
||||
|
||||
## Examples and source
|
||||
|
||||
- [Go mixnet example](https://github.com/nymtech/nym/blob/develop/sdk/ffi/go/example.go): init, send, receive, SURB reply
|
||||
- [Go TcpProxy example](https://github.com/nymtech/nym/blob/develop/sdk/ffi/go/proxy_example.go): proxy client and server with TCP echo
|
||||
- [C++ example](https://github.com/nymtech/nym/blob/develop/sdk/ffi/cpp/src/main.cpp): same flow using Boost threads
|
||||
- [`sdk/ffi` source](https://github.com/nymtech/nym/tree/develop/sdk/ffi): full source and build scripts
|
||||
## Client Pool
|
||||
There are currently no FFI bindings for the Client Pool. This will be coming in the future. The bindings for the TcpProxy have been updated to be able to use the Client Pool under the hood, but the standalone Pool is not yet exposed to FFI.
|
||||
|
||||
@@ -1,51 +1,13 @@
|
||||
---
|
||||
title: "Install the Nym Rust SDK"
|
||||
description: "Add nym-sdk to your Rust project from Git or crates.io. Covers version requirements, minimum Rust version, and current feature gate status."
|
||||
schemaType: "TechArticle"
|
||||
section: "Developers"
|
||||
lastUpdated: "2026-03-27"
|
||||
---
|
||||
|
||||
# Installation
|
||||
|
||||
import { Callout } from 'nextra/components';
|
||||
import { CratesPaused } from '../../../components/crates-paused'
|
||||
|
||||
<CratesPaused />
|
||||
The `nym-sdk` crate is **not yet available via [crates.io](https://crates.io)**. As such, in order to import the crate you must specify the Nym monorepo in your `Cargo.toml` file. Since the `HEAD` of `master` is always the most recent release, we recommend developers use that for their imports, unless they have a reason to pull in a specific historic version of the code.
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
nym-sdk = { git = "https://github.com/nymtech/nym", rev = "97068b2" }
|
||||
blake3 = "=1.7.0" # pin to avoid a transitive dependency conflict — see note below
|
||||
```
|
||||
|
||||
<Callout type="warning">
|
||||
**Temporary pin required.** You must pin `blake3 = "=1.7.0"` in your `Cargo.toml` to avoid a build failure caused by a transitive `digest` version conflict. This will be resolved in a future SDK release.
|
||||
</Callout>
|
||||
|
||||
You can also track a branch if you want the latest changes:
|
||||
|
||||
```toml
|
||||
# development branch (latest changes, may be unstable)
|
||||
nym-sdk = { git = "https://github.com/nymtech/nym", branch = "develop" }
|
||||
|
||||
# latest stable release
|
||||
# importing HEAD of master branch
|
||||
nym-sdk = { git = "https://github.com/nymtech/nym", branch = "master" }
|
||||
# importing HEAD of the third release of 2023, codename 'kinder'
|
||||
nym-sdk = { git = "https://github.com/nymtech/nym", branch = "release/2023.3-kinder" }
|
||||
```
|
||||
|
||||
**Minimum Rust version:** 1.70+
|
||||
|
||||
### crates.io (older API only)
|
||||
|
||||
If you don't need the Stream module or other recent additions, you can still use the published crate:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
nym-sdk = "1.20.4"
|
||||
```
|
||||
|
||||
This version includes the Mixnet message API, Client Pool, and TcpProxy modules.
|
||||
|
||||
<Callout type="warning">
|
||||
**No feature gates yet.** Importing `nym-sdk` pulls in everything (mixnet, tcp_proxy, client_pool, etc.) and their full dependency trees. Cargo feature flags are planned.
|
||||
</Callout>
|
||||
Work will occur in the future to break the monorepo down into importable features, in order to reduce the number of dependencies imported by developers.
|
||||
|
||||
@@ -3,60 +3,12 @@ title: "Nym Rust SDK: Mixnet Messaging Module"
|
||||
description: "Use the Nym Rust SDK Mixnet module to send messages through the mixnet. Covers builder patterns, custom topologies, SOCKS proxy, and anonymous replies."
|
||||
schemaType: "TechArticle"
|
||||
section: "Developers"
|
||||
lastUpdated: "2026-03-13"
|
||||
lastUpdated: "2026-02-01"
|
||||
---
|
||||
|
||||
# Mixnet Module
|
||||
|
||||
import { Callout } from 'nextra/components';
|
||||
|
||||
The `mixnet` module is the core of the Nym SDK. It provides [`MixnetClient`](https://docs.rs/nym-sdk/latest/nym_sdk/mixnet/struct.MixnetClient.html) for connecting to the Nym Mixnet, sending messages through Sphinx packet encryption and 5-hop routing, and receiving reconstructed messages on the other side.
|
||||
This module exposes the logic of creating and interacting with clients and Mixnet messages. This is recommended for those wanting to either start playing around with the Mixnet and how it works, or build connection logic.
|
||||
|
||||
<Callout type="warning">
|
||||
Messages are individually routed through the Mixnet with no guaranteed ordering or persistent connections. If you want familiar socket-like I/O (`read`/`write`), use the [Stream module](./stream) instead. See the [Tour](./tour) for how the two approaches compare.
|
||||
</Callout>
|
||||
|
||||
## Two operating modes
|
||||
|
||||
The client operates in one of two mutually exclusive modes:
|
||||
|
||||
**Message mode** (default): send and receive raw message payloads:
|
||||
```rust
|
||||
use nym_sdk::mixnet::{self, MixnetMessageSender};
|
||||
|
||||
let mut client = mixnet::MixnetClient::connect_new().await.unwrap();
|
||||
|
||||
// Send a message
|
||||
client.send_plain_message(*client.nym_address(), "hello").await.unwrap();
|
||||
|
||||
// Receive messages
|
||||
if let Some(msgs) = client.wait_for_messages().await {
|
||||
for msg in msgs {
|
||||
println!("Got: {}", String::from_utf8_lossy(&msg.message));
|
||||
}
|
||||
}
|
||||
|
||||
client.disconnect().await;
|
||||
```
|
||||
|
||||
**Stream mode:** persistent `AsyncRead + AsyncWrite` channels. See the [Stream module](./stream) for details.
|
||||
|
||||
<Callout type="info">
|
||||
Stream mode is activated by calling `open_stream()` or `listener()`. Once active, message-mode methods return `Error::StreamModeActive`. This is a one-way transition.
|
||||
</Callout>
|
||||
|
||||
## API reference
|
||||
|
||||
- [API reference on docs.rs](https://docs.rs/nym-sdk/latest/nym_sdk/mixnet/): full architecture documentation, all types, builder methods, traits, and configuration options
|
||||
- [Examples on GitHub](https://github.com/nymtech/nym/tree/develop/sdk/rust/nym-sdk/examples): runnable examples covering simple send/receive, builder patterns, custom topologies, SOCKS proxy, anonymous replies, and more
|
||||
|
||||
Run any example with:
|
||||
```sh
|
||||
cargo run --example <example_name>
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
- [Tutorial: Send your first private message](./mixnet/tutorial): step-by-step guide covering sending, receiving, SURBs, and persistent identity
|
||||
- [Troubleshooting](./mixnet/troubleshooting): common issues with logging, empty messages, and client lifecycle
|
||||
- [Stream module](./stream): if you need persistent bidirectional byte channels
|
||||
> For developers wanting something more 'plug and play' we recommend the [`TcpProxy` module](./tcpproxy).
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"tutorial": "Tutorial",
|
||||
"examples": "Examples",
|
||||
"examples": "Basic Examples",
|
||||
"message-helpers": "Message Helpers",
|
||||
"message-types": "Message Types",
|
||||
"troubleshooting": "Troubleshooting"
|
||||
}
|
||||
|
||||
@@ -1,29 +1,19 @@
|
||||
---
|
||||
title: "Mixnet Module Examples"
|
||||
description: "Runnable Rust examples for the Nym mixnet module: sending messages, SURB anonymous replies, MixnetClientBuilder, persistent storage, and parallel send/receive."
|
||||
schemaType: "TechArticle"
|
||||
section: "Developers"
|
||||
lastUpdated: "2026-03-15"
|
||||
---
|
||||
|
||||
# Examples
|
||||
|
||||
Runnable examples in [`sdk/rust/nym-sdk/examples/`](https://github.com/nymtech/nym/tree/develop/sdk/rust/nym-sdk/examples). Each file is self-contained with step-by-step comments.
|
||||
import { Callout } from 'nextra/components';
|
||||
|
||||
```bash
|
||||
cargo run --example <NAME>
|
||||
<Callout type="warning">
|
||||
There will be a breaking SDK upgrade in the coming months. This upgrade will make the SDK a lot easier to build with.
|
||||
|
||||
This upgrade will affect the interface of the SDK dramatically, and will be coupled with a protocol change - stay tuned for information on early access to the new protocol testnet.
|
||||
|
||||
It will also be coupled with the documentation of the SDK on [crates.io](https://crates.io/).
|
||||
</Callout>
|
||||
|
||||
All the following examples can be found in the `nym-sdk` [examples directory](https://github.com/nymtech/nym/tree/master/sdk/rust/nym-sdk/examples) in the monorepo. Just navigate to `nym/sdk/rust/nym-sdk/examples/` and run the files from there with:
|
||||
|
||||
```sh
|
||||
cargo run --example <NAME_OF_FILE>
|
||||
```
|
||||
|
||||
| Example | Source | What it demonstrates |
|
||||
|---|---|---|
|
||||
| Simple | [`simple.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/simple.rs) | Send a message to yourself and print it |
|
||||
| SURB Reply | [`surb_reply.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/surb_reply.rs) | Anonymous replies using `AnonymousSenderTag` and `send_reply()` |
|
||||
| Builder | [`builder.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/builder.rs) | Using `MixnetClientBuilder` with ephemeral keys |
|
||||
| Builder with Storage | [`builder_with_storage.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/builder_with_storage.rs) | Persisting keys to disk with `StoragePaths` |
|
||||
| Parallel Send/Receive | [`parallel_sending_and_receiving.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/parallel_sending_and_receiving.rs) | Using `split_sender()` for concurrent tasks |
|
||||
| Sandbox Testnet | [`sandbox.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/sandbox.rs) | Connecting to the Sandbox testnet instead of mainnet |
|
||||
| Bandwidth Credential | [`bandwidth.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/bandwidth.rs) | Acquiring a bandwidth credential for paid mixnet access |
|
||||
| Custom Topology | [`custom_topology_provider.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/custom_topology_provider.rs) | Implementing the `TopologyProvider` trait to filter or customize node selection |
|
||||
| Overwrite Topology | [`manually_overwrite_topology.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/manually_overwrite_topology.rs) | Manually constructing a topology with hardcoded nodes |
|
||||
| Control Requests | [`control_requests.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/control_requests.rs) | Sending service provider control requests (health, version, binary info) |
|
||||
| Custom Storage | [`manually_handle_storage.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/manually_handle_storage.rs) | Implementing custom storage backends for keys, gateways, and credentials |
|
||||
If you wish to run these outside of the workspace - such as if you want to use one as the basis for your own project - then make sure to import the `sdk`, `tokio`, and `nym_bin_common` crates.
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"simple": "Simple Send",
|
||||
"builders": "Builder Patterns",
|
||||
"testnet": "Configurable Network",
|
||||
"custom-topology": "Custom Network Topologies",
|
||||
"split-send": "Concurrent Send & Receive",
|
||||
"socks": "Socks Proxy",
|
||||
"storage": "Manually Handle Storage",
|
||||
"surbs": "Anonymous Replies"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# Builder Patterns
|
||||
import { Callout } from 'nextra/components';
|
||||
|
||||
Since there are two ways of creating an SDK client - ephemeral and with-storage - then there are two ways of applying the Builder Pattern to client creation.
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"builder": "Ephemeral",
|
||||
"builder-with-storage": "With Storage"
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
# Mixnet Client Builder with Storage
|
||||
import { Callout } from 'nextra/components';
|
||||
|
||||
The previous example involves ephemeral keys - if we want to create and then maintain a client identity over time, our code becomes a little more complex as we need to create, store, and conditionally load these keys.
|
||||
|
||||
> You can find this code [here](https://github.com/nymtech/nym/blob/master/sdk/rust/nym-sdk/examples/builder_with_storage.rs).
|
||||
|
||||
```rust
|
||||
use nym_sdk::mixnet;
|
||||
use nym_sdk::mixnet::MixnetMessageSender;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
nym_bin_common::logging::setup_logging();
|
||||
|
||||
// Specify some config options
|
||||
let config_dir = PathBuf::from("/tmp/mixnet-client");
|
||||
let storage_paths = mixnet::StoragePaths::new_from_dir(&config_dir).unwrap();
|
||||
|
||||
// Create the client with a storage backend, and enable it by giving it some paths. If keys
|
||||
// exists at these paths, they will be loaded, otherwise they will be generated.
|
||||
let client = mixnet::MixnetClientBuilder::new_with_default_storage(storage_paths)
|
||||
.await
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
// Now we connect to the mixnet, using keys now stored in the paths provided.
|
||||
let mut client = client.connect_to_mixnet().await.unwrap();
|
||||
|
||||
// Be able to get our client address
|
||||
let our_address = client.nym_address();
|
||||
println!("Our client nym address is: {our_address}");
|
||||
|
||||
// Send a message throught the mixnet to ourselves
|
||||
client
|
||||
.send_plain_message(*our_address, "hello there")
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
println!("Waiting for message");
|
||||
if let Some(received) = client.wait_for_messages().await {
|
||||
for r in received {
|
||||
println!("Received: {}", String::from_utf8_lossy(&r.message));
|
||||
}
|
||||
}
|
||||
|
||||
client.disconnect().await;
|
||||
}
|
||||
```
|
||||
|
||||
As seen in the example above, the `mixnet::MixnetClientBuilder::new()` function handles checking for keys in a storage location, loading them if present, or creating them and storing them if not, making client key management very simple.
|
||||
|
||||
Assuming our client config is stored in `/tmp/mixnet-client`, the following files are generated:
|
||||
```
|
||||
$ tree /tmp/mixnet-client
|
||||
|
||||
mixnet-client
|
||||
├── ack_key.pem
|
||||
├── db.sqlite
|
||||
├── db.sqlite-shm
|
||||
├── db.sqlite-wal
|
||||
├── gateway_details.json
|
||||
├── gateway_shared.pem
|
||||
├── persistent_reply_store.sqlite
|
||||
├── private_encryption.pem
|
||||
├── private_identity.pem
|
||||
├── public_encryption.pem
|
||||
└── public_identity.pem
|
||||
|
||||
1 directory, 11 files
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
# Mixnet Client Builder
|
||||
import { Callout } from 'nextra/components';
|
||||
|
||||
You can spin up an ephemeral client like so. This client will not have a persistent identity and its keys will be dropped on restart. Since there is currently no way of reconnecting a client that has been disconnected after use, then treat disconnecting a client the same as dropping its keys entirely.
|
||||
|
||||
> You can find this code [here](https://github.com/nymtech/nym/blob/master/sdk/rust/nym-sdk/examples/builder.rs).
|
||||
|
||||
```rust
|
||||
use nym_sdk::mixnet;
|
||||
use nym_sdk::mixnet::MixnetMessageSender;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
nym_bin_common::logging::setup_logging();
|
||||
|
||||
// Create client builder, including ephemeral keys. The builder can be usable in the context
|
||||
// where you don't want to connect just yet.
|
||||
let client = mixnet::MixnetClientBuilder::new_ephemeral()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
// Now we connect to the mixnet, using ephemeral keys already created
|
||||
let mut client = client.connect_to_mixnet().await.unwrap();
|
||||
|
||||
// Be able to get our client address
|
||||
let our_address = client.nym_address();
|
||||
println!("Our client nym address is: {our_address}");
|
||||
|
||||
// Send a message through the mixnet to ourselves
|
||||
client
|
||||
.send_plain_message(*our_address, "hello there")
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
println!("Waiting for message");
|
||||
if let Some(received) = client.wait_for_messages().await {
|
||||
for r in received {
|
||||
println!("Received: {}", String::from_utf8_lossy(&r.message));
|
||||
}
|
||||
}
|
||||
|
||||
client.disconnect().await;
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# Importing and using a custom network topology
|
||||
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
<Callout type="warning" emoji="⚠️">
|
||||
These examples are **not** the same as using a configurable network: these functions define a subset of nodes to use on a given network, whereas the [testnet](./testnet) example is an example of switching to use a different network entirely. The two can be combined, but if you are looking for how to connect your client to a testnet, see the `testnet` file.
|
||||
</Callout>
|
||||
|
||||
If you want to send traffic through a sub-set of nodes (for instance, ones you control, or a small test setup) when developing, debugging, or performing research, you will need to import these nodes as a custom network topology, instead of grabbing it from the [`Mainnet Nym-API`](https://validator.nymtech.net/api/swagger/index.html).
|
||||
|
||||
There are two ways to do this:
|
||||
|
||||
## Custom Topology Provider
|
||||
If you are also running a Validator and Nym API for your network, you can specify that endpoint. Clients will then use this endpoint to grab a network topology on startup. You can also use this to specify using a testnet.
|
||||
|
||||
## Import a specific topology manually
|
||||
If you aren't running a Validator and Nym API, and just want to import a specific sub-set of mix nodes, you can also overwrite the grabbed topology manually.
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"custom-provider": "Custom Topology Provider",
|
||||
"manual-topology": "Manually Overwrite Topology"
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
# Custom Topology Provider
|
||||
import { Callout } from 'nextra/components';
|
||||
|
||||
If you are also running a Validator and Nym API for your network, you can specify that endpoint as such and interact with it as clients usually do (under the hood).
|
||||
|
||||
> You can find this code [here](https://github.com/nymtech/nym/blob/master/sdk/rust/nym-sdk/examples/custom_topology_provider.rs)
|
||||
|
||||
```rust
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_sdk::mixnet;
|
||||
use nym_sdk::mixnet::MixnetMessageSender;
|
||||
use nym_topology::provider_trait::{async_trait, TopologyProvider};
|
||||
use nym_topology::{nym_topology_from_detailed, NymTopology};
|
||||
use nym_validator_client::nym_api::NymApiClientExt;
|
||||
use url::Url;
|
||||
|
||||
struct MyTopologyProvider {
|
||||
validator_client: nym_http_api_client::Client,
|
||||
}
|
||||
|
||||
impl MyTopologyProvider {
|
||||
fn new(nym_api_url: Url) -> MyTopologyProvider {
|
||||
let validator_client = nym_http_api_client::Client::builder::<_, nym_validator_client::models::RequestError>(nym_api_url)
|
||||
.expect("Failed to create API client builder")
|
||||
.build::<nym_validator_client::models::RequestError>()
|
||||
.expect("Failed to build API client");
|
||||
|
||||
MyTopologyProvider {
|
||||
validator_client,
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_topology(&self) -> NymTopology {
|
||||
let mixnodes = self
|
||||
.validator_client
|
||||
.get_cached_active_mixnodes()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// in our topology provider only use mixnodes that have mix_id divisible by 3
|
||||
// and have more than 100k nym (i.e. 100'000'000'000 unym) in stake
|
||||
// why? because this is just an example to showcase arbitrary uses and capabilities of this trait
|
||||
let filtered_mixnodes = mixnodes
|
||||
.into_iter()
|
||||
.filter(|mix| {
|
||||
mix.mix_id() % 3 == 0 && mix.total_stake() > "100000000000".parse().unwrap()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let gateways = self.validator_client.get_cached_gateways().await.unwrap();
|
||||
|
||||
nym_topology_from_detailed(filtered_mixnodes, gateways)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl TopologyProvider for MyTopologyProvider {
|
||||
// this will be manually refreshed on a timer specified inside mixnet client config
|
||||
async fn get_new_topology(&mut self) -> Option<NymTopology> {
|
||||
Some(self.get_topology().await)
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
nym_bin_common::logging::setup_logging();
|
||||
|
||||
let nym_api = "https://validator.nymtech.net/api/".parse().unwrap();
|
||||
let my_topology_provider = MyTopologyProvider::new(nym_api);
|
||||
|
||||
// Passing no config makes the client fire up an ephemeral session and figure things out on its own
|
||||
let mut client = mixnet::MixnetClientBuilder::new_ephemeral()
|
||||
.custom_topology_provider(Box::new(my_topology_provider))
|
||||
.build()
|
||||
.unwrap()
|
||||
.connect_to_mixnet()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let our_address = client.nym_address();
|
||||
println!("Our client nym address is: {our_address}");
|
||||
|
||||
// Send a message through the mixnet to ourselves
|
||||
client
|
||||
.send_plain_message(*our_address, "hello there")
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
println!("Waiting for message (ctrl-c to exit)");
|
||||
client
|
||||
.on_messages(|msg| println!("Received: {}", String::from_utf8_lossy(&msg.message)))
|
||||
.await;
|
||||
}
|
||||
```
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
# Manually Overwrite Topology
|
||||
import { Callout } from 'nextra/components';
|
||||
|
||||
If you aren't running a Validator and Nym API, and just want to import a specific sub-set of mix nodes, you can simply overwrite the grabbed topology manually.
|
||||
|
||||
> You can find this code [here](https://github.com/nymtech/nym/blob/master/sdk/rust/nym-sdk/examples/manually_overwrite_topology.rs)
|
||||
|
||||
```rust
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_sdk::mixnet;
|
||||
use nym_sdk::mixnet::MixnetMessageSender;
|
||||
use nym_topology::mix::Layer;
|
||||
use nym_topology::{mix, NymTopology};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
nym_bin_common::logging::setup_logging();
|
||||
|
||||
// Passing no config makes the client fire up an ephemeral session and figure shit out on its own
|
||||
let mut client = mixnet::MixnetClient::connect_new().await.unwrap();
|
||||
let starting_topology = client.read_current_topology().await.unwrap();
|
||||
|
||||
// but we don't like our default topology, we want to use only those very specific, hardcoded, nodes:
|
||||
let mut mixnodes = BTreeMap::new();
|
||||
mixnodes.insert(
|
||||
1,
|
||||
vec![mix::Node {
|
||||
mix_id: 63,
|
||||
owner: None,
|
||||
host: "172.105.92.48".parse().unwrap(),
|
||||
mix_host: "172.105.92.48:1789".parse().unwrap(),
|
||||
identity_key: "GLdR2NRVZBiCoCbv4fNqt9wUJZAnNjGXHkx3TjVAUzrK"
|
||||
.parse()
|
||||
.unwrap(),
|
||||
sphinx_key: "CBmYewWf43iarBq349KhbfYMc9ys2ebXWd4Vp4CLQ5Rq"
|
||||
.parse()
|
||||
.unwrap(),
|
||||
layer: Layer::One,
|
||||
version: "1.1.0".into(),
|
||||
}],
|
||||
);
|
||||
mixnodes.insert(
|
||||
2,
|
||||
vec![mix::Node {
|
||||
mix_id: 23,
|
||||
owner: None,
|
||||
host: "178.79.143.65".parse().unwrap(),
|
||||
mix_host: "178.79.143.65:1789".parse().unwrap(),
|
||||
identity_key: "4Yr4qmEHd9sgsuQ83191FR2hD88RfsbMmB4tzhhZWriz"
|
||||
.parse()
|
||||
.unwrap(),
|
||||
sphinx_key: "8ndjk5oZ6HxUZNScLJJ7hk39XtUqGexdKgW7hSX6kpWG"
|
||||
.parse()
|
||||
.unwrap(),
|
||||
layer: Layer::Two,
|
||||
version: "1.1.0".into(),
|
||||
}],
|
||||
);
|
||||
mixnodes.insert(
|
||||
3,
|
||||
vec![mix::Node {
|
||||
mix_id: 66,
|
||||
owner: None,
|
||||
host: "139.162.247.97".parse().unwrap(),
|
||||
mix_host: "139.162.247.97:1789".parse().unwrap(),
|
||||
identity_key: "66UngapebhJRni3Nj52EW1qcNsWYiuonjkWJzHFsmyYY"
|
||||
.parse()
|
||||
.unwrap(),
|
||||
sphinx_key: "7KyZh8Z8KxuVunqytAJ2eXFuZkCS7BLTZSzujHJZsGa2"
|
||||
.parse()
|
||||
.unwrap(),
|
||||
layer: Layer::Three,
|
||||
version: "1.1.0".into(),
|
||||
}],
|
||||
);
|
||||
|
||||
// but we like the available gateways, so keep using them!
|
||||
// (we like them because the author of this example is too lazy to use the same hardcoded gateway
|
||||
// during client initialisation to make sure we are able to send to ourselves : ) )
|
||||
let custom_topology = NymTopology::new(mixnodes, starting_topology.gateways().to_vec());
|
||||
|
||||
client.manually_overwrite_topology(custom_topology).await;
|
||||
|
||||
// and everything we send now should only ever go via those nodes
|
||||
|
||||
let our_address = client.nym_address();
|
||||
println!("Our client nym address is: {our_address}");
|
||||
|
||||
// Send a message through the mixnet to ourselves
|
||||
client
|
||||
.send_plain_message(*our_address, "hello there")
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
println!("Waiting for message (ctrl-c to exit)");
|
||||
client
|
||||
.on_messages(|msg| println!("Received: {}", String::from_utf8_lossy(&msg.message)))
|
||||
.await;
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,37 @@
|
||||
# Simple Send
|
||||
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
Lets look at a very simple example of how you can import and use the websocket client in a piece of Rust code.
|
||||
|
||||
Simply importing the `nym_sdk` crate into your project allows you to create a client and send traffic through the mixnet.
|
||||
|
||||
> You can find this code [here](https://github.com/nymtech/nym/blob/master/sdk/rust/nym-sdk/examples/simple.rs)
|
||||
|
||||
```rust
|
||||
use nym_sdk::mixnet;
|
||||
use nym_sdk::mixnet::MixnetMessageSender;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
nym_bin_common::logging::setup_logging();
|
||||
|
||||
// Passing no config makes the client fire up an ephemeral session and figure shit out on its own
|
||||
let mut client = mixnet::MixnetClient::connect_new().await.unwrap();
|
||||
|
||||
// Be able to get our client address
|
||||
let our_address = client.nym_address();
|
||||
println!("Our client nym address is: {our_address}");
|
||||
|
||||
// Send a message through the mixnet to ourselves
|
||||
client
|
||||
.send_plain_message(*our_address, "hello there")
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
println!("Waiting for message (ctrl-c to exit)");
|
||||
client
|
||||
.on_messages(|msg| println!("Received: {}", String::from_utf8_lossy(&msg.message)))
|
||||
.await;
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,50 @@
|
||||
# Socks Proxy
|
||||
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
If you are looking at implementing Nym as a transport layer for a crypto wallet or desktop app, this is probably the best place to start if they can speak SOCKS5, 4a, or 4.
|
||||
|
||||
> You can find this code [here](https://github.com/nymtech/nym/blob/master/sdk/rust/nym-sdk/examples/socks5.rs)
|
||||
|
||||
```rust
|
||||
use nym_sdk::mixnet;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
nym_bin_common::logging::setup_logging();
|
||||
|
||||
println!("Connecting receiver");
|
||||
let mut receiving_client = mixnet::MixnetClient::connect_new().await.unwrap();
|
||||
|
||||
let socks5_config = mixnet::Socks5::new(receiving_client.nym_address().to_string());
|
||||
let sending_client = mixnet::MixnetClientBuilder::new_ephemeral()
|
||||
.socks5_config(socks5_config)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
println!("Connecting sender");
|
||||
let sending_client = sending_client.connect_to_mixnet_via_socks5().await.unwrap();
|
||||
|
||||
let proxy = reqwest::Proxy::all(sending_client.socks5_url()).unwrap();
|
||||
let reqwest_client = reqwest::Client::builder().proxy(proxy).build().unwrap();
|
||||
tokio::spawn(async move {
|
||||
println!("Sending socks5-wrapped http request");
|
||||
// Message should be sent through the mixnet, via socks5
|
||||
// We don't expect to get anything, as there is no network requester on the other end
|
||||
reqwest_client.get("https://nym.com").send().await.ok()
|
||||
});
|
||||
|
||||
println!("Waiting for message");
|
||||
if let Some(received) = receiving_client.wait_for_messages().await {
|
||||
for r in received {
|
||||
println!(
|
||||
"Received socks5 message requesting for endpoint: {}",
|
||||
String::from_utf8_lossy(&r.message[10..27])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
receiving_client.disconnect().await;
|
||||
sending_client.disconnect().await;
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,52 @@
|
||||
# Send and Receive in Different Tasks
|
||||
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
If you need to split the different actions of your client across different tasks, you can do so like this. You can think of this analogously to spliting a Tcp Stream into read/write. This functionality is also useful for embedding a sending and receiving client into different tasks.
|
||||
|
||||
> You can find this code [here](https://github.com/nymtech/nym/blob/master/sdk/rust/nym-sdk/examples/parallel_sending_and_receiving.rs)
|
||||
|
||||
```rust
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use futures::StreamExt;
|
||||
use nym_sdk::mixnet;
|
||||
use nym_sdk::mixnet::MixnetMessageSender;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
nym_bin_common::logging::setup_logging();
|
||||
|
||||
// Passing no config makes the client fire up an ephemeral session and figure stuff out on its own
|
||||
let mut client = mixnet::MixnetClient::connect_new().await.unwrap();
|
||||
|
||||
// Be able to get our client address
|
||||
let our_address = *client.nym_address();
|
||||
println!("Our client nym address is: {our_address}");
|
||||
|
||||
let sender = client.split_sender();
|
||||
|
||||
// receiving task
|
||||
let receiving_task_handle = tokio::spawn(async move {
|
||||
if let Some(received) = client.next().await {
|
||||
println!("Received: {}", String::from_utf8_lossy(&received.message));
|
||||
}
|
||||
|
||||
client.disconnect().await;
|
||||
});
|
||||
|
||||
// sending task
|
||||
let sending_task_handle = tokio::spawn(async move {
|
||||
sender
|
||||
.send_plain_message(our_address, "hello from a different task!")
|
||||
.await
|
||||
.unwrap();
|
||||
});
|
||||
|
||||
// wait for both tasks to be done
|
||||
println!("waiting for shutdown");
|
||||
sending_task_handle.await.unwrap();
|
||||
receiving_task_handle.await.unwrap();
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,229 @@
|
||||
# Manually Handle Storage
|
||||
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
If you're integrating mixnet functionality into an existing app and want to integrate saving client configs and keys into your existing storage logic, you can manually perform these actions.
|
||||
|
||||
> You can find this code [here](https://github.com/nymtech/nym/blob/master/sdk/rust/nym-sdk/examples/manually_handle_storage.rs)
|
||||
|
||||
```rust
|
||||
use nym_sdk::mixnet::{
|
||||
self, ActiveGateway, BadGateway, ClientKeys, EmptyReplyStorage, EphemeralCredentialStorage,
|
||||
GatewayRegistration, GatewaysDetailsStore, KeyStore, MixnetClientStorage, MixnetMessageSender,
|
||||
};
|
||||
use nym_topology::provider_trait::async_trait;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
nym_bin_common::logging::setup_logging();
|
||||
|
||||
// Just some plain data to pretend we have some external storage that the application
|
||||
// implementer is using.
|
||||
let mock_storage = MockClientStorage::empty();
|
||||
let mut client = mixnet::MixnetClientBuilder::new_with_storage(mock_storage)
|
||||
.build()
|
||||
.unwrap()
|
||||
.connect_to_mixnet()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Be able to get our client address
|
||||
let our_address = client.nym_address();
|
||||
println!("Our client nym address is: {our_address}");
|
||||
|
||||
// Send important info up the pipe to a buddy
|
||||
client
|
||||
.send_plain_message(*our_address, "hello there")
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
println!("Waiting for message");
|
||||
if let Some(received) = client.wait_for_messages().await {
|
||||
for r in received {
|
||||
println!("Received: {}", String::from_utf8_lossy(&r.message));
|
||||
}
|
||||
}
|
||||
|
||||
client.disconnect().await;
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
struct MockClientStorage {
|
||||
pub key_store: MockKeyStore,
|
||||
pub gateway_details_store: MockGatewayDetailsStore,
|
||||
pub reply_store: EmptyReplyStorage,
|
||||
pub credential_store: EphemeralCredentialStorage,
|
||||
}
|
||||
|
||||
impl MockClientStorage {
|
||||
fn empty() -> Self {
|
||||
Self {
|
||||
key_store: MockKeyStore,
|
||||
gateway_details_store: MockGatewayDetailsStore,
|
||||
reply_store: EmptyReplyStorage::default(),
|
||||
credential_store: EphemeralCredentialStorage::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MixnetClientStorage for MockClientStorage {
|
||||
type KeyStore = MockKeyStore;
|
||||
type ReplyStore = EmptyReplyStorage;
|
||||
type CredentialStore = EphemeralCredentialStorage;
|
||||
type GatewaysDetailsStore = MockGatewayDetailsStore;
|
||||
|
||||
fn into_runtime_stores(self) -> (Self::ReplyStore, Self::CredentialStore) {
|
||||
(self.reply_store, self.credential_store)
|
||||
}
|
||||
|
||||
fn key_store(&self) -> &Self::KeyStore {
|
||||
&self.key_store
|
||||
}
|
||||
|
||||
fn reply_store(&self) -> &Self::ReplyStore {
|
||||
&self.reply_store
|
||||
}
|
||||
|
||||
fn credential_store(&self) -> &Self::CredentialStore {
|
||||
&self.credential_store
|
||||
}
|
||||
|
||||
fn gateway_details_store(&self) -> &Self::GatewaysDetailsStore {
|
||||
&self.gateway_details_store
|
||||
}
|
||||
}
|
||||
|
||||
struct MockKeyStore;
|
||||
|
||||
#[async_trait]
|
||||
impl KeyStore for MockKeyStore {
|
||||
type StorageError = MyError;
|
||||
|
||||
async fn load_keys(&self) -> Result<ClientKeys, Self::StorageError> {
|
||||
println!("loading stored keys");
|
||||
|
||||
Err(MyError)
|
||||
}
|
||||
|
||||
async fn store_keys(&self, _keys: &ClientKeys) -> Result<(), Self::StorageError> {
|
||||
println!("storing keys");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct MockGatewayDetailsStore;
|
||||
|
||||
#[async_trait]
|
||||
impl GatewaysDetailsStore for MockGatewayDetailsStore {
|
||||
type StorageError = MyError;
|
||||
|
||||
async fn active_gateway(&self) -> Result<ActiveGateway, Self::StorageError> {
|
||||
println!("getting active gateway");
|
||||
|
||||
Err(MyError)
|
||||
}
|
||||
|
||||
async fn set_active_gateway(&self, _gateway_id: &str) -> Result<(), Self::StorageError> {
|
||||
println!("setting active gateway");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn all_gateways(&self) -> Result<Vec<GatewayRegistration>, Self::StorageError> {
|
||||
println!("getting all registered gateways");
|
||||
|
||||
Err(MyError)
|
||||
}
|
||||
|
||||
async fn has_gateway_details(&self, _gateway_id: &str) -> Result<bool, Self::StorageError> {
|
||||
println!("checking for gateway details");
|
||||
|
||||
Err(MyError)
|
||||
}
|
||||
|
||||
async fn load_gateway_details(
|
||||
&self,
|
||||
_gateway_id: &str,
|
||||
) -> Result<GatewayRegistration, Self::StorageError> {
|
||||
println!("loading gateway details");
|
||||
|
||||
Err(MyError)
|
||||
}
|
||||
|
||||
async fn store_gateway_details(
|
||||
&self,
|
||||
_details: &GatewayRegistration,
|
||||
) -> Result<(), Self::StorageError> {
|
||||
println!("storing gateway details");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn remove_gateway_details(&self, _gateway_id: &str) -> Result<(), Self::StorageError> {
|
||||
println!("removing gateway details");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// struct MockReplyStore;
|
||||
//
|
||||
// #[async_trait]
|
||||
// impl ReplyStorageBackend for MockReplyStore {
|
||||
// type StorageError = MyError;
|
||||
//
|
||||
// async fn flush_surb_storage(
|
||||
// &mut self,
|
||||
// _storage: &CombinedReplyStorage,
|
||||
// ) -> Result<(), Self::StorageError> {
|
||||
// todo!()
|
||||
// }
|
||||
//
|
||||
// async fn init_fresh(&mut self, _fresh: &CombinedReplyStorage) -> Result<(), Self::StorageError> {
|
||||
// todo!()
|
||||
// }
|
||||
//
|
||||
// async fn load_surb_storage(&self) -> Result<CombinedReplyStorage, Self::StorageError> {
|
||||
// todo!()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// struct MockCredentialStore;
|
||||
//
|
||||
// #[async_trait]
|
||||
// impl CredentialStorage for MockCredentialStore {
|
||||
// type StorageError = MyError;
|
||||
//
|
||||
// async fn insert_coconut_credential(
|
||||
// &self,
|
||||
// _voucher_value: String,
|
||||
// _voucher_info: String,
|
||||
// _serial_number: String,
|
||||
// _binding_number: String,
|
||||
// _signature: String,
|
||||
// _epoch_id: String,
|
||||
// ) -> Result<(), Self::StorageError> {
|
||||
// todo!()
|
||||
// }
|
||||
//
|
||||
// async fn get_next_coconut_credential(&self) -> Result<CoconutCredential, Self::StorageError> {
|
||||
// todo!()
|
||||
// }
|
||||
//
|
||||
// async fn consume_coconut_credential(&self, id: i64) -> Result<(), Self::StorageError> {
|
||||
// todo!()
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
#[error("foobar")]
|
||||
struct MyError;
|
||||
|
||||
impl From<BadGateway> for MyError {
|
||||
fn from(_: BadGateway) -> Self {
|
||||
MyError
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,86 @@
|
||||
# Anonymous Replies with SURBs (Single Use Reply Blocks)
|
||||
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
Both functions used to send messages through the mixnet (`send_message` and `send_plain_message`) send a pre-determined number of SURBs along with their messages by default.
|
||||
|
||||
You can read more about how SURBs function under the hood [here](../../../../network/traffic/anonymous-replies).
|
||||
|
||||
In order to reply to an incoming message using SURBs, you can construct a `recipient` from the `sender_tag` sent along with the message you wish to reply to.
|
||||
|
||||
> You can find this code [here](https://github.com/nymtech/nym/blob/master/sdk/rust/nym-sdk/examples/surb_reply.rs)
|
||||
|
||||
```rust
|
||||
use nym_sdk::mixnet::{
|
||||
AnonymousSenderTag, MixnetClientBuilder, MixnetMessageSender, ReconstructedMessage,
|
||||
StoragePaths,
|
||||
};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
nym_bin_common::logging::setup_logging();
|
||||
|
||||
// Specify some config options
|
||||
let config_dir = PathBuf::from("/tmp/surb-example");
|
||||
let storage_paths = StoragePaths::new_from_dir(&config_dir).unwrap();
|
||||
|
||||
// Create the client with a storage backend, and enable it by giving it some paths. If keys
|
||||
// exists at these paths, they will be loaded, otherwise they will be generated.
|
||||
let client = MixnetClientBuilder::new_with_default_storage(storage_paths)
|
||||
.await
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
// Now we connect to the mixnet, using keys now stored in the paths provided.
|
||||
let mut client = client.connect_to_mixnet().await.unwrap();
|
||||
|
||||
// Be able to get our client address
|
||||
let our_address = client.nym_address();
|
||||
println!("\nOur client nym address is: {our_address}");
|
||||
|
||||
// Send a message through the mixnet to ourselves using our nym address
|
||||
client
|
||||
.send_plain_message(*our_address, "hello there")
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// we're going to parse the sender_tag (AnonymousSenderTag) from the incoming message and use it to 'reply' to ourselves instead of our Nym address.
|
||||
// we know there will be a sender_tag since the sdk sends SURBs along with messages by default.
|
||||
println!("Waiting for message\n");
|
||||
|
||||
// get the actual message - discard the empty vec sent along with a potential SURB topup request
|
||||
let mut message: Vec<ReconstructedMessage> = Vec::new();
|
||||
while let Some(new_message) = client.wait_for_messages().await {
|
||||
if new_message.is_empty() {
|
||||
continue;
|
||||
}
|
||||
message = new_message;
|
||||
break;
|
||||
}
|
||||
|
||||
let mut parsed = String::new();
|
||||
if let Some(r) = message.first() {
|
||||
parsed = String::from_utf8(r.message.clone()).unwrap();
|
||||
}
|
||||
// parse sender_tag: we will use this to reply to sender without needing their Nym address
|
||||
let return_recipient: AnonymousSenderTag = message[0].sender_tag.unwrap();
|
||||
println!(
|
||||
"\nReceived the following message: {} \nfrom sender with surb bucket {}",
|
||||
parsed, return_recipient
|
||||
);
|
||||
|
||||
// reply to self with it: note we use `send_str_reply` instead of `send_str`
|
||||
println!("Replying with using SURBs");
|
||||
client
|
||||
.send_reply(return_recipient, "hi an0n!")
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
println!("Waiting for message (once you see it, ctrl-c to exit)\n");
|
||||
client
|
||||
.on_messages(|msg| println!("\nReceived: {}", String::from_utf8_lossy(&msg.message)))
|
||||
.await;
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,46 @@
|
||||
# Configurable Network
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
|
||||
If you want to connect your Mixnet client to a different network than Mainnet, simply pull in a file from [`nym/envs`](https://github.com/nymtech/nym/tree/master/envs) as such:
|
||||
|
||||
```rust
|
||||
use futures::StreamExt;
|
||||
use nym_network_defaults::setup_env;
|
||||
use nym_sdk::mixnet;
|
||||
use nym_sdk::mixnet::MixnetMessageSender;
|
||||
|
||||
// An example of creating a client relying on a testnet, in this case Sandbox.
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
nym_bin_common::logging::setup_logging();
|
||||
// relative root is `sdk/rust/nym-sdk/` for fallback file path
|
||||
let env_path =
|
||||
std::env::var("NYM_ENV_PATH").unwrap_or_else(|_| "../../../envs/sandbox.env".to_string());
|
||||
setup_env(Some(&env_path));
|
||||
let sandbox_network = mixnet::NymNetworkDetails::new_from_env();
|
||||
|
||||
let mixnet_client = mixnet::MixnetClientBuilder::new_ephemeral()
|
||||
.network_details(sandbox_network)
|
||||
.build()?;
|
||||
|
||||
let mut client = mixnet_client.connect_to_mixnet().await?;
|
||||
|
||||
let our_address = client.nym_address();
|
||||
|
||||
// Send a message throughout the mixnet to ourselves
|
||||
client
|
||||
.send_plain_message(*our_address, "hello there")
|
||||
.await?;
|
||||
|
||||
println!("Waiting for message");
|
||||
if let Some(received) = client.next().await {
|
||||
println!("Received: {}", String::from_utf8_lossy(&received.message));
|
||||
} else {
|
||||
eprintln!("Failed to receive message.");
|
||||
}
|
||||
|
||||
client.disconnect().await;
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,75 @@
|
||||
# Message Helpers
|
||||
|
||||
import { Callout } from 'nextra/components';
|
||||
|
||||
<Callout type="warning">
|
||||
There will be a breaking SDK upgrade in the coming months. This upgrade will make the SDK a lot easier to build with.
|
||||
|
||||
This upgrade will affect the interface of the SDK dramatically, and will be coupled with a protocol change - stay tuned for information on early access to the new protocol testnet.
|
||||
|
||||
It will also be coupled with the documentation of the SDK on [crates.io](https://crates.io/).
|
||||
</Callout>
|
||||
|
||||
## Handling incoming messages
|
||||
When listening out for a response to a sent message (e.g. if you have sent a request to a service, and are awaiting the response) you will want to await [non-empty messages (if you don't know why, read the info on this here)](./troubleshooting#client-receives-empty-messages-when-listening-for-response). This can be done with something like the helper functions here:
|
||||
|
||||
```rust
|
||||
use nym_sdk::mixnet::ReconstructedMessage;
|
||||
|
||||
pub async fn wait_for_non_empty_message(
|
||||
client: &mut MixnetClient,
|
||||
) -> anyhow::Result<ReconstructedMessage> {
|
||||
while let Some(mut new_message) = client.wait_for_messages().await {
|
||||
if !new_message.is_empty() {
|
||||
return Ok(new_message.pop().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
bail!("did not receive any non-empty message")
|
||||
}
|
||||
|
||||
pub fn handle_response(message: ReconstructedMessage) -> anyhow::Result<ResponseTypes> {
|
||||
ResponseTypes::try_deserialize(message.message)
|
||||
}
|
||||
|
||||
// Note here that the only difference between handling a request and a response
|
||||
// is that a request will have a sender_tag to parse.
|
||||
//
|
||||
// This is used for anonymous replies with SURBs.
|
||||
pub fn handle_request(
|
||||
message: ReconstructedMessage,
|
||||
) -> anyhow::Result<(RequestTypes, Option<AnonymousSenderTag>)> {
|
||||
let request = RequestTypes::try_deserialize(message.message)?;
|
||||
Ok((request, message.sender_tag))
|
||||
}
|
||||
```
|
||||
|
||||
The above helper functions are used as such by the client in tutorial example: it sends a message to the service (what the message is isn't important - just that your client has sent a message _somewhere_ and you are awaiting a response), waits for a _non_empty_ message, then handles it (then logs it - but you can do whatever you want, parse it, etc):
|
||||
|
||||
```rust
|
||||
// Send serialised request to service via mixnet what is await-ed here is
|
||||
// placing the message in the client's message queue, NOT the sending itself.
|
||||
let _ = client
|
||||
.send_message(sp_address, message.serialize(), Default::default())
|
||||
.await;
|
||||
|
||||
// Await a non-empty message
|
||||
let received = wait_for_non_empty_message(client).await?;
|
||||
|
||||
// Handle the response received (the non-empty message awaited above)
|
||||
let sp_response = handle_response(received)?;
|
||||
|
||||
// Match JSON -> ResponseType
|
||||
let res = match sp_response {
|
||||
crate::ResponseTypes::Balance(response) => {
|
||||
println!("{:#?}", response);
|
||||
response.balance
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Iterating over incoming messages
|
||||
It is recommended to use `nym_client.next().await` over `nym_client.wait_for_messages().await` as the latter will return one message at a time which will probably be easier to deal with. See the [parallel send and receive example](./examples/split-send) for an example.
|
||||
|
||||
## Remember to disconnect your client
|
||||
You should always **manually disconnect your client** with `client.disconnect().await` as seen in the code examples. This is important as your client is writing to a local DB and dealing with SURB storage, so needs to gracefully shutdown.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Message Types
|
||||
|
||||
import { Callout } from 'nextra/components';
|
||||
|
||||
<Callout type="warning">
|
||||
There will be a breaking SDK upgrade in the coming months. This upgrade will make the SDK a lot easier to build with.
|
||||
|
||||
This upgrade will affect the interface of the SDK dramatically, and will be coupled with a protocol change - stay tuned for information on early access to the new protocol testnet.
|
||||
|
||||
It will also be coupled with the documentation of the SDK on [crates.io](https://crates.io/).
|
||||
</Callout>
|
||||
|
||||
There are several functions used to send outgoing messages through the Mixnet, each with a different level of customisation:
|
||||
|
||||
- `send(&self, message: InputMessage) -> Result<()>`
|
||||
Sends a `InputMessage` to the mixnet. This is the most low-level sending function, for full customization. Called by `send_message()`.
|
||||
|
||||
- `send_message<M>(&self, address: Recipient, message: M, surbs: IncludedSurbs) -> Result<()>`
|
||||
Sends bytes to the supplied Nym address. There is the option to specify the number of reply-SURBs to include. Called by `send_plain_message()`.
|
||||
|
||||
- `send_plain_message<M>(&self, address: Recipient, message: M) -> Result<()>`
|
||||
Sends data to the supplied Nym address with the default surb behaviour.
|
||||
|
||||
> Note we specify *outgoing* messages above: this is because the SDK assumes that replies will be anonymous via [SURBs](../../../network/traffic/anonymous-replies).
|
||||
|
||||
Replies rely on the creation of an `AnonymousSenderTag` by parsing and storing the `sender_tag` from incoming messages, and using this to reply, instead of the `Receipient` type used by the functions outlined above:
|
||||
|
||||
`send_reply<M>(&self, recipient_tag: AnonymousSenderTag, message: M) -> Result<()>` will send the reply message to the supplied anonymous recipient.
|
||||
|
||||
> You can find all of the function definitions [here](https://github.com/nymtech/nym/blob/master/sdk/rust/nym-sdk/src/mixnet/traits.rs).
|
||||
@@ -1,78 +1,130 @@
|
||||
---
|
||||
title: "Mixnet Module Troubleshooting"
|
||||
description: "Solutions for common Nym Rust SDK issues: client disconnect errors, empty SURB messages, verbose logging, and database lock problems."
|
||||
schemaType: "FAQPage"
|
||||
section: "Developers"
|
||||
lastUpdated: "2026-03-15"
|
||||
---
|
||||
|
||||
# Troubleshooting
|
||||
|
||||
import { Callout } from 'nextra/components';
|
||||
|
||||
Common issues and how to resolve them.
|
||||
<Callout type="warning">
|
||||
There will be a breaking SDK upgrade in the coming months. This upgrade will make the SDK a lot easier to build with.
|
||||
|
||||
## Always disconnect your client
|
||||
This upgrade will affect the interface of the SDK dramatically, and will be coupled with a protocol change - stay tuned for information on early access to the new protocol testnet.
|
||||
|
||||
You should always **manually disconnect your client** with `client.disconnect().await`. The client writes to a local DB and manages SURB storage, so it needs to shut down gracefully. Failing to do this can lead to the errors described below.
|
||||
|
||||
## Waiting for non-empty messages
|
||||
|
||||
When listening for a response, you may receive empty messages. These are SURB replenishment requests: the remote side asking for more reply SURBs. Filter them out:
|
||||
|
||||
```rust
|
||||
let mut message = None;
|
||||
while let Some(new_message) = client.wait_for_messages().await {
|
||||
if !new_message.is_empty() {
|
||||
message = new_message.into_iter().next();
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<Callout type="info">
|
||||
Prefer `client.next().await` (from the `futures::StreamExt` trait, not the Nym Stream module) over `client.wait_for_messages().await`; it returns one message at a time which is easier to work with. You'll need `use futures::StreamExt;` in scope.
|
||||
It will also be coupled with the documentation of the SDK on [crates.io](https://crates.io/).
|
||||
</Callout>
|
||||
|
||||
|
||||
Below are several common issues or questions you may have.
|
||||
|
||||
If you come across something that isn't explained here, [PRs are welcome](https://github.com/nymtech/nym/issues/new/choose).
|
||||
|
||||
## Verbose `task client is being dropped` logging
|
||||
|
||||
### On client shutdown (expected)
|
||||
If this is happening at the end of your code when disconnecting your client, this is fine; we just have a verbose client! When calling `client.disconnect().await` this is simply informing you that the client is shutting down.
|
||||
|
||||
When calling `client.disconnect().await`, the client logs that its background tasks are shutting down. This is normal and expected.
|
||||
On client shutdown / disconnect this is to be expected - this can be seen in many of the code examples as well. We use the [`nym_bin_common::logging`](https://github.com/nymtech/nym/blob/master/common/bin-common/src/logging/mod.rs) import to set logging in our example code. This defaults to `INFO` level.
|
||||
|
||||
Control log verbosity with `RUST_LOG`:
|
||||
If you wish to quickly lower the verbosity of your client process logs when developing you can prepend your command with `RUST_LOG=<LOGGING_LEVEL>`.
|
||||
|
||||
If you want to run the `builder.rs` example with only `WARN` level logging and below:
|
||||
|
||||
```sh
|
||||
RUST_LOG=warn cargo run --example simple
|
||||
cargo run --example builder
|
||||
```
|
||||
|
||||
Becomes:
|
||||
|
||||
```sh
|
||||
RUST_LOG=warn cargo run --example builder
|
||||
```
|
||||
|
||||
You can also make the logging _more_ verbose with:
|
||||
|
||||
```sh
|
||||
RUST_LOG=debug cargo run --example builder
|
||||
```
|
||||
|
||||
### Not on client shutdown (unexpected)
|
||||
|
||||
If you see these messages unexpectedly, you may be killing the client process too early. See the next section.
|
||||
If this is happening unexpectedly then you might be shutting your client process down too early. See the [accidentally killing your client process](#accidentally-killing-your-client-process-too-early) below for possible explanations and how to fix this issue.
|
||||
|
||||
## Accidentally killing your client process too early
|
||||
If you are seeing either of the following errors when trying to run a client, specifically sending a message, then you may be accidentally killing your client process.
|
||||
|
||||
If you see errors like `Polling shutdown failed: channel closed` or panics about `action control task has died`, your client is being dropped before it finishes sending.
|
||||
```sh
|
||||
2023-11-02T10:31:03.930Z INFO TaskClient-BaseNymClient-real_traffic_controller-ack_control-action_controller > the task client is getting dropped
|
||||
2023-11-02T10:31:04.625Z INFO TaskClient-BaseNymClient-received_messages_buffer-request_receiver > the task client is getting dropped
|
||||
2023-11-02T10:31:04.626Z DEBUG nym_client_core::client::real_messages_control::acknowledgement_control::input_message_listener > InputMessageListener: Exiting
|
||||
2023-11-02T10:31:04.626Z INFO TaskClient-BaseNymClient-real_traffic_controller-ack_control-input_message_listener > the task client is getting dropped
|
||||
2023-11-02T10:31:04.626Z INFO TaskClient-BaseNymClient-real_traffic_controller-reply_control > the task client is getting dropped
|
||||
2023-11-02T10:31:04.626Z DEBUG nym_client_core::client::real_messages_control > The reply controller has finished execution!
|
||||
2023-11-02T10:31:04.626Z DEBUG nym_client_core::client::real_messages_control::acknowledgement_control > The input listener has finished execution!
|
||||
2023-11-02T10:31:04.626Z INFO nym_task::manager > All registered tasks succesfully shutdown
|
||||
```
|
||||
|
||||
`send_plain_message()` is async, but **it only blocks until the message is placed in the client's internal queue**, not until it's actually sent into the Mixnet. After queuing, the client still needs to route-encrypt the message and interleave it with cover traffic.
|
||||
```sh
|
||||
2023-11-02T11:22:08.408Z ERROR TaskClient-BaseNymClient-topology_refresher > Assuming this means we should shutdown...
|
||||
2023-11-02T11:22:08.408Z ERROR TaskClient-BaseNymClient-mix_traffic_controller > Polling shutdown failed: channel closed
|
||||
2023-11-02T11:22:08.408Z INFO TaskClient-BaseNymClient-gateway_transceiver-child > the task client is getting dropped
|
||||
2023-11-02T11:22:08.408Z ERROR TaskClient-BaseNymClient-mix_traffic_controller > Assuming this means we should shutdown...
|
||||
thread 'tokio-runtime-worker' panicked at 'action control task has died: TrySendError { kind: Disconnected }', /home/.local/share/cargo/git/checkouts/nym-fbd2f6ea2e760da9/a800cba/common/client-core/src/client/real_messages_control/message_handler.rs:634:14
|
||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||
2023-11-02T11:22:08.477Z INFO TaskClient-BaseNymClient-real_traffic_controller-ack_control-input_message_listener > the task client is getting dropped
|
||||
2023-11-02T11:22:08.477Z ERROR TaskClient-BaseNymClient-real_traffic_controller-ack_control-input_message_listener > Polling shutdown failed: channel closed
|
||||
2023-11-02T11:22:08.477Z ERROR TaskClient-BaseNymClient-real_traffic_controller-ack_control-input_message_listener > Assuming this means we should shutdown...
|
||||
```
|
||||
|
||||
Make sure the program stays alive long enough. In practice this means awaiting a response or calling `sleep` before disconnecting:
|
||||
Using the following piece of code as an example:
|
||||
|
||||
```rust
|
||||
// Send a message
|
||||
client.send_plain_message(recipient, "hello").await.unwrap();
|
||||
use nym_sdk::mixnet::{MixnetClient, MixnetMessageSender, Recipient};
|
||||
use clap::Parser;
|
||||
|
||||
// Wait for the reply (keeps the client alive)
|
||||
if let Some(received) = client.wait_for_messages().await {
|
||||
for r in received {
|
||||
println!("Received: {}", String::from_utf8_lossy(&r.message));
|
||||
#[derive(Debug, Clone, Parser)]
|
||||
enum Opts {
|
||||
Client {
|
||||
recipient: Recipient
|
||||
}
|
||||
}
|
||||
|
||||
// Always disconnect gracefully
|
||||
client.disconnect().await;
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let opts: Opts = Parser::parse();
|
||||
nym_bin_common::logging::setup_logging();
|
||||
|
||||
let mut nym_client = MixnetClient::connect_new().await.expect("Could not build Nym client");
|
||||
|
||||
match opts {
|
||||
Opts::Client { recipient } => {
|
||||
nym_client.send_plain_message(recipient, "some message string").await.expect("send failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Lots of `duplicate fragment received` messages
|
||||
This is a simplified snippet of code for sending a simple hardcoded message with the following command:
|
||||
|
||||
`WARN` level logs about duplicate fragments are caused by Mixnet-level packet retransmission: the original and the retransmitted copy both arrive. This is not a bug in your client logic.
|
||||
```sh
|
||||
cargo run client <RECIPIENT_NYM_ADDRESS>
|
||||
```
|
||||
|
||||
You might assume that `send`-ing your message would _just work_ as `nym_client.send_plain_message()` is an async function; you might expect that the client will block until the message is actually sent into the mixnet, then shutdown.
|
||||
|
||||
However, this is not true.
|
||||
|
||||
**This will only block until the message is put into client's internal queue**. Therefore in the above example, the client is being shut down before the message is _actually sent to the mixnet_; after being placed in the client's internal queue, there is still work to be done under the hood, such as route encrypting the message and placing it amongst the stream of cover traffic.
|
||||
|
||||
The simple solution? Make sure the program/client stays active, either by calling `sleep`, or listening out for new messages. As sending a one-shot message without listening out for a response is likely not what you'll be doing, then you will be then awaiting a response (see the [message helpers page](./message-helpers) for an example of this).
|
||||
|
||||
Furthermore, you should always **manually disconnect your client** with `client.disconnect().await` as seen in the code examples. This is important as your client is writing to a local DB and dealing with SURB storage.
|
||||
|
||||
## Client receives empty messages when listening for response
|
||||
If you are sending out a message, it makes sense for your client to then listen out for incoming messages; this would probably be the reply you get from the service you've sent a message to.
|
||||
|
||||
You might however be receiving messages without data attached to them / empty payloads. This is most likely because your client is receiving a message containing a [SURB request](../../../network/traffic/anonymous-replies) - a SURB requesting more SURB packets to be sent to the service, in order for them to have enough packets (with a big enough overall payload) to split the entire response to your initial request across.
|
||||
|
||||
Whether the `data` of a SURB request being empty is a feature or a bug is to be decided - there is some discussion surrounding whether we can use SURB requests to send additional data to streamline the process of sending large replies across the mixnet.
|
||||
|
||||
You can find a few helper functions [here](./message-helpers) to help deal with this issue in the meantime.
|
||||
|
||||
> If you can think of a more succinct or different way of handling this do reach out - we're happy to hear other opinions
|
||||
|
||||
## Lots of `duplicate fragment received` messages
|
||||
You might see a lot of `WARN` level logs about duplicate fragments in your logs, depending on the log level you're using. This occurs when a packet is retransmitted somewhere in the Mixnet, but then the original makes it to the destination client as well. This is not something to do with your client logic, but instead the state of the Mixnet.
|
||||
|
||||
@@ -1,314 +0,0 @@
|
||||
---
|
||||
title: "Mixnet Tutorial: Send Your First Private Message"
|
||||
description: "Step-by-step Rust tutorial to connect to the Nym mixnet, send and receive messages, reply anonymously with SURBs, and persist client identity."
|
||||
schemaType: "HowTo"
|
||||
section: "Developers"
|
||||
lastUpdated: "2026-03-26"
|
||||
---
|
||||
|
||||
# Tutorial: Send Your First Private Message
|
||||
|
||||
import { Callout } from 'nextra/components'
|
||||
import { CodeVerified } from '../../../../components/code-verified'
|
||||
|
||||
By the end of this tutorial you'll have a working program that sends a Sphinx-encrypted message to itself through the Nym Mixnet, receives it, and replies anonymously using SURBs. The later sections cover persistent identity and concurrent send/receive.
|
||||
|
||||
**You'll need:** Rust 1.70+ and an internet connection (clients connect to the live Mixnet).
|
||||
|
||||
<CodeVerified />
|
||||
|
||||
## Step 1: Set up the project
|
||||
|
||||
```sh
|
||||
cargo init nym-mixnet-demo
|
||||
cd nym-mixnet-demo
|
||||
```
|
||||
|
||||
Add dependencies to `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
nym-sdk = { git = "https://github.com/nymtech/nym", rev = "97068b2" }
|
||||
nym-bin-common = { git = "https://github.com/nymtech/nym", rev = "97068b2", features = ["basic_tracing"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
blake3 = "=1.7.0" # required pin — see https://nymtech.net/docs/developers/rust/importing
|
||||
```
|
||||
|
||||
## Step 2: Connect and send
|
||||
|
||||
Replace the contents of `src/main.rs`:
|
||||
|
||||
```rust
|
||||
use nym_sdk::mixnet::{self, MixnetMessageSender};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
nym_bin_common::logging::setup_tracing_logger();
|
||||
|
||||
// connect_new() creates an ephemeral client — keys are generated in
|
||||
// memory and discarded on disconnect.
|
||||
let mut client = mixnet::MixnetClient::connect_new().await.unwrap();
|
||||
let our_address = client.nym_address();
|
||||
println!("Connected: {our_address}");
|
||||
|
||||
// The message is Sphinx-encrypted and mixed across 5 nodes.
|
||||
// send_plain_message only blocks until the message is queued —
|
||||
// encryption and mixing happen in background tasks.
|
||||
client
|
||||
.send_plain_message(*our_address, "hello from the mixnet!")
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
println!("Sent — waiting for arrival...");
|
||||
```
|
||||
|
||||
<Callout type="info">
|
||||
`setup_tracing_logger()` shows what the SDK is doing under the hood: gateway connections, topology fetches, Sphinx packet encryption. If the output is too verbose, comment out the line or filter with `RUST_LOG=warn cargo run`.
|
||||
</Callout>
|
||||
|
||||
## Step 3: Receive
|
||||
|
||||
```rust
|
||||
// wait_for_messages() returns the next batch of incoming messages.
|
||||
// Filter empty messages — these are SURB replenishment requests.
|
||||
let message = loop {
|
||||
if let Some(msgs) = client.wait_for_messages().await {
|
||||
if let Some(msg) = msgs.into_iter().find(|m| !m.message.is_empty()) {
|
||||
break msg;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
println!("Received: {}", String::from_utf8_lossy(&message.message));
|
||||
```
|
||||
|
||||
## Step 4: Reply anonymously
|
||||
|
||||
Every message includes a `sender_tag`, an opaque `AnonymousSenderTag` that lets you reply **without knowing the sender's address**. The SDK bundles SURBs (Single Use Reply Blocks) with every outgoing message by default:
|
||||
|
||||
```rust
|
||||
let sender_tag = message.sender_tag.expect("should have sender tag");
|
||||
|
||||
// send_reply uses the SURB — the sender's address is never revealed.
|
||||
client.send_reply(sender_tag, "hello back, anonymously!").await.unwrap();
|
||||
|
||||
let reply = loop {
|
||||
if let Some(msgs) = client.wait_for_messages().await {
|
||||
if let Some(msg) = msgs.into_iter().find(|m| !m.message.is_empty()) {
|
||||
break msg;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
println!("Reply: {}", String::from_utf8_lossy(&reply.message));
|
||||
|
||||
client.disconnect().await;
|
||||
}
|
||||
```
|
||||
|
||||
## Step 5: Run it
|
||||
|
||||
```sh
|
||||
RUST_LOG=info cargo run
|
||||
```
|
||||
|
||||
```
|
||||
Connected: 8gk4Y...@2xU4d...
|
||||
Sent — waiting for arrival...
|
||||
Received: hello from the mixnet!
|
||||
Reply: hello back, anonymously!
|
||||
```
|
||||
|
||||
## Going further: persist your identity
|
||||
|
||||
The ephemeral client above generates a new address on every run. To keep the same address across restarts, use `MixnetClientBuilder` with on-disk storage:
|
||||
|
||||
```rust
|
||||
use nym_sdk::mixnet::{self, MixnetMessageSender, StoragePaths};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
// Keys are generated on first run, then loaded from disk on subsequent runs.
|
||||
let paths = StoragePaths::new_from_dir("./my-client-data").unwrap();
|
||||
|
||||
let mut client = mixnet::MixnetClientBuilder::new_with_default_storage(paths)
|
||||
.await
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.connect_to_mixnet()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
println!("Address: {}", client.nym_address());
|
||||
|
||||
// Same API as before — send, receive, reply.
|
||||
client
|
||||
.send_plain_message(*client.nym_address(), "persistent identity!")
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
if let Some(msgs) = client.wait_for_messages().await {
|
||||
for m in msgs.into_iter().filter(|m| !m.message.is_empty()) {
|
||||
println!("Received: {}", String::from_utf8_lossy(&m.message));
|
||||
}
|
||||
}
|
||||
|
||||
// Always disconnect for clean shutdown — background tasks need to be
|
||||
// stopped and state files flushed.
|
||||
client.disconnect().await;
|
||||
}
|
||||
```
|
||||
|
||||
Run it twice; the address stays the same.
|
||||
|
||||
## Going further: send and receive from different tasks
|
||||
|
||||
Add `futures` to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
futures = "0.3"
|
||||
```
|
||||
|
||||
Use `split_sender()` to get a clone-able send handle for use in separate tasks:
|
||||
|
||||
```rust
|
||||
use futures::StreamExt;
|
||||
use nym_sdk::mixnet::{self, MixnetMessageSender};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let mut client = mixnet::MixnetClient::connect_new().await.unwrap();
|
||||
let addr = *client.nym_address();
|
||||
|
||||
// split_sender() returns a clone-able MixnetClientSender.
|
||||
let sender = client.split_sender();
|
||||
|
||||
// Spawn a receiver — the original client implements futures::Stream.
|
||||
let rx = tokio::spawn(async move {
|
||||
if let Some(msg) = client.next().await {
|
||||
println!("Received: {}", String::from_utf8_lossy(&msg.message));
|
||||
}
|
||||
client.disconnect().await;
|
||||
});
|
||||
|
||||
// Spawn a sender on a different task.
|
||||
let tx = tokio::spawn(async move {
|
||||
sender.send_plain_message(addr, "hello from another task!").await.unwrap();
|
||||
});
|
||||
|
||||
tx.await.unwrap();
|
||||
rx.await.unwrap();
|
||||
}
|
||||
```
|
||||
|
||||
## What's happening underneath
|
||||
|
||||
`connect_new()` generates an ephemeral identity (ed25519 + x25519 keypair), fetches the current network topology, selects a gateway, and opens a persistent WebSocket connection. `send_plain_message()` wraps the payload in Sphinx packets, layered encryption where each of the 5 Mix Nodes can only decrypt one layer and learn the next hop, never the full route. `wait_for_messages()` drains a local queue fed by the gateway; messages arrive out of order by design, to defeat timing analysis.
|
||||
|
||||
SURBs (Single Use Reply Blocks) are pre-computed return routes bundled with each outgoing message. The recipient uses them to reply without learning the sender's address. Each is single-use; the SDK replenishes them automatically.
|
||||
|
||||
`split_sender()` clones the send channel while the original client retains the receive side. Both halves can run on separate tokio tasks without synchronization.
|
||||
|
||||
## Complete code
|
||||
|
||||
### Ephemeral client
|
||||
|
||||
New address on every run, good for quick experiments:
|
||||
|
||||
```rust
|
||||
use nym_sdk::mixnet::{self, MixnetMessageSender};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
nym_bin_common::logging::setup_tracing_logger();
|
||||
|
||||
let mut client = mixnet::MixnetClient::connect_new().await.unwrap();
|
||||
let our_address = client.nym_address();
|
||||
println!("Connected: {our_address}");
|
||||
|
||||
client
|
||||
.send_plain_message(*our_address, "hello from the mixnet!")
|
||||
.await
|
||||
.unwrap();
|
||||
println!("Sent — waiting for arrival...");
|
||||
|
||||
let message = loop {
|
||||
if let Some(msgs) = client.wait_for_messages().await {
|
||||
if let Some(msg) = msgs.into_iter().find(|m| !m.message.is_empty()) {
|
||||
break msg;
|
||||
}
|
||||
}
|
||||
};
|
||||
println!("Received: {}", String::from_utf8_lossy(&message.message));
|
||||
|
||||
let sender_tag = message.sender_tag.expect("should have sender tag");
|
||||
client.send_reply(sender_tag, "hello back, anonymously!").await.unwrap();
|
||||
|
||||
let reply = loop {
|
||||
if let Some(msgs) = client.wait_for_messages().await {
|
||||
if let Some(msg) = msgs.into_iter().find(|m| !m.message.is_empty()) {
|
||||
break msg;
|
||||
}
|
||||
}
|
||||
};
|
||||
println!("Reply: {}", String::from_utf8_lossy(&reply.message));
|
||||
|
||||
client.disconnect().await;
|
||||
}
|
||||
```
|
||||
|
||||
### Persistent identity
|
||||
|
||||
Same address across restarts. Use this for real applications:
|
||||
|
||||
```rust
|
||||
use nym_sdk::mixnet::{self, MixnetMessageSender, StoragePaths};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
nym_bin_common::logging::setup_tracing_logger();
|
||||
|
||||
let paths = StoragePaths::new_from_dir("./my-client-data").unwrap();
|
||||
let mut client = mixnet::MixnetClientBuilder::new_with_default_storage(paths)
|
||||
.await
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.connect_to_mixnet()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let our_address = client.nym_address();
|
||||
println!("Connected: {our_address}");
|
||||
|
||||
client
|
||||
.send_plain_message(*our_address, "hello from the mixnet!")
|
||||
.await
|
||||
.unwrap();
|
||||
println!("Sent — waiting for arrival...");
|
||||
|
||||
let message = loop {
|
||||
if let Some(msgs) = client.wait_for_messages().await {
|
||||
if let Some(msg) = msgs.into_iter().find(|m| !m.message.is_empty()) {
|
||||
break msg;
|
||||
}
|
||||
}
|
||||
};
|
||||
println!("Received: {}", String::from_utf8_lossy(&message.message));
|
||||
|
||||
let sender_tag = message.sender_tag.expect("should have sender tag");
|
||||
client.send_reply(sender_tag, "hello back, anonymously!").await.unwrap();
|
||||
|
||||
let reply = loop {
|
||||
if let Some(msgs) = client.wait_for_messages().await {
|
||||
if let Some(msg) = msgs.into_iter().find(|m| !m.message.is_empty()) {
|
||||
break msg;
|
||||
}
|
||||
}
|
||||
};
|
||||
println!("Reply: {}", String::from_utf8_lossy(&reply.message));
|
||||
|
||||
client.disconnect().await;
|
||||
}
|
||||
```
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user