Compare commits

...

59 Commits

Author SHA1 Message Date
Sachin Kamath 0bb71399ee revert to original vanity link 2024-07-15 02:23:50 +05:30
Bogdan-Ștefan Neacşu 1f144690da Add upgrades to nym-node for authenticator changes (#4703) (#4710)
* Add iterative upgrades to nym-node

* Authenticator correct configuration

* Add info log

* Enable auth opts on entry gw

* Move ephemeral config from exit_gateway

* Fix fmt

* Fix clippy

* Pass custom transceiver for authenticator

* Fix non-linux build

* Feature gate wg_api

* Change naming from semver to simple incremental

* Move opts unwrap inside the mutable function

* Remove unneeded authenticator_description
2024-07-12 14:45:59 +02:00
Tommy Verrall eec1895acc Merge pull request #4709 from nymtech/dependabot/npm_and_yarn/nym-wallet/webdriver/braces-3.0.3
Bump braces from 3.0.2 to 3.0.3 in /nym-wallet/webdriver
2024-07-12 12:14:04 +02:00
dependabot[bot] 99864cb7a9 Bump braces from 3.0.2 to 3.0.3 in /nym-wallet/webdriver
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-12 09:09:14 +00:00
Fouad 3155728119 fix explorer mui deps (#4708) 2024-07-12 10:08:29 +01:00
Sachin Kamath 65a1d6d91e switch to new vanity link (#4705) 2024-07-11 13:04:56 +01:00
mx 44cf9b054b Max/dev portal update (#4696)
* updated tutorials with archive + stub

* removed out of date faq pages

* added binary build instructions section

* removed clients from docs

* added clients to devportal

* moved nym-vs-others to docs from devportal

* removed ood quickstart stuff

* tweaked integration options page

* summary changes for new structure

* moved sdk to devportal

* removed sdk from docs

* changed summary file for new structure

* added intro client overview page

* added wallet gif

* fixed now broken links

* removed old comm pages

* added references to newer apps (oreowallet + zcash demo)

* updated darkfi irc socks5

* fixed broken link

---------

Co-authored-by: mfahampshire <mfahampshire@pm.me>
2024-07-10 13:54:13 +02:00
Tommy Verrall 39e2473ef3 Merge pull request #4702 from nymtech/release/2024.7-doubledecker
Release/2024.7 doubledecker
2024-07-10 13:25:11 +02:00
import this 93a108863c add node description and release changelog (#4701) 2024-07-10 10:59:47 +00:00
import this 0905593123 [DOCs/operators]: Test WSS for exit-gateway, write a tutorial & update reversed proxy page (#4694)
* initialise wss guide

* update reverse proxy guide to post smoosh

* finish draft - missing correct script and testing

* syntax edit

* syntax edit

* update WSS configs and script

* edit WSS configs and script

* dinish wss guide - ready to review

* dinish wss guide - ready to review
2024-07-10 10:59:22 +00:00
Tommy Verrall ed9223d5a3 Merge branch 'develop' into release/2024.7-doubledecker 2024-07-10 11:46:21 +02:00
Tommy Verrall 962684ff56 Merge pull request #4667 from nymtech/feature/authenticator
Add authenticator
2024-07-10 10:14:58 +02:00
Tommy Verrall 7b3804c078 Merge pull request #4697 from nymtech/event-parsing
add event parsing to support cosmos_sdk > 0.50
2024-07-10 09:55:43 +02:00
Sachin Kamath 170f1823e1 fix tests 2024-07-09 21:54:57 +05:30
Sachin Kamath dc2020559a parse attributes from events instead of raw logs 2024-07-09 21:24:58 +05:30
Tommy Verrall 2b9444cce3 add an early return in parse_raw_str_logs for empty raw log strings.
this accommodates for the v50 chain upgrade
2024-07-09 20:36:36 +05:30
Bogdan-Ștefan Neacşu 68c1c068ac Add old config upgrade flow 2024-07-09 09:16:00 +00:00
Drazen Urch 3d0b70a237 Add mixnodes to self describing api cache (#4684)
* Add mixnodes to self describing api cache

* Use NodeRole enum

* Add route for described mixnodes

* Cleanup contract_cache

* Remove nodestatuscache

* wait_until_ready impl
2024-07-09 10:54:48 +02:00
Bogdan-Ștefan Neacşu 65a6edc78c Add authenticator debug to entry gateway config 2024-07-08 11:00:53 +00:00
Sachin Kamath 2ec8349897 update social links (#4695)
* replace vanity link

* fix links
2024-07-05 14:19:09 +00:00
Bogdan-Ștefan Neacşu 38a2d94f80 Fix clippy 2024-07-05 11:36:15 +00:00
Bogdan-Ștefan Neacşu c7fa910516 Fix add of req id 2024-07-05 10:36:18 +00:00
Bogdan-Ștefan Neacşu 2fe08274dd Add another layer for request id field 2024-07-05 10:20:56 +00:00
mx be89d848dc Max/try fix doc search (#4692)
* minimised dropdown bar

* update ci scripts

* theme changes to dev portal

* theme changes to operators

* theme changes to docs

* theme -> themes

* fixed theme -> themes import in book

* removed bak files

* remove logging from post_process + remove search feature from mdbook

---------

Co-authored-by: mfahampshire <mfahampshire@pm.me>
2024-07-05 12:19:14 +02:00
Bogdan-Ștefan Neacşu a230a9b8b9 Merge remote-tracking branch 'origin/develop' into feature/authenticator 2024-07-05 09:57:48 +00:00
Bogdan-Ștefan Neacşu 72eae7cdf3 Remove stale mid-registrations 2024-07-05 09:38:17 +00:00
Bogdan-Ștefan Neacşu 7cae195370 Typo 2024-07-05 07:54:29 +00:00
Bogdan-Ștefan Neacşu dfb16e385c Rand from workspace 2024-07-05 07:53:33 +00:00
Bogdan-Ștefan Neacşu 660e1cad0a Reconstruction msg 2024-07-04 14:26:37 +00:00
Bogdan-Ștefan Neacşu 7c1aa57a7e Add curr version 2024-07-04 14:15:25 +00:00
Bogdan-Ștefan Neacşu a06e496f78 Add final req creation 2024-07-04 13:54:13 +00:00
Jon Häggblad 70599b97b9 Send bandwidth status messages when connecting (#4691)
* Send bandwidth status messages when connecting

* Rename to task_client

* Move status message type to bandwidth controller
2024-07-04 13:10:16 +02:00
Bogdan-Ștefan Neacşu 02b194bde0 Function to create AuthReq 2024-07-04 10:40:53 +00:00
Bogdan-Ștefan Neacşu 20ec049db5 Remove more unnecessary structures 2024-07-04 09:41:17 +00:00
Tommy Verrall ebac4e8564 Update ci-build-upload-binaries.yml 2024-07-04 09:57:37 +02:00
benedettadavico da81664729 update versions and changelog 2024-07-04 09:36:09 +02:00
Bogdan-Ștefan Neacşu fec3d46b33 Include auth in self description 2024-07-03 13:50:44 +00:00
Bogdan-Ștefan Neacşu a4eb3a7dbf Named fork for better logging 2024-07-03 13:03:32 +00:00
Bogdan-Ștefan Neacşu 28d15f2c4f Remove unused import 2024-07-03 11:28:09 +00:00
Bogdan-Ștefan Neacşu c6f93e38f5 Remove unused post function 2024-07-03 09:34:03 +00:00
Bogdan-Ștefan Neacşu 2159f71888 Fix wg feature 2024-07-03 09:04:01 +00:00
Bogdan-Ștefan Neacşu a9abea3446 Fix macos build 2024-07-03 08:27:10 +00:00
Bogdan-Ștefan Neacşu 8e2713c9ba Remove unwrap 2024-07-03 08:21:58 +00:00
Bogdan-Ștefan Neacşu 2ba0ef0e35 Remove unused wg http endpoint 2024-07-02 14:09:34 +00:00
Bogdan-Ștefan Neacşu d3713cbc79 Fix user agent arg 2024-07-02 16:40:11 +03:00
Bogdan-Ștefan Neacşu 4d3fb2b585 Merge remote-tracking branch 'origin/develop' into feature/authenticator 2024-07-02 16:25:29 +03:00
benedetta davico ebfb9c4bc1 Merge pull request #4686 from nymtech/bugfix/chain-upgrade-raw-logs
Add an early return in `parse_raw_str_logs` for empty raw log strings.
2024-07-02 12:29:48 +02:00
Tommy Verrall 8e7918cc45 add an early return in parse_raw_str_logs for empty raw log strings.
this accommodates for the v50 chain upgrade
2024-07-02 11:19:50 +02:00
Bogdan-Ștefan Neacşu c465eb3efc Fix error type 2024-07-02 08:58:48 +00:00
Bogdan-Ștefan Neacşu b90136ac4e Uniformise non-linux wg function 2024-07-01 15:10:36 +00:00
Bogdan-Ștefan Neacşu ae5373168d Fmt 2024-07-01 14:42:10 +00:00
Bogdan-Ștefan Neacşu 6f3942f6b7 Move implementation for final request 2024-07-01 14:38:48 +00:00
Bogdan-Ștefan Neacşu 13f38343aa Finalize cli build 2024-07-01 13:44:59 +00:00
Bogdan-Ștefan Neacşu f75b4843e8 Merge remote-tracking branch 'origin/develop' into feature/authenticator 2024-07-01 09:56:34 +00:00
Bogdan-Ștefan Neacşu b43844bd7a Embed into gateway 2024-06-21 15:51:02 +00:00
Bogdan-Ștefan Neacşu cd89feb57e Fix path 2024-06-20 15:15:05 +00:00
Bogdan-Ștefan Neacşu 17553d606e Requests and responses 2024-06-20 16:58:21 +03:00
Bogdan-Ștefan Neacşu b6d9ed960b Specify version 2024-06-19 11:37:09 +03:00
Bogdan-Ștefan Neacşu 1d89a887fb Add authenticator 2024-06-18 19:05:23 +03:00
220 changed files with 6130 additions and 4425 deletions
@@ -104,8 +104,6 @@ jobs:
name: nym-binaries-artifacts
path: |
target/release/nym-client
target/release/nym-gateway
target/release/nym-mixnode
target/release/nym-socks5-client
target/release/nym-api
target/release/nym-network-requester
@@ -123,8 +121,6 @@ jobs:
OUTPUT_DIR: ci-builds/${{ github.ref_name }}
run: |
cp target/release/nym-client $OUTPUT_DIR
cp target/release/nym-gateway $OUTPUT_DIR
cp target/release/nym-mixnode $OUTPUT_DIR
cp target/release/nym-socks5-client $OUTPUT_DIR
cp target/release/nym-api $OUTPUT_DIR
cp target/release/nym-network-requester $OUTPUT_DIR
+32
View File
@@ -4,6 +4,38 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [2024.7-doubledecker] (2024-07-04)
- Add an early return in `parse_raw_str_logs` for empty raw log strings. ([#4686])
- Bump braces from 3.0.2 to 3.0.3 in /wasm/mix-fetch/internal-dev ([#4672])
- add expiry returned on import ([#4670])
- [bugfix] missing rustls feature ([#4666])
- Bump ws from 8.13.0 to 8.17.1 in /wasm/client/internal-dev-node ([#4665])
- Bump braces from 3.0.2 to 3.0.3 in /clients/native/examples/js-examples/websocket ([#4663])
- Bump ws from 8.14.2 to 8.17.1 in /sdk/typescript/packages/nodejs-client ([#4662])
- Update setup.md ([#4661])
- New clippy lints ([#4660])
- Bump braces from 3.0.2 to 3.0.3 in /nym-api/tests ([#4659])
- Bump braces from 3.0.2 to 3.0.3 in /docker/typescript_client/upload_contract ([#4658])
- Update vps-setup.md ([#4656])
- Update configuration.md ([#4655])
- Remove old PR template ([#4639])
[#4686]: https://github.com/nymtech/nym/pull/4686
[#4672]: https://github.com/nymtech/nym/pull/4672
[#4670]: https://github.com/nymtech/nym/pull/4670
[#4666]: https://github.com/nymtech/nym/pull/4666
[#4665]: https://github.com/nymtech/nym/pull/4665
[#4663]: https://github.com/nymtech/nym/pull/4663
[#4662]: https://github.com/nymtech/nym/pull/4662
[#4661]: https://github.com/nymtech/nym/pull/4661
[#4660]: https://github.com/nymtech/nym/pull/4660
[#4659]: https://github.com/nymtech/nym/pull/4659
[#4658]: https://github.com/nymtech/nym/pull/4658
[#4656]: https://github.com/nymtech/nym/pull/4656
[#4655]: https://github.com/nymtech/nym/pull/4655
[#4639]: https://github.com/nymtech/nym/pull/4639
## [2024.6-chomp] (2024-06-25)
- Remove additional code as part of Ephemera Purge and SP and contracts ([#4650])
Generated
+75 -8
View File
@@ -2093,7 +2093,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]]
name = "explorer-api"
version = "1.1.35"
version = "1.1.36"
dependencies = [
"chrono",
"clap 4.5.4",
@@ -3849,7 +3849,7 @@ dependencies = [
[[package]]
name = "nym-api"
version = "1.1.39"
version = "1.1.40"
dependencies = [
"anyhow",
"async-trait",
@@ -3950,6 +3950,54 @@ dependencies = [
"tokio",
]
[[package]]
name = "nym-authenticator"
version = "0.1.0"
dependencies = [
"anyhow",
"bincode",
"bs58 0.5.1",
"bytes",
"clap 4.5.4",
"fastrand 2.1.0",
"futures",
"ipnetwork 0.16.0",
"log",
"nym-authenticator-requests",
"nym-bin-common",
"nym-client-core",
"nym-config",
"nym-crypto",
"nym-id",
"nym-network-defaults",
"nym-sdk",
"nym-service-providers-common",
"nym-sphinx",
"nym-task",
"nym-types",
"nym-wireguard",
"nym-wireguard-types",
"rand 0.8.5",
"serde",
"serde_json",
"thiserror",
"tokio",
"tokio-stream",
"tokio-util",
"url",
]
[[package]]
name = "nym-authenticator-requests"
version = "0.1.0"
dependencies = [
"bincode",
"nym-sphinx",
"nym-wireguard-types",
"rand 0.8.5",
"serde",
]
[[package]]
name = "nym-bandwidth-controller"
version = "0.1.0"
@@ -4009,7 +4057,7 @@ dependencies = [
[[package]]
name = "nym-cli"
version = "1.1.37"
version = "1.1.38"
dependencies = [
"anyhow",
"base64 0.13.1",
@@ -4088,7 +4136,7 @@ dependencies = [
[[package]]
name = "nym-client"
version = "1.1.36"
version = "1.1.37"
dependencies = [
"bs58 0.5.1",
"clap 4.5.4",
@@ -4514,6 +4562,7 @@ dependencies = [
"ipnetwork 0.16.0",
"log",
"nym-api-requests",
"nym-authenticator",
"nym-bin-common",
"nym-config",
"nym-credentials",
@@ -4901,7 +4950,7 @@ dependencies = [
[[package]]
name = "nym-network-requester"
version = "1.1.37"
version = "1.1.38"
dependencies = [
"addr",
"anyhow",
@@ -4950,9 +4999,26 @@ dependencies = [
"zeroize",
]
[[package]]
name = "nym-network-statistics"
version = "1.1.34"
dependencies = [
"dirs 4.0.0",
"log",
"nym-bin-common",
"nym-statistics-common",
"nym-task",
"pretty_env_logger",
"rocket",
"serde",
"sqlx",
"thiserror",
"tokio",
]
[[package]]
name = "nym-node"
version = "1.1.3"
version = "1.1.4"
dependencies = [
"anyhow",
"bip39",
@@ -4964,6 +5030,7 @@ dependencies = [
"cupid",
"humantime-serde",
"ipnetwork 0.16.0",
"nym-authenticator",
"nym-bin-common",
"nym-client-core-config-types",
"nym-config",
@@ -5214,7 +5281,7 @@ dependencies = [
[[package]]
name = "nym-socks5-client"
version = "1.1.36"
version = "1.1.37"
dependencies = [
"bs58 0.5.1",
"clap 4.5.4",
@@ -5727,7 +5794,7 @@ dependencies = [
[[package]]
name = "nymvisor"
version = "0.1.2"
version = "0.1.3"
dependencies = [
"anyhow",
"bytes",
+2
View File
@@ -20,6 +20,7 @@ members = [
"clients/native",
"clients/native/websocket-requests",
"clients/socks5",
"common/authenticator-requests",
"common/async-file-watcher",
"common/bandwidth-controller",
"common/bin-common",
@@ -95,6 +96,7 @@ members = [
"mixnode",
"sdk/lib/socks5-listener",
"sdk/rust/nym-sdk",
"service-providers/authenticator",
"service-providers/common",
"service-providers/ip-packet-router",
"service-providers/network-requester",
+1 -1
View File
@@ -52,7 +52,7 @@ References for developers:
You can chat to us in two places:
* The #dev channel on [Matrix](https://matrix.to/#/#dev:nymtech.chat)
* The various developer channels on [Discord](discord.gg/nymproject)
* The various developer channels on [Discord](https://discord.gg/nym)
### Tokenomics & Rewards
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.36"
version = "1.1.37"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.36"
version = "1.1.37"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021"
+17
View File
@@ -0,0 +1,17 @@
[package]
name = "nym-authenticator-requests"
version = "0.1.0"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
documentation.workspace = true
edition.workspace = true
license.workspace = true
[dependencies]
bincode = { workspace = true }
rand = { workspace = true }
serde = { workspace = true, features = ["derive"] }
nym-sphinx = { path = "../nymsphinx" }
nym-wireguard-types = { path = "../wireguard-types" }
+13
View File
@@ -0,0 +1,13 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod v1;
pub const CURRENT_VERSION: u8 = 1;
fn make_bincode_serializer() -> impl bincode::Options {
use bincode::Options;
bincode::DefaultOptions::new()
.with_big_endian()
.with_varint_encoding()
}
@@ -0,0 +1,7 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod request;
pub mod response;
const VERSION: u8 = 1;
@@ -0,0 +1,70 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_sphinx::addressing::Recipient;
use nym_wireguard_types::{GatewayClient, InitMessage};
use serde::{Deserialize, Serialize};
use crate::make_bincode_serializer;
use super::VERSION;
fn generate_random() -> u64 {
use rand::RngCore;
let mut rng = rand::rngs::OsRng;
rng.next_u64()
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthenticatorRequest {
pub version: u8,
pub data: AuthenticatorRequestData,
pub reply_to: Recipient,
pub request_id: u64,
}
impl AuthenticatorRequest {
pub fn from_reconstructed_message(
message: &nym_sphinx::receiver::ReconstructedMessage,
) -> Result<Self, bincode::Error> {
use bincode::Options;
make_bincode_serializer().deserialize(&message.message)
}
pub fn new_initial_request(init_message: InitMessage, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random();
(
Self {
version: VERSION,
data: AuthenticatorRequestData::Initial(init_message),
reply_to,
request_id,
},
request_id,
)
}
pub fn new_final_request(gateway_client: GatewayClient, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random();
(
Self {
version: VERSION,
data: AuthenticatorRequestData::Final(gateway_client),
reply_to,
request_id,
},
request_id,
)
}
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
use bincode::Options;
make_bincode_serializer().serialize(self)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorRequestData {
Initial(InitMessage),
Final(GatewayClient),
}
@@ -0,0 +1,88 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_sphinx::addressing::Recipient;
use nym_wireguard_types::registration::RegistrationData;
use serde::{Deserialize, Serialize};
use crate::make_bincode_serializer;
use super::VERSION;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthenticatorResponse {
pub version: u8,
pub data: AuthenticatorResponseData,
pub reply_to: Recipient,
}
impl AuthenticatorResponse {
pub fn new_pending_registration_success(
registration_data: RegistrationData,
request_id: u64,
reply_to: Recipient,
) -> Self {
Self {
version: VERSION,
data: AuthenticatorResponseData::PendingRegistration(PendingRegistrationResponse {
reply: registration_data,
reply_to,
request_id,
}),
reply_to,
}
}
pub fn new_registered(reply_to: Recipient, request_id: u64) -> Self {
Self {
version: VERSION,
data: AuthenticatorResponseData::Registered(RegisteredResponse {
reply_to,
request_id,
}),
reply_to,
}
}
pub fn recipient(&self) -> Recipient {
self.reply_to
}
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
use bincode::Options;
make_bincode_serializer().serialize(self)
}
pub fn from_reconstructed_message(
message: &nym_sphinx::receiver::ReconstructedMessage,
) -> Result<Self, bincode::Error> {
use bincode::Options;
make_bincode_serializer().deserialize(&message.message)
}
pub fn id(&self) -> Option<u64> {
match &self.data {
AuthenticatorResponseData::PendingRegistration(response) => Some(response.request_id),
AuthenticatorResponseData::Registered(response) => Some(response.request_id),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorResponseData {
PendingRegistration(PendingRegistrationResponse),
Registered(RegisteredResponse),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PendingRegistrationResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: RegistrationData,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RegisteredResponse {
pub request_id: u64,
pub reply_to: Recipient,
}
+13
View File
@@ -0,0 +1,13 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
// See other comments for other TaskStatus message enumds about abusing the Error trait when we
// should have a new trait for TaskStatus messages
#[derive(Debug, thiserror::Error)]
pub enum BandwidthStatusMessage {
#[error("remaining bandwidth: {0}")]
RemainingBandwidth(i64),
#[error("no bandwidth left")]
NoBandwidth,
}
+3
View File
@@ -14,8 +14,11 @@ use nym_validator_client::coconut::all_coconut_api_clients;
use nym_validator_client::nym_api::EpochId;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
pub use event::BandwidthStatusMessage;
pub mod acquire;
pub mod error;
mod event;
mod utils;
#[derive(Debug)]
+15 -12
View File
@@ -11,7 +11,7 @@ use crate::traits::GatewayPacketRouter;
use crate::{cleanup_socket_message, try_decrypt_binary_message};
use futures::{SinkExt, StreamExt};
use log::*;
use nym_bandwidth_controller::BandwidthController;
use nym_bandwidth_controller::{BandwidthController, BandwidthStatusMessage};
use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage;
use nym_credential_storage::storage::Storage as CredentialStorage;
use nym_credentials::CredentialSpendingData;
@@ -105,8 +105,8 @@ pub struct GatewayClient<C, St = EphemeralCredentialStorage> {
// currently unused (but populated)
negotiated_protocol: Option<u8>,
/// Listen to shutdown messages.
shutdown: TaskClient,
/// Listen to shutdown messages and send notifications back to the task manager
task_client: TaskClient,
}
impl<C, St> GatewayClient<C, St> {
@@ -117,7 +117,7 @@ impl<C, St> GatewayClient<C, St> {
shared_key: Option<Arc<SharedKeys>>,
packet_router: PacketRouter,
bandwidth_controller: Option<BandwidthController<C, St>>,
shutdown: TaskClient,
task_client: TaskClient,
) -> Self {
GatewayClient {
authenticated: false,
@@ -135,7 +135,7 @@ impl<C, St> GatewayClient<C, St> {
reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS,
reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF,
negotiated_protocol: None,
shutdown,
task_client,
}
}
@@ -299,7 +299,7 @@ impl<C, St> GatewayClient<C, St> {
loop {
tokio::select! {
_ = self.shutdown.recv() => {
_ = self.task_client.recv() => {
log::trace!("GatewayClient control response: Received shutdown");
log::debug!("GatewayClient control response: Exiting");
break Err(GatewayClientError::ConnectionClosedGatewayShutdown);
@@ -540,6 +540,9 @@ impl<C, St> GatewayClient<C, St> {
self.bandwidth_remaining = bandwidth_remaining;
self.negotiated_protocol = protocol_version;
log::debug!("authenticated: {status}, bandwidth remaining: {bandwidth_remaining}");
self.task_client.send_status_msg(Box::new(
BandwidthStatusMessage::RemainingBandwidth(bandwidth_remaining),
));
Ok(())
}
ServerResponse::Error { message } => Err(GatewayClientError::GatewayError(message)),
@@ -805,7 +808,7 @@ impl<C, St> GatewayClient<C, St> {
.as_ref()
.expect("no shared key present even though we're authenticated!"),
),
self.shutdown.clone(),
self.task_client.clone(),
)
}
_ => unreachable!(),
@@ -879,8 +882,8 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
// perfectly fine here, because it's not meant to be used
let (ack_tx, _) = mpsc::unbounded();
let (mix_tx, _) = mpsc::unbounded();
let shutdown = TaskClient::dummy();
let packet_router = PacketRouter::new(ack_tx, mix_tx, shutdown.clone());
let task_client = TaskClient::dummy();
let packet_router = PacketRouter::new(ack_tx, mix_tx, task_client.clone());
GatewayClient {
authenticated: false,
@@ -898,7 +901,7 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS,
reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF,
negotiated_protocol: None,
shutdown,
task_client,
}
}
@@ -906,7 +909,7 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
self,
packet_router: PacketRouter,
bandwidth_controller: Option<BandwidthController<C, St>>,
shutdown: TaskClient,
task_client: TaskClient,
) -> GatewayClient<C, St> {
// invariants that can't be broken
// (unless somebody decided to expose some field that wasn't meant to be exposed)
@@ -930,7 +933,7 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
reconnection_attempts: self.reconnection_attempts,
reconnection_backoff: self.reconnection_backoff,
negotiated_protocol: self.negotiated_protocol,
shutdown,
task_client,
}
}
}
@@ -3,7 +3,7 @@
use crate::nyxd::cosmwasm_client::client_traits::CosmWasmClient;
use crate::nyxd::cosmwasm_client::helpers::{compress_wasm_code, CheckResponse};
use crate::nyxd::cosmwasm_client::logs::{self, parse_raw_logs};
use crate::nyxd::cosmwasm_client::logs::parse_raw_logs;
use crate::nyxd::cosmwasm_client::types::*;
use crate::nyxd::error::NyxdError;
use crate::nyxd::fee::{Fee, DEFAULT_SIMULATED_GAS_MULTIPLIER};
@@ -19,6 +19,7 @@ use cosmrs::feegrant::{
};
use cosmrs::proto::cosmos::tx::signing::v1beta1::SignMode;
use cosmrs::staking::{MsgDelegate, MsgUndelegate};
use cosmrs::tendermint::abci::{Event, EventAttribute};
use cosmrs::tx::{self, Msg};
use cosmrs::{cosmwasm, AccountId, Any, Tx};
use log::debug;
@@ -51,6 +52,20 @@ fn single_unspecified_signer_auth(
}
.auth_info(empty_fee())
}
// Searches in events for an event of the given event type which contains an
// attribute for with the given key.
fn find_attribute<'a>(
events: &'a [Event],
event_type: &str,
attr_key: &str,
) -> Option<&'a EventAttribute> {
events
.iter()
.find(|attr| attr.kind == event_type)?
.attributes
.iter()
.find(|attr| attr.key == attr_key)
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
@@ -118,6 +133,7 @@ where
.check_response()?;
let logs = parse_raw_logs(tx_res.tx_result.log)?;
let events = tx_res.tx_result.events;
let gas_info = GasInfo {
gas_wanted: tx_res.tx_result.gas_wanted.try_into().unwrap_or_default(),
gas_used: tx_res.tx_result.gas_used.try_into().unwrap_or_default(),
@@ -127,7 +143,7 @@ where
// the reason I think unwrap here is fine is that if the transaction succeeded and those
// fields do not exist or code_id is not a number, there's no way we can recover, we're probably connected
// to wrong validator or something
let code_id = logs::find_attribute(&logs, "store_code", "code_id")
let code_id = find_attribute(&events, "store_code", "code_id")
.unwrap()
.value
.parse()
@@ -140,6 +156,7 @@ where
compressed_checksum,
code_id,
logs,
events,
transaction_hash: tx_res.hash,
gas_info,
})
@@ -182,6 +199,7 @@ where
.check_response()?;
let logs = parse_raw_logs(tx_res.tx_result.log)?;
let events = tx_res.tx_result.events;
let gas_info = GasInfo {
gas_wanted: tx_res.tx_result.gas_wanted.try_into().unwrap_or_default(),
gas_used: tx_res.tx_result.gas_used.try_into().unwrap_or_default(),
@@ -190,7 +208,7 @@ where
// the reason I think unwrap here is fine is that if the transaction succeeded and those
// fields do not exist or address is malformed, there's no way we can recover, we're probably connected
// to wrong validator or something
let contract_address = logs::find_attribute(&logs, "instantiate", "_contract_address")
let contract_address = find_attribute(&events, "instantiate", "_contract_address")
.unwrap()
.value
.parse()
@@ -199,6 +217,7 @@ where
Ok(InstantiateResult {
contract_address,
logs,
events,
transaction_hash: tx_res.hash,
gas_info,
})
@@ -231,6 +250,7 @@ where
};
Ok(ChangeAdminResult {
logs: parse_raw_logs(tx_res.tx_result.log)?,
events: tx_res.tx_result.events,
transaction_hash: tx_res.hash,
gas_info,
})
@@ -261,6 +281,7 @@ where
};
Ok(ChangeAdminResult {
logs: parse_raw_logs(tx_res.tx_result.log)?,
events: tx_res.tx_result.events,
transaction_hash: tx_res.hash,
gas_info,
})
@@ -298,6 +319,7 @@ where
};
Ok(MigrateResult {
logs: parse_raw_logs(tx_res.tx_result.log)?,
events: tx_res.tx_result.events,
transaction_hash: tx_res.hash,
gas_info,
})
@@ -335,6 +357,7 @@ where
};
Ok(ExecuteResult {
logs: parse_raw_logs(tx_res.tx_result.log)?,
events: tx_res.tx_result.events,
data: tx_res.tx_result.data.into(),
transaction_hash: tx_res.hash,
gas_info,
@@ -378,6 +401,7 @@ where
};
Ok(ExecuteResult {
logs: parse_raw_logs(tx_res.tx_result.log)?,
events: tx_res.tx_result.events,
data: tx_res.tx_result.data.into(),
transaction_hash: tx_res.hash,
gas_info,
@@ -9,16 +9,12 @@ pub use nym_coconut_bandwidth_contract_common::event_attributes::*;
pub use nym_coconut_dkg_common::event_attributes::*;
// it seems that currently validators just emit stringified events (which are also returned as part of deliverTx response)
// as theirs logs
// as their logs
#[derive(Debug, Serialize, Deserialize)]
pub struct Log {
#[serde(default)]
// weird thing is that the first msg_index seems to always be undefined on the raw logs
pub msg_index: usize,
// unless I'm missing something obvious, the "log" type in cosmjs is always an empty string
// and launchpad cosmos validator was setting it to what essentially is just the raw version of what
// we received (and we don't care about launchpad, we, as the time of writing this, work on the stargate)
// log: String,
pub events: Vec<cosmwasm_std::Event>,
}
@@ -37,8 +33,13 @@ pub fn find_attribute<'a>(
.find(|attr| attr.key == attribute_key)
}
// those two functions were separated so that the internal logic could actually be tested
// these two functions were separated so that the internal logic could actually be tested
fn parse_raw_str_logs(raw: &str) -> Result<Vec<Log>, NyxdError> {
// From Cosmos SDK > 0.50 onwards, log field is not populated
if raw.is_empty() {
return Ok(Vec::new());
}
let logs: Vec<Log> = serde_json::from_str(raw).map_err(|_| NyxdError::MalformedLogString)?;
if logs.len() != logs.iter().unique_by(|log| log.msg_index).count() {
// this check is only here because I don't yet fully understand raw log string generation and
@@ -232,6 +232,8 @@ pub struct UploadResult {
pub logs: Vec<Log>,
pub events: Vec<abci::Event>,
/// Transaction hash (might be used as transaction ID)
pub transaction_hash: Hash,
@@ -269,6 +271,8 @@ pub struct InstantiateResult {
pub logs: Vec<Log>,
pub events: Vec<abci::Event>,
/// Transaction hash (might be used as transaction ID)
pub transaction_hash: Hash,
@@ -279,6 +283,8 @@ pub struct InstantiateResult {
pub struct ChangeAdminResult {
pub logs: Vec<Log>,
pub events: Vec<abci::Event>,
/// Transaction hash (might be used as transaction ID)
pub transaction_hash: Hash,
@@ -289,6 +295,8 @@ pub struct ChangeAdminResult {
pub struct MigrateResult {
pub logs: Vec<Log>,
pub events: Vec<abci::Event>,
/// Transaction hash (might be used as transaction ID)
pub transaction_hash: Hash,
@@ -301,6 +309,8 @@ pub struct ExecuteResult {
pub data: Vec<u8>,
pub events: Vec<abci::Event>,
/// Transaction hash (might be used as transaction ID)
pub transaction_hash: Hash,
+1 -1
View File
@@ -14,7 +14,7 @@ bytes = { workspace = true }
nym-bin-common = { path = "../bin-common" }
nym-crypto = { path = "../crypto" }
nym-sphinx = { path = "../nymsphinx" }
rand = "0.8.5"
rand = { workspace = true }
serde = { workspace = true, features = ["derive"] }
thiserror = { workspace = true }
time = { workspace = true }
+1 -2
View File
@@ -10,8 +10,7 @@ pub use config::Config;
pub use error::Error;
pub use public_key::PeerPublicKey;
pub use registration::{
ClientMac, ClientMessage, ClientRegistrationResponse, GatewayClient, GatewayClientRegistry,
InitMessage, Nonce,
ClientMac, ClientMessage, GatewayClient, GatewayClientRegistry, InitMessage, Nonce,
};
#[cfg(feature = "verify")]
+3 -11
View File
@@ -7,6 +7,7 @@ use base64::{engine::general_purpose, Engine};
use dashmap::DashMap;
use serde::{Deserialize, Serialize};
use std::net::IpAddr;
use std::time::SystemTime;
use std::{fmt, ops::Deref, str::FromStr};
#[cfg(feature = "verify")]
@@ -18,13 +19,13 @@ use sha2::Sha256;
pub type GatewayClientRegistry = DashMap<PeerPublicKey, GatewayClient>;
pub type PendingRegistrations = DashMap<PeerPublicKey, RegistrationData>;
pub type PrivateIPs = DashMap<IpAddr, Free>;
pub type PrivateIPs = DashMap<IpAddr, Taken>;
#[cfg(feature = "verify")]
pub type HmacSha256 = Hmac<Sha256>;
pub type Nonce = u64;
pub type Free = bool;
pub type Taken = Option<SystemTime>;
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "type", rename_all = "camelCase")]
@@ -53,15 +54,6 @@ impl InitMessage {
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "type", rename_all = "camelCase")]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub enum ClientRegistrationResponse {
PendingRegistration(RegistrationData),
Registered,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub struct RegistrationData {
pub nonce: u64,
pub gateway_data: GatewayClient,
+39 -33
View File
@@ -3,7 +3,7 @@ title = "Nym Docs"
authors = ["Max Hampshire, Serinko, Alexia Lorenza Martinel"]
description = "Nym technical documentation"
language = "en"
multilingual = false # for the moment - ideally work on chinese, brazillian ,portugese spanish next
multilingual = false # for the moment - ideally work on chinese, brazillian ,portugese spanish next
src = "src"
[rust]
@@ -14,17 +14,19 @@ edition = "2018"
#################
[preprocessor.theme]
sidebar-width = "280px"
content-max-width = "70%"
content-main-margin-left = "5%"
content-main-margin-right = "5%"
root-font-size = "70%"
# DO NOT CHANGE or you might overwrite the custom hbs file
turn-off = false
pagetoc = true
sidebar-width = "280px"
content-max-width = "80%"
root-font-size = "70%"
# if you need to change anything in the index.hbs file you need to turn this to `false`, rebuild the book,
# probably remove the additional `comment` that gets appended to the header, and then change this back to `true`.
# this is because of a bug in the `mdbook-theme` plugin
turn-off = true
[preprocessor.admonish]
command = "mdbook-admonish"
assets_version = "3.0.2" # do not edit: managed by `mdbook-admonish install`
assets_version = "3.0.2" # do not edit: managed by `mdbook-admonish install`
# https://gitlab.com/tglman/mdbook-variables/
[preprocessor.variables.variables]
@@ -53,52 +55,56 @@ renderer = ["html"]
#########
[build]
build-dir = "book" # the directory where the output is placed
create-missing = true # whether or not to create missing pages
use-default-preprocessors = true # use the default preprocessors
extra-watch-dirs = [] # directories to watch for triggering builds
build-dir = "book" # the directory where the output is placed
create-missing = true # whether or not to create missing pages
use-default-preprocessors = true # use the default preprocessors
extra-watch-dirs = [] # directories to watch for triggering builds
##########
# OUTPUT #
##########
[output.html]
theme = "nym_themes"
theme = "themes"
default-theme = "coal"
preferred-dark-theme = "coal"
curly-quotes = true
copy-fonts = true
no-section-label = false
additional-css = ["./nym_themes/custom.css", "./nym_themes/mdbook-admonish.css", "./nym_themes/pagetoc.css"]
additional-js = ["./nym_themes/pagetoc.js"]
additional-css = [
"./themes/custom.css",
"./themes/mdbook-admonish.css",
"./themes/pagetoc.css",
]
additional-js = ["./themes/pagetoc.js"]
git-repository-url = "https://github.com/nymtech/nym"
git-repository-icon = "fa-github"
input-404 = "not-found.md"
[output.html.fold]
enable = true # whether or not to enable section folding
level = 0 # the depth to start folding
enable = true # whether or not to enable section folding
level = 0 # the depth to start folding
# controlling rust sample code blocks
[output.html.playground]
editable = false # allows editing the source code
copyable = true # include the copy button for copying code snippets
copy-js = true # includes the JavaScript for the code editor
line-numbers = true # displays line numbers for editable code
runnable = true # displays a run button for rust code
editable = false # allows editing the source code
copyable = true # include the copy button for copying code snippets
copy-js = true # includes the JavaScript for the code editor
line-numbers = true # displays line numbers for editable code
runnable = true # displays a run button for rust code
# options for the built in text search
[output.html.search]
enable = true # enables the search feature
limit-results = 30 # maximum number of search results
teaser-word-count = 30 # number of words used for a search result teaser
use-boolean-and = true # multiple search terms must all match
boost-title = 2 # ranking boost factor for matches in headers
boost-hierarchy = 1 # ranking boost factor for matches in page names
boost-paragraph = 1 # ranking boost factor for matches in text
expand = true # partial words will match longer terms
heading-split-level = 3 # link results to heading levels
copy-js = true # include Javascript code for search
enable = true # enables the search feature
limit-results = 30 # maximum number of search results
teaser-word-count = 30 # number of words used for a search result teaser
use-boolean-and = true # multiple search terms must all match
boost-title = 2 # ranking boost factor for matches in headers
boost-hierarchy = 1 # ranking boost factor for matches in page names
boost-paragraph = 1 # ranking boost factor for matches in text
expand = true # partial words will match longer terms
heading-split-level = 3 # link results to heading levels
copy-js = true # include Javascript code for search
[output.linkcheck]
warning-policy = "warn"
+35 -70
View File
@@ -1,94 +1,59 @@
#
# Summary
- [Introduction](introduction.md)
- [Clients Overview - Start Here!](clients-overview.md)
# Infrastructure
# SDKs
- [Rust SDK](sdk/rust/rust.md)
- [Message Types](sdk/rust/message-types.md)
- [Message Helpers](sdk/rust/message-helpers.md)
- [Troubleshooting](sdk/rust/troubleshooting.md)
- [Examples](sdk/rust/examples.md)
- [Simple Send](sdk/rust/examples/simple.md)
- [Create and Store Keys](sdk/rust/examples/keys.md)
- [Manual Storage](sdk/rust/examples/storage.md)
- [Anonymous Replies](sdk/rust/examples/surbs.md)
- [Use Custom Network Topology](sdk/rust/examples/custom-network.md)
- [Socks Proxy](sdk/rust/examples/socks.md)
- [Split Send and Receive](sdk/rust/examples/split-send.md)
- [Testnet Bandwidth Cred](sdk/rust/examples/credential.md)
- [Example Cargo file](sdk/rust/examples/cargo.md)
- [Typescript SDK](sdk/typescript.md)
- [What is Nym?](infrastructure/nym.md)
- [Nym vs Other Systems](infrastructure/nym-vs-others.md)
- [Node Types](infrastructure/node-types.md)
# Binaries
- [Pre-built Binaries](binaries/pre-built-binaries.md)
- [Building from Source](binaries/building-nym.md)
# Quickstart
# Standalone Clients
- [Websocket Client](clients/websocket-client.md)
- [Setup & Run](clients/websocket/setup.md)
- [Configuration](clients/websocket/config.md)
- [Using Your Client](clients/websocket/usage.md)
- [Examples](clients/websocket/examples.md)
- [Socks5 Client](clients/socks5-client.md)
- [Setup & Run](clients/socks5/setup.md)
- [Using Your Client](clients/socks5/usage.md)
- [Webassembly Client](clients/webassembly-client.md)
- [Overview](quickstart/overview.md)
- [Chat demo (webapp)](quickstart/chat-demo.md)
- [Coconut Credential Playground (webapp)](quickstart/cred-playground.md)
- [SOCKS Proxy (CLI)](quickstart/socks-proxy.md)
# User Manuals
- [NymVPN alpha](nymvpn/intro.md)
- [CLI](nymvpn/cli.md)
<!-- OUTDATED STUFF:
- [NymConnect X Monero](tutorials/monero.md)
- [NymConnect X Matrix](tutorials/matrix.md)
- [NymConnect X Telegram](tutorials/telegram.md)
- [NymConnect X Electrum](tutorials/electrum.md)
- [NymConnect X Firo wallet](tutorials/firo.md)
-->
# Tutorials
- [Stub: Updates Coming Soon!](./tutorials/coming-soon.md)
# Code Examples
- [Custom Service Providers](examples/custom-services.md)
- [Apps Using Network Requesters](examples/using-nrs.md)
- [Browser only](examples/browser-only.md)
- [Monorepo examples](examples/monorepo-examples.md)
# Integrations
- [Integration Options](integrations/integration-options.md)
[//]: # (- [Mixnet Integration]&#40;integrations/mixnet-integration.md&#41;)
- [Payment Integration](integrations/payment-integration.md)
# Tutorials
- [Rust SDK](tutorials/rust-sdk.md)
- [Blockchain Service pt1](tutorials/cosmos-service/intro.md)
- [Tutorial Overview](tutorials/cosmos-service/overview.md)
- [Preparing Your Environment](tutorials/cosmos-service/preparing-env.md)
- [Preparing Your Lib](tutorials/cosmos-service/lib.md)
- [Preparing Your Client](tutorials/cosmos-service/client.md)
- [Preparing Your Client pt2](tutorials/cosmos-service/client-src.md)
- [Preparing Your Service](tutorials/cosmos-service/service.md)
- [Preparing Your Service pt2](tutorials/cosmos-service/service-src.md)
- [Querying the Chain](tutorials/cosmos-service/querying.md)
- [Typescript](tutorials/typescript.md)
- [Simple Service Provider](tutorials/simple-service-provider/simple-service-provider.md)
- [Tutorial Overview](tutorials/simple-service-provider/overview.md)
- [Preparing Your User Client Environment](tutorials/simple-service-provider/preparating-env.md)
- [Building Your User Client](tutorials/simple-service-provider/user-client.md)
- [Preparing Your Service Provider Environment](tutorials/simple-service-provider/preparating-env2.md)
- [Building Your Service Provider](tutorials/simple-service-provider/service-provider.md)
- [Sending a Message Through the Mixnet](tutorials/simple-service-provider/sending-message.md)
[//]: # (TODO make generic )
[//]: # (# Shipyard Builders Hackathon 2023 )
[//]: # (- [General Info & Resources]&#40;shipyard/general.md&#41;)
[//]: # (- [Hackathon Challenges]&#40;shipyard/challenges-overview.md&#41;)
[//]: # (- [A Note on Infrastructure]&#40;shipyard/infra.md&#41;)
[//]: # (- [Submission Guidelines]&#40;shipyard/guidelines.md&#41;)
<!-- Commenting out as a lot of the stuff is deprecated, can be purged as a part of the large overhaul
# Events
- [Web3Privacy Now](./events/web3-privacy.md)
- [HCPP23-serinko](./events/hcpp23-serinko.md)
- [HCPP23-max](./events/hcpp23-max.md)
-->
# FAQ
- [General](faq/general-faq.md)
- [Integrations](faq/integrations-faq.md)
- [Rewards & Token](faq/rewards-faq.md)
# Community Resources
- [Nym DevRel AMAs](community-resources/ama.md)
- [Community Applications and Guides](community-resources/community-applications-and-guides.md)
- [Change Service Grantee Information](info-request.md)
# User Manuals
- [NymVPN alpha](nymvpn/intro.md)
- [CLI](nymvpn/cli.md)
---
# Misc.
@@ -0,0 +1,61 @@
# Building from Source
> Nym runs on Mac OS X, Linux, and Windows. All nodes **except the Desktop Wallet and NymConnect** on Windows should be considered experimental - it works fine if you're an app developer but isn't recommended for running nodes.
## Building Nym
Nym has two main codebases:
- the [Nym platform](https://github.com/nymtech/nym), written in Rust. This contains all of our code _except_ for the validators.
- the [Nym validators](https://github.com/nymtech/nyxd), written in Go.
> This page details how to build the main Nym platform code.
## Prerequisites
- Debian/Ubuntu: `pkg-config`, `build-essential`, `libssl-dev`, `curl`, `jq`, `git`
```
apt install pkg-config build-essential libssl-dev curl jq git
```
- Arch/Manjaro: `base-devel`
```
pacman -S base-devel
```
- Mac OS X: `pkg-config` , `brew`, `openss1`, `protobuf`, `curl`, `git`
Running the following the script installs Homebrew and the above dependencies:
```
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
- `Rust & cargo >= {{minimum_rust_version}}`
We recommend using the [Rust shell script installer](https://www.rust-lang.org/tools/install). Installing cargo from your package manager (e.g. `apt`) is not recommended as the packaged versions are usually too old.
If you really don't want to use the shell script installer, the [Rust installation docs](https://forge.rust-lang.org/infra/other-installation-methods.html) contain instructions for many platforms.
## Download and build Nym binaries
The following commands will compile binaries into the `nym/target/release` directory:
```sh
rustup update
git clone https://github.com/nymtech/nym.git
cd nym
git reset --hard # in case you made any changes on your branch
git pull # in case you've checked it out before
git checkout master # master branch has the latest release version: `develop` will most likely be incompatible with deployed public networks
cargo build --release # build your binaries with **mainnet** configuration
```
Quite a bit of stuff gets built. The key working parts for devs are the Client binaries and the CLI tool:
* [websocket client](../clients/websocket-client.md): `nym-client`
* [socks5 client](../clients/socks5-client.md): `nym-socks5-client`
* [nym-cli tool](https://nymtech.net/docs/tools/nym-cli.md): `nym-cli`
> You cannot build from GitHub's .zip or .tar.gz archive files on the releases page - the Nym build scripts automatically include the current git commit hash in the built binary during compilation, so the build will fail if you use the archive code (which isn't a Git repository). Check the code out from github using `git clone` instead.
@@ -0,0 +1,6 @@
# Pre-built Binaries
The [Github releases page](https://github.com/nymtech/nym/releases) has pre-built binaries which should work on Ubuntu 20.04 and other Debian-based systems, but at this stage cannot be guaranteed to work everywhere.
If the pre-built binaries don't work or are unavailable for your system, you will need to build the platform yourself.
@@ -0,0 +1,49 @@
# Clients Overview
A large proportion of the Nym mixnet's functionality is implemented client-side.
Clients perform the following actions on behalf of users:
* determine network topology - what mixnodes exist, what their keys are, etc.
* register with a gateway
* authenticate with a gateway
* receive and decrypt messages from the gateway
* create layer-encrypted Sphinx packets
* send Sphinx packets with real messages
* send Sphinx packet _cover traffic_ when no real messages are being sent
* retransmit un-acknowledged packet sends - if a client sends 100 packets to a gateway, but only receives an acknowledgement ('ack') for 95 of them, it will resend those 5 packets to the gateway again, to make sure that all packets are received.
> As a developer, you'll want to use a Nym client to send your application network traffic through the mixnet; whether that is an RPC call, a TCP connection request, or treating it like a UDP pipe, you need to send whatever bytes your app needs to send through it. However, unlike (e.g.) a TCP Socket, Nym client communication is message-based, so you cannot (yet) simply plug-and-play using the mixnet as a seamless drop-in replacement. We are currently working on stream-like abstractions for ease of integration with the Rust SDK.
## Types of Nym clients
At present, there are three Nym clients:
- the websocket (native) client
- the SOCKS5 client
- the wasm (webassembly) client
You need to choose which one you want incorporate into your app. Which one you use will depend largely on your preferred programming style and the purpose of your app.
### The websocket client
Your first option is the native websocket client (`nym-client`). This is a compiled program that can run on Linux, Mac OS X, and Windows machines. It can be run as a persistent process on a desktop or server machine. You can connect to it with **any language that supports websockets**.
> Rust developers can import websocket client functionality into their code via the [Rust SDK](sdk/rust/rust.md).
### The webassembly client
If you're working in JavaScript or Typescript in the browser, or building an [edge computing](https://en.wikipedia.org/wiki/Edge_computing) app, you'll likely want to choose the webassembly client.
It's packaged and [available on the npm registry](https://www.npmjs.com/package/@nymproject/nym-client-wasm), so you can `npm install` it into your JavaScript or TypeScript application.
> The webassembly client is most easily used via the [Typescript SDK](sdk/typescript.md). Typescript developers who wish to send API requests through the mixnet can can also check the [`mixfetch`]() package.
### The SOCKS5 client
The `nym-socks5-client` is useful for allowing existing applications to use the Nym mixnet without any code changes. All that's necessary is that they can use one of the SOCKS5, SOCKS4a, or SOCKS4 proxy protocols (which many applications can - crypto wallets, browsers, chat applications etc).
When used as a standalone client, it's less flexible as a way of writing custom applications than the other clients, but able to be used to proxy application traffic through the mixnet without having to make any code changes.
> Rust developers can import socks client functionality into their code via the [Rust SDK](sdk/rust/rust.md).
## Commonalities between clients
All Nym client packages present basically the same capabilities to the privacy application developer. They need to run as a persistent process in order to stay connected and ready to receive any incoming messages from their gateway nodes. They register and authenticate to gateways, and encrypt Sphinx packets.
@@ -25,14 +25,14 @@ You need to choose which one you want incorporate into your app. Which one you u
### The websocket client
Your first option is the native websocket client (`nym-client`). This is a compiled program that can run on Linux, Mac OS X, and Windows machines. It can be run as a persistent process on a desktop or server machine. You can connect to it with **any language that supports websockets**.
_Rust developers can import websocket client functionality into their code via the [Rust SDK](../sdk/rust/rust.md)_.
> Rust developers can import websocket client functionality into their code via the [Rust SDK](../sdk/rust/rust.md).
### The webassembly client
If you're working in JavaScript or Typescript in the browser, or building an [edge computing](https://en.wikipedia.org/wiki/Edge_computing) app, you'll likely want to choose the webassembly client.
It's packaged and [available on the npm registry](https://www.npmjs.com/package/@nymproject/nym-client-wasm), so you can `npm install` it into your JavaScript or TypeScript application.
_The webassembly client is most easily used via the [Typescript SDK](../sdk/typescript.md)_.
> The webassembly client is most easily used via the [Typescript SDK](../sdk/typescript.md). Typescript developers who wish to send API requests through the mixnet can can also check the [`mixfetch`]() package.
### The SOCKS5 client
The `nym-socks5-client` is useful for allowing existing applications to use the Nym mixnet without any code changes. All that's necessary is that they can use one of the SOCKS5, SOCKS4a, or SOCKS4 proxy protocols (which many applications can - crypto wallets, browsers, chat applications etc).
@@ -1,6 +1,6 @@
# Socks5 Client
> The Nym socks5 client was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code on this page, go there first.
> The Nym Socks5 Client was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code on this page, go there first.
## Current version
```
@@ -60,7 +60,7 @@ There are 2 pieces of software that work together to send SOCKS traffic through
The `nym-socks5-client` allows you to do the following from your local machine:
* Take a TCP data stream from a application that can send traffic via SOCKS5.
* Chop up the TCP stream into multiple Sphinx packets, assigning sequence numbers to them, while leaving the TCP connection open for more data
* Send the Sphinx packets through the mixnet to a [network requester](../nodes/network-requester.md). Packets are shuffled and mixed as they transit the mixnet.
* Send the Sphinx packets through the mixnet to a [network requester](https://nymtech.net/operators/nodes/network-requester.md). Packets are shuffled and mixed as they transit the mixnet.
The `nym-network-requester` then reassembles the original TCP stream using the packets' sequence numbers, and make the intended request. It will then chop up the response into Sphinx packets and send them back through the mixnet to your `nym-socks5-client`. The application will then receive its data, without even noticing that it wasn't talking to a "normal" SOCKS5 proxy!
@@ -100,11 +100,11 @@ 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](../architecture/traffic-flow.md#private-replies-using-surbs) along with your request. It defaults to `false`, we are explicitly setting it as `true`. It defaults to `false` for compatibility with older versions of the [Network Requester](../nodes/network-requester.md).
The `--use-reply-surbs` field denotes whether you wish to send [SURBs](https://nymtech.net/docs/architecture/traffic-flow.md#private-replies-using-surbs) along with your request. It defaults to `false`, we are explicitly setting it as `true`. It defaults to `false` for compatibility with older versions of the [Network Requester](https://nymtech.net/nodes/network-requester.md).
The `--provider` field needs to be filled with the Nym address of a Network Requester that can make network requests on your behalf. If you don't want to [run your own](../nodes/network-requester.md) you can select one from the [mixnet explorer](https://explorer.nymtech.net/network-components/service-providers) by copying its `Client ID` and using this as the value of the `--provider` flag. Alternatively, you could use [this list](https://harbourmaster.nymtech.net/).
The `--provider` field needs to be filled with the Nym address of a Network Requester that can make network requests on your behalf. If you don't want to [run your own](https://nymtech.net/operators/nodes/network-requester.md) you can select one from the [mixnet explorer](https://explorer.nymtech.net/network-components/service-providers) by copying its `Client ID` and using this as the value of the `--provider` flag. Alternatively, you could use [this list](https://harbourmaster.nymtech.net/).
Since the nodes on this list are the infrastructure for [Nymconnect](https://nymtech.net/developers/quickstart/nymconnect-gui.html) they will support all apps on the [default whitelist](../nodes/network-requester.md#network-requester-whitelist): Keybase, Telegram, Electrum, Blockstream Green, and Helios.
Since the nodes on this list are the infrastructure for [Nymconnect](https://nymtech.net/developers/quickstart/nymconnect-gui.html) they will support all apps on the [default whitelist](https://nymtech.net/operators/nodes/network-requester.md#network-requester-whitelist): Keybase, Telegram, Electrum, Blockstream Green, and Helios.
#### Choosing a Gateway
By default - as in the example above - your client will choose a random gateway to connect to.
@@ -1,4 +1,4 @@
# SOCKS Proxy (CLI)
# Setup
> `nym-socks5-client` now also supports SOCKS4 and SOCKS4A protocols as well as SOCKS5.
@@ -39,33 +39,4 @@ Now your client is initialised, start it with the following:
./nym-socks5-client run --id <ID>
```
## Proxying traffic
After completing the steps above, your local `nym-socks5-client` will be listening on `localhost:1080` ready to proxy traffic to the Network Requester set as the `--provider` when initialising.
When trying to connect your app, generally the proxy settings are found in `settings->advanced` or `settings->connection`.
Here is an example of setting the proxy connecting in Blockstream Green:
![Blockstream Green settings](../images/blockstream-green.gif)
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.
## Supported Applications
Any application which can be redirected over Socks5 proxy should work. Nym community has been successfully running over Nym Mixnet these applications:
- Bitcoin Electrum wallet
- Monero wallet (GUI and CLI with monerod)
- Telegram chat
- Element/Matrix chat
- Firo wallet
- ircd chat
- Blockstream Green
Keep in mind that Nym has been developing a new client **[NymVPN](https://nymvpn.com) (GUI and CLI) routing all users traffic through the Mixnet.**
## Further reading
If you want to dig more into the architecture and use of the socks5 client check out its documentation [here](https://nymtech.net/docs/clients/socks5-client.html).
@@ -0,0 +1,33 @@
# Using Your Client
## Proxying traffic
After completing the steps above, your local `nym-socks5-client` will be listening on `localhost:1080` ready to proxy traffic to the Network Requester set as the `--provider` when initialising.
When trying to connect your app, generally the proxy settings are found in `settings->advanced` or `settings->connection`.
Here is an example of setting the proxy connecting in Blockstream Green:
![Blockstream Green settings](../../images/blockstream-green.gif)
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.
## Supported Applications
Any application which can be redirected over Socks5 proxy should work. Nym community has been successfully running over Nym Mixnet these applications:
- Bitcoin Electrum wallet
- Monero wallet (GUI and CLI with monerod)
- Telegram chat
- Element/Matrix chat
- Firo wallet
- Blockstream Green
> DarkFi's ircd chat was previously supported: they have moved to DarkIrc: whether the existing integration work is still operational needs to be tested.
Keep in mind that Nym has been developing a new client **[NymVPN](https://nymvpn.com) (GUI and CLI) routing all users traffic through the Mixnet.**
## Further reading
If you want to dig more into the architecture and use of the socks5 client check out its documentation [here](https://nymtech.net/docs/clients/socks5-client.html).
@@ -11,7 +11,7 @@ There are a number of message types that you can send up the websocket as define
```
## Getting your own address
When you start your app, it is best practice to ask the native client to tell you what your own address is (from the generated configuration files - see [here](../addressing-system.md) for more on Nym's addressing scheme). If you are running a service, you need to do this in order to know what address to give others. In a client-side piece of code you can also use this as a test to make sure your websocket connection is running smoothly. To do this, send:
When you start your app, it is best practice to ask the native client to tell you what your own address is (from the generated configuration files - see [here](https://nymtech.net/docs/architecture/addressing-system.md) for more on Nym's addressing scheme). If you are running a service, you need to do this in order to know what address to give others. In a client-side piece of code you can also use this as a test to make sure your websocket connection is running smoothly. To do this, send:
```json
{
@@ -58,7 +58,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](../../architecture/traffic-flow.md#private-replies-using-surbs) 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](https://nymtech.net/docs/architecture/traffic-flow.md#private-replies-using-surbs) 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,7 +0,0 @@
# DevRel AMAs
The Nym Technology Developer Relations AMA (Ask Me Anything) is an event organised by the Nym team to engage and connect with the developer community as well as answer any questions that they may have.
> ⚠️ Hosted every fortnight on Wednesday @ 4pm UTC
Archives of these calls can be found [here](https://www.youtube.com/watch?v=0kVXR7aNOyg&list=PLoc3wV2YJYwohgwzf5IinyebV4GGYsa9K).
@@ -1,122 +0,0 @@
# Community Applications
If you would like to share your application here, please submit a pull request to the `main` branch of the `nymtech/dev-portal` [repository](https://github.com/nymtech/dev-portal).
## <img src='../images/profile_picture/pastenym_ntv_pp.png' style="float: right; width: 75px; height: 75px;">Pastenym
>A [pastebin](https://pastebin.com) inspired project, offer a solution for sharing text with Nym products to offer full anonymity, even on metadata level.
* [Github](https://github.com/notrustverify/pastenym)
* [Deployed App](https://pastenym.ch)
## <img src='../images/profile_picture/pineappleproxy_pp.png' style="float: right; width: 75px; height: 75px;">Nostr-Nym
> [Nostr-nym](https://github.com/notrustverify/nostr-nym) offer a solution to use [Nostr](https://nostr.how/en/what-is-nostr) protocol by giving the possibility to run a relay on mixnet. By using a nostr client compatible with the mixnet, users can protect their privacy to be able to use Nostr has the want, without being observed.
* [Github](https://github.com/notrustverify/nostr-nym)
* [Deployed App](https://nostrnym.pnproxy.org/)
* [Documentation](https://blog.notrustverify.ch/nostr-relay-on-nym)
## <img src='../images/profile_picture/ethereum_rpc_spook_pp.png' style="float: right; width: 75px; height: 75px;"> Spook
> Ethereum RPC request mixer uses the Nym network mixing service to anonymize RPC requests to the Ethereum network without revealing sensitive data and metadata.
* [Github](https://github.com/EdenBlockVC/spook)
## <img src='../images/profile_picture/ethereum_transaction_broadcaster_root_pp.png' style="float: right; width: 75px; height: 75px;"> Ethereum Transaction Broadcaster
> Ethereum Transaction Broadcaster that uses the Nym Mixnet to provide privacy and anonymity for transactions on the Ethereum network command-line interface.
* [Github](https://github.com/noot/nym-ethtx)
## <img src='../images/profile_picture/nymdrive_saleel_pp.png' style="float: right; width: 75px; height: 75px;">NymDrive
> An open-source, decentralized, E2E encrypted, privacy friendly alternative to Google Drive/Dropbox, allowing for file encryption and decryption using the Nym Mixnet.
* [Github](https://github.com/saleel/nymdrive)
* [Demo](https://www.youtube.com/watch?v=5Rx73nw8NYI)
* [Presentation](https://docs.google.com/presentation/d/1MpvIK32Mx9VKLVfMTcvbeyrsKHHUsTvDQ-3n31dR0NE/edit#slide=id.p)
## <img src='../images/profile_picture/nym_dashboard_pp.svg' style="float: right; width: 75px; height: 75px;">Nym Dashboard
> Developed by No Trust Verify, this dashboard is a great tool to get information about the mixnet, gateways and mixnodes.
* [Deployed App](https://status.notrustverify.ch/d/CW3L7dVVk/nym-mixnet?orgId=1)
## <img src='../images/profile_picture/pastenym_ntv_pp.png' style="float: right; width: 75px; height: 75px;">Is Nym Up
> Explore whether we're up through IsNymUp, a tool that helps check the heath of the Nym network as well as some mixnet related statistics!
* [Deployed App](https://isnymup.com/)
## <img src='../images/profile_picture/darkfi_over_nym_pp.png' style="float: right; width: 75px; height: 75px;">DarkFi over Nym
> DarkFi leverages Nym's mixnet as a pluggable transport for IRCD, their p2p IRC variant. Users can anonymously connect to peers over the network, ensuring secure and private communication within the DarkFi ecosystem.
* [Github](https://github.com/darkrenaissance/darkfi)
* [Documentation](https://darkrenaissance.github.io/darkfi/clients/nym_outbound.html)
## <img src='../images/profile_picture/nymstr_email_pp.png' style="float: right; width: 75px; height: 75px;">Nymstr email
> Experience secure and private email communication with ease using Nymstr email, which enables seamless transmission of emails over a SOCKS5 proxy and our NYM mixnet!
* [Github](https://github.com/dial0ut/nymstr-email)
## <img src='../images/profile_picture/minibolt_pp.png' style="float: right; width: 75px; height: 75px;">Minibolt
> Proxies the clearnet connections of a Bitcoin node and its associated tools using the NYM mixnet.
* [Github](https://github.com/minibolt-guide/minibolt)
* [Documentation](https://v2.minibolt.info/bonus-guides/system/nym-mixnet#proxying-bitcoin-core)
## <img src='../images/profile_picture/nymgraph_pp.png' style="float: right; width: 75px; height: 75px;">NymGraph
> NymGraph is a graphical chat client for Nym running on Ubuntu and Debian. Test it to chat over the Nym network!
* [Github](https://github.com/Tyz3/nymgraph)
<br/> <br/>
# Community Guides
We aren't the only ones writing documentation: the Nym developer community is also a great source of guides and resources, some of which we've included here.
## <img src='../images/profile_picture/pastenym_ntv_pp.png' style="float: right; width: 75px; height: 75px;"> No Trust Verify
>No Trust Verify is a project that aims to build open-source, privacy-enhancing technologies that make it easier to use the Internet securely and anonymously. Their focus is on providing tools and services that make it simple for developers to create decentralized applications (dApps) that respect users' privacy.
* [Awesome Nym list](https://notrustverify.github.io/awesome-nym/) ([GitHub](https://github.com/notrustverify/awesome-nym))
* A lot of guides can be found on the [NTV Blog](https://blog.notrustverify.ch/)
## <img src='../images/profile_picture/pineappleproxy_pp.png' style="float: right; width: 75px; height: 75px;">The Way of the NYMJA
by Pineapple Proxy🍍
>Born out of a study group from Nym's Shipyard Academy, Pineapple Proxy has emerged as a cluster of motivated and skilled individuals who see the new internet taking shape. With vibecare at the heart of their approach, this zesty collective is on a mission to make privacy convenient for everyone via content, new tools, events, and novel experiences. They believe in collective intelligence, empathy, and collaboration as the means by which privacy will become a meaningful reality.
* [Website](https://pnproxy.org/welcome.html) ([GitHub](https://github.com/Pineapple-Proxy-DAO/web))
@@ -1,6 +0,0 @@
# Forums
Welcome to our page dedicated to providing you with links to open forums discussing privacy-enhancing technologies, as well as general privacy topics. These forums are a great place to learn more about the latest developments in privacy technology, as well as to connect with other individuals who are passionate about protecting their online privacy. Whether you're new to the world of privacy or an experienced user, you're sure to find valuable information and resources on these forums.
🚧 coming soon 🚧
@@ -1,6 +1,9 @@
# Browser only
With the Typescript SDK you can run a Nym client in a webworker - meaning you can connect to the mixnet through the browser without having to worry about any other code than your web framework.
- Oreowallet have integrated `mixFetch` into their browser-extension wallet to run transactions through the mixnet.
- [Codebase](https://github.com/oreoslabs/oreowallet-extension/tree/mixFetch)
- [NoTrustVerify](https://notrustverify.ch/) have set up an example application using [`mixFetch`](https://sdk.nymtech.net/examples/mix-fetch) to fetch crypto prices from CoinGecko over the mixnet.
- [Website](https://notrustverify.github.io/mixfetch-examples/)
- [Codebase](https://github.com/notrustverify/mixfetch-examples)
@@ -1,6 +1,11 @@
# Custom Services
Custom services involve two pieces of code that communicate via the mixnet: a client, and a custom server/service. This custom service will most likely interact with the wider internet / a clearnet service on your behalf, with the mixnet between you and the service, acting as a privacy shield.
> The current model of relying on a Service Provider has some issues, such as additional complexity in deployment and maintenance, as well as creating potential chokepoints for app traffic. Work is going on (in the open in our [monorepo](https://github.com/nymtech/nym) ofc) to start removing this requirement as much as possible, by allowing for the creation of packet-contents in such a way that the existing Network Requester/Exit Gateway infrastructure can support network requests in a similar way to `mixFetch`. More on this as and when it is released.
- [Nym Zcash RPC demo](https://github.com/nymtech/nym-zcash-rpc-demo), although used to only pipe RPC traffic, is a proof of concept 'generic' mixnet piping example which exposes a TPC Socket on the client side for incoming traffic, pipes this through the mixnet, and then streams TCP packets 'out' the other side. A good example of non-app-specific traffic transport which developers could also quite easily use as a template for their own app-specific work.
- [Codebase](https://github.com/nymtech/nym-zcash-rpc-demo)
- PasteNym is a private pastebin alternative. It involves a browser-based frontend utilising the Typescript SDK and a Python-based backend service communicating with a standalone Nym Websocket Client. **If you're a Python developer, start here!**.
- [Frontend codebase](https://github.com/notrustverify/pastenym)
- [Backend codebase](https://github.com/notrustverify/pastenym-frontend)
@@ -1,45 +0,0 @@
# Nym General FAQ
> If you have questions which are not answered below, please share them at our [DevRel AMAs](../community-resources/ama.md) or seek support in [Nym's community](https://nymtech.net/community)
### What is Nym?
Nym is a privacy platform that secures user data and protects against surveillance at the network level.
The platform does so by leveraging different technological components:
- **Nym Mixnet**, a type of overlay network that makes both content and metadata of transactions private through mixing, network-level obfuscation and incentivisation (using Sphinx);
- A blockchain called **Nyx**, our Cosmos SDK blockchain, to allow for us to use payment tokens in the form of NYM, as well as smart contracts, in order to create a robust, decentralized, and secure environment incentives for the Mixnet;
- **Coconut**, a zero-knowledge signature scheme, that creates an application-level private access control layer to power Zk-Nyms;
- A utility token **NYM**, to pay for usage, measure reputation and serve as rewards for the privacy infrastructure.
Simply put, the [Nym network ("Nym")](https://www.feat-nym-update-nym-web.websites.dev.nymte.ch/nym-whitepaper.pdf) is a decentralized and incentivized infrastructure to provision privacy to a broad range of message-based applications and services. Think of it as a [*"Layer 0" privacy infrastructure*](https://blog.nymtech.net/nym-layer-0-privacy-infrastructure-for-the-whole-internet-e53238f9b8e7) for the entire internet.
**Related articles:**
- [*Nym is not a blockchain, but is powered by one*](https://blog.nymtech.net/nym-is-not-a-blockchain-but-it-is-powered-by-one-4bb16ef16587)
- [*Nym tokens*](https://blog.nymtech.net/nym-tokens-where-do-they-live-and-how-are-they-distributed-cross-chain-8d134bf9c41f)
- [*A breakdown of the smart contracts that run the Nym token economics*](https://blog.nymtech.net/a-breakdown-of-the-smart-contracts-that-run-the-nym-token-economics-3a61b4139f95)
- [*Zk-Nyms are here*](https://blog.nymtech.net/a-breakdown-of-the-smart-contracts-that-run-the-nym-token-economics-3a61b4139f95)
- [*Sphinx: the anonymous data format that powers Nym*](https://blog.nymtech.net/sphinx-tl-dr-the-data-packet-that-can-anonymize-bitcoin-and-the-internet-18d152c6e4dc)
### What's the difference between Nym and VPNs?
Nym is not an onion routing system, it is not a decentralized VPN - its much more than that. Nym is a mixnet meant to stop precisely the traffic analysis attacks that Tor and dVPNs are vulnerable to.
It is an orthogonal design that maintains better privacy and can support anonymity, although usually with a cost in terms of latency.
It basically is an infrastructure on which privacy preserving apps can be built, leveraging the Mixnet and Coconut credentials, amongst others.
The **Nym mixnet and VPNs differ** because VPNs do not mix nor do they protect metadata from an adversary who may be able to watch the entire network.
**Related articles:**
- [*VPNs, Tor, I2P, how does Nym compare? *](https://blog.nymtech.net/vpns-tor-i2p-how-does-nym-compare-8576824617b8)
### What is Nyms VPN?
Since Q2 2023 the Nym core team has been working on launching the **first major consumer facing product** that runs on top of the Nym mixnet: a high speed, trustless and decentralized VPN, paid for via the NYM token - facilitating anonymous payments if wished.
The product positions itself as a full-network protection service available across all of a users devices, **leveraging the Nym Mixnet** and other primitives to offer split tunneling and traffic obfuscation techniques to protect against censorship.
**Related articles:**
- [*What does it take to build the most powerful VPN?*](https://blog.nymtech.net/what-does-it-take-to-build-the-worlds-most-powerful-vpn-d351a76ec4e6)
Binary file not shown.

After

Width:  |  Height:  |  Size: 364 KiB

@@ -1,5 +1,5 @@
# Integration Options
If you've already gone through the different [Quick Start](../quickstart/overview.md) options and had a look at the tutorials, you have seen the possibilities available to you for quickly connecting existing application code to another Nym process.
If you've already gone through the different options and had a look at the tutorials, you have seen the possibilities available to you for quickly connecting existing application code to another Nym process.
Below are a resources that will be useful for either beginning to integrate mixnet functionality into existing application code or build a new app using Nym.
@@ -7,8 +7,6 @@ Below are a resources that will be useful for either beginning to integrate mixn
- The [integrations FAQ](../faq/integrations-faq.md) has a list of common questions regarding integrating with Nym and Nyx, as well as commonly required links.
- To get an idea of what is possible / has already been built, check the [community applications and resources](../community-resources/community-applications-and-guides.md) page, as well as the [developer tutorials codebase](https://github.com/nymtech/developer-tutorials).
> If you wish to integrate with the Nyx blockchain to use `NYM` for payments, start with the [payment integration](./payment-integration.md) page.
@@ -1,5 +0,0 @@
# Chat demo (webapp)
You can find a browser-based 'hello world' chat app [here](https://chat-demo.nymtech.net).
Either open in two browser windows and send messages to yourself, or share with a friend and send messages to each other through the mixnet.
@@ -1,5 +0,0 @@
# Coconut Credential Playground (webapp)
There is a coconut-scheme based Credential Library playground [here](https://coco-demo.nymtech.net/). This is a WASM implementation of our Coconut libraries which generate raw Coconut credentials. Test it to create and re-randomize your own credentials.
For more information on what is happening here check out the [Coconut docs](https://nymtech.net/docs/coconut.html).
@@ -1,22 +0,0 @@
# NymConnect Beta (GUI)
NymConnect is a one-button GUI application that wraps around the `nym-socks5-client` for proxying application traffic through the Mixnet.
You can watch our video on getting started with NymConnect:
<iframe width="700" height="400" src="https://www.youtube.com/embed/quj8H2qeOwY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
Install NymConnect and select an application that you want to privacy-enhance from the dropdown menu. For now, NymConnect can be used with Electrum Wallet, Keybase, desktop Telegram and Blockstream Green. Configure these to run via a SOCKS5 proxy and send their data through the Nym mixnet!
**Please note that NymConnect is currently released in beta. Please report bugs via Github**.
## Usage instuctions
* [Download](https://github.com/nymtech/nym/releases/) and install NymConnect.
* Select your service provider from the dropdown menu.
* Click `connect` - NymConnect will connect to a service provider and its SOCKS Proxy (IP) and Port will be displayed.
* Click on IP or Port to copy their values to the clipboard.
* Go to your app settings and look for the network/proxy settings. Select `running via SOCKS5 proxy` and paste the IP and Port values given by NymConnect.
Your traffic from that application will now run through the mixnet for privacy and unlinkability!
@@ -1,7 +0,0 @@
# Overview
There are multiple options to quickly connect to Nym and play with both the mixnet and credentials on the Sandbox testnet.
At most, these involve running Nym as a second process alongside an existing application in order to send traffic through the mixnet, most are either interact webpages or a standalone app.
If you've already covered the information in this section, or want to jump straight into integrating/ a Nym connection into an existing application, head to the [Integrations](../integrations/integration-options.md) section.
@@ -1,9 +1,9 @@
# Coconut credential generation
The following code shows how you can use the SDK to create and use a [credential](../../../bandwidth-credentials.md) representing paid bandwidth on the Sandbox testnet.
The following code shows how you can use the SDK to create and use a credential representing paid bandwidth on the Sandbox testnet.
```rust,noplayground
{{#include ../../../../../../sdk/rust/nym-sdk/examples/bandwidth.rs}}
```
You can read more about Coconut credentials (also referred to as `zk-Nym`) [here](../../../coconut.md).
You can read more about Coconut credentials (also referred to as `zk-Nym`) [here](https://nymtech.net/docs/coconut.md).
@@ -1,13 +1,7 @@
# Anonymous Replies with SURBs (Single Use Reply Blocks)
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.
The number of SURBs is set [here](https://github.com/nymtech/nym/blob/master/sdk/rust/nym-sdk/src/mixnet/client.rs#L33).
```rust,noplayground
{{#include ../../../../../../sdk/rust/nym-sdk/src/mixnet/client.rs:33}}
```
You can read more about how SURBs function under the hood [here](../../../architecture/traffic-flow.md#private-replies-using-surbs).
You can read more about how SURBs function under the hood [here](https://nymtech.net/docs/architecture/traffic-flow.md#private-replies-using-surbs).
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:
@@ -1,4 +1,4 @@
# Typescript SDK
The Typescript SDK allows developers to start building browser-based mixnet applications quickly, by simply importing the SDK into their code via NPM as they would any other Typescript library.
> If you'd like to learn more, build apps or integrate Nym components using the TS SDK, please visit the **dedicated [TS SDK Handbook](https://sdk.nymtech.net/)** !
If you'd like to learn more, build apps or integrate Nym components using the TS SDK, visit the dedicated [TS SDK Handbook](https://sdk.nymtech.net/).
@@ -0,0 +1,11 @@
# Stub: Updates Coming Soon!
There is a lot of development work ongoing with our clients; as such the old tutorials that were here got quite out of date.
However, you can still access the old [tutorial codebases](https://github.com/nymtech/developer-tutorials) as well as the markdown files in the `tutorial-archives/` directory in the [developer portal docs repo](https://github.com/nymtech/nym/tree/develop/documentation/dev-portal/src/tutorials) if you want.
More up to date tutorials will be coming soon for using RPC and gRPC, `mixfetch`, as well as using the [FFI libraries](https://github.com/nymtech/nym/tree/develop/sdk/ffi) for interacting with the Mixnet via C++ and Go.
> Developers who are searching for example code can use the following list as the current 'best practices':
> * Generic traffic transport: the [`zcash-rpc-demo`](https://github.com/nymtech/nym-zcash-rpc-demo) repo, although here used to only pipe RPC traffic, is a proof of concept 'generic' mixnet piping example which exposes a TPC Socket on the client side for incoming traffic, pipes this through the mixnet, and then streams TCP packets 'out' the other side.
> * In-browser usage: see the [browser examples](../examples/browser-only.md) page for examples using `mixFetch`.
@@ -1,55 +0,0 @@
# Preparing Your Client pt2
Open `src/client.rs`. This is where the logic of the command from the `match` statement in `bin/client.rs` is defined.
# Dependencies
```rust
use crate::{handle_response, wait_for_non_empty_message, RequestTypes, DEFAULT_VALIDATOR_RPC};
use cosmrs::AccountId;
use nym_sdk::mixnet::MixnetClient;
use nym_sphinx_addressing::clients::Recipient;
use nym_validator_client::nyxd::Coin;
```
As well as importing message-handling functionality, request types, and the default RPC endpoint, this file relies on the `AccountId` type to construct blockchain addresses, the `MixnetClient` for interacting with the mixnet, the `Recipient` type to construct mixnet recipient addresses, and the `Coin` type for properly handling the returned balance of the account that will be queried.
# Querying via the Mixnet
The following is used to construct a `BalanceRequest`, send this to the supplied `service` address, and then handle the response, matching it to a `ResponseType` (in this case the only expected response, a `BalanceResponse`).
The actual sending of the request is performed by `client.send_message`: sending the serialised `BalanceRequest` to the supplied Nym address (the `Recipient` imported from the `nym_sphinx_addressing` crate). It is sending the default number of SURBs along with the message as the third argument, defined [here](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/src/mixnet/client.rs#L34).
```rust
pub async fn query_balance(
account: AccountId,
client: &mut MixnetClient,
sp_address: Recipient,
) -> anyhow::Result<Coin> {
// construct balance request
let message = RequestTypes::Balance(crate::BalanceRequest {
validator: DEFAULT_VALIDATOR_RPC.to_owned(), // rpc endpoint for broadcaster to use
account,
});
// send serialised request to service via mixnet
let _ = client
.send_message(sp_address, message.serialize(), Default::default())
.await;
let received = wait_for_non_empty_message(client).await?;
// listen for response from service
let sp_response = handle_response(received)?;
// match JSON -> ResponseType
let res = match sp_response {
crate::ResponseTypes::Balance(response) => {
println!("{:#?}", response);
response.balance
}
};
Ok(res)
}
```
That is all the client code written: now to move on to the `service` that will be interacting with the blockchain on behalf of the `client`.
@@ -1,79 +0,0 @@
# Preparing Your Client
Start by creating the startup logic of your `client` in `bin/client.rs` - creating a Nym client and connecting to the mixnet (or just connecting if your client has been started before and config already exists for it), and defining and running commands.
## Dependencies
Import the following dependencies:
```rust
use clap::{Args, Parser, Subcommand};
use chain_query::{client::query_balance, create_client};
use nym_sdk::mixnet::Recipient;
use nym_validator_client::nyxd::AccountId;
use nym_bin_common::logging::setup_logging;
```
`clap` is used so different commands can be passed to the `client` (even though we're only defining one function in this first part of the tutorial, more will be added in subsequent chapters). `nym_sdk::mixnet::Recipient` is the type used to define the recipient of a mixnet message, `nym_bin_common::logging::setup_logging` is the logging setup for `client`'s Nym client, and `chain_query` imports the `create_client` and `query_balance` functions created on the previous page.
## CLI Command with Clap
The following simply defines the commands that the client can perform. For the moment, there is only one: the `query_balance` function created in the previous section.
As with the data structures, this structure is being used for ease of adding future commands in subsequent tutorials.
```rust
#[derive(Debug, Parser)]
#[clap(name = "rust sdk demo - chain query service")]
#[clap(about = "query the sandbox testnet blockchain via the mixnet... part 2 coming soon")]
struct Cli {
#[clap(subcommand)]
command: Option<Commands>,
}
#[derive(Debug, Subcommand)]
enum Commands {
QueryBalance(QueryBalance),
}
#[derive(Debug, Args)]
struct QueryBalance {
/// the account we want to query
account: AccountId,
/// the address of the broadcaster service - this submits txs and queries the chain on our behalf
sp_address: String,
}
```
## `main()`
This is the root logic of the `client`. Using `[tokio](https://tokio.rs/)` for the async runtime, this function performs the following functions:
* If not already existing, create a Nym client with config at `/tmp/client`. Otherwise load the already existing client from this config.
* Matche the command from the CLI - in this instance, the `QueryBalance` function which will be defined in the next section. This creates a `BalanceRequest` and sends this to the `service`, before returning the response back to the main thread and print this to the console.
* Perform a proper shutdown of the Nym client.
```rust
#[tokio::main]
async fn main() -> anyhow::Result<()> {
setup_logging();
let cli = Cli::parse();
let mut client = create_client("/tmp/client2".into()).await;
let our_address = client.nym_address();
println!("\nclient's nym address: {our_address}");
match cli.command {
Some(Commands::QueryBalance(QueryBalance {
account,
sp_address,
})) => {
println!("\nsending bank balance request to service via mixnet");
let sp_address = Recipient::try_from_base58_string(sp_address).unwrap();
let returned_balance = query_balance(account, &mut client, sp_address).await?;
println!("\nreturned balance is: {}", returned_balance);
}
None => {
println!("\nno command specified - nothing to do")
}
}
println!("\ndisconnecting client");
client.disconnect().await;
println!("client disconnected");
Ok(())
}
```
@@ -1,7 +0,0 @@
# Interacting with a Cosmos SDK Blockchain via the Mixnet with the Rust SDK
This tutorial is for Rust developers wanting to interact with the Rust SDK and take a first step at building a service with which to interact with a Cosmos SDK blockchain.
The key here is to think of the service as a proxy: it interacts with the blockchain _on the client's behalf_, shielding the client from the Validator it interacts with, whilst also being shielded from the client by the mixnet.
> This service also nicely highlights the limitations of the mixnet - even though with this code your metadata is shielded from the Validator, and even the service does not know your Nym address, application-level information such as a blockchain address is not made private, in virtue of the fact that using the mixnet provides solely network-level privacy. For information on what application-level privacy Nym offers, check out the [coconut credential SDK example](https://nymtech.net/docs/sdk/rust.html#coconut-credential-generation).
@@ -1,164 +0,0 @@
# Preparing Your Lib
Now move on to preparing shared data structures and functions in `src/lib.rs`.
These include the request and response types the client and the service will be passing through the mixnet, as well as shared functions such as client creation, and message parsing.
## Dependencies
The dependencies for the shared `lib` file are the following:
```rust
use anyhow::bail;
use cosmrs::AccountId;
use nym_sdk::mixnet::{
AnonymousSenderTag, MixnetClient, MixnetClientBuilder, ReconstructedMessage, StoragePaths,
};
use nym_validator_client::nyxd::Coin;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
pub mod client;
pub mod service;
```
Since this is the file where client creation and message parsing are handled, the various `nym_sdk` imports, as well as `serde`'s (de)serialisation functionality, are required. `PathBuf` is for reading filepaths, `cosmrs` types are required for defining Nyx blockchain accounts, and the `Coin` type from the `nyxd_validator_client` is for our Coin balance request and response. `anyhow` is for easy error handing.
## Constants
Below this are the chain-related `const` variables. These have been hardcoded for this demo.
```rust
pub const DEFAULT_VALIDATOR_RPC: &str = "https://rpc.sandbox.nymtech.net";
pub const DEFAULT_DENOM: &str = "unym";
pub const DEFAULT_PREFIX: &str = "n";
```
These define the RPC endpoint your service will use to interact with the blockchain - in this case the Sandbox testnet - as well as the expected coin denomination, and Bech32-prefix of addresses.
## Shared Data Structures
Define the following structs for our different request and responses that will be serialised and sent through the mixnet between your client and service binaries:
```rust
#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub struct BalanceRequest {
pub validator: String,
pub account: AccountId,
}
#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub struct BalanceResponse {
pub balance: Coin,
}
#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub enum RequestTypes {
Balance(BalanceRequest),
}
impl RequestTypes {
pub fn serialize(&self) -> Vec<u8> {
serde_json::to_vec(self).expect("serde failure")
}
pub fn try_deserialize<M: AsRef<[u8]>>(raw: M) -> anyhow::Result<Self> {
serde_json::from_slice(raw.as_ref()).map_err(Into::into)
}
}
#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub enum ResponseTypes {
Balance(BalanceResponse),
}
impl ResponseTypes {
pub fn serialize(&self) -> Vec<u8> {
serde_json::to_vec(self).expect("serde failure")
}
pub fn try_deserialize<M: AsRef<[u8]>>(raw: M) -> anyhow::Result<Self> {
serde_json::from_slice(raw.as_ref()).map_err(Into::into)
}
}
```
The above data types are pretty straightforward. Even though there are only one instance of a request type (sent from `client` -> mixnet -> `service`) and one of a response type (`service` -> mixnet -> `client`) so far, a pair of enums has been defined to contain additional response and request types that will be added in part 2 of this tutorial, when adding credential functionality.
`BalanceRequest` will be used when requesting the service to query the token balance of the supplied address on the client's behalf. You can see the information that will be returned from the chain to the service, and from the service to the client, in `BalanceResponse`.
Custom serialistion and deserialisation have been implemented for each enum for ease of future modification and testing.
## Shared Functions
Now to define functions shared by the `client` and `service` binaries.
### Client Creation
The following function is called on startup by each binary, with the `config_path` being a filepath for storing client config:
```rust
// create our client with specified path for key storage
pub async fn create_client(config_path: PathBuf) -> MixnetClient {
let config_dir = config_path;
let storage_paths = StoragePaths::new_from_dir(&config_dir).unwrap();
let client = MixnetClientBuilder::new_with_default_storage(storage_paths)
.await
.unwrap()
.build()
.unwrap();
client.connect_to_mixnet().await.unwrap()
}
```
If no config files exist at the location designated by `config_path` (in this case `/tmp/service`) then the following files are generated:
```sh
service
├── 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
```
> If keys and config already exist at this location, re-running this function **will not** overwrite them.
### Listening for & Parsing Incoming messages
Next to define two functions: one for listening _for_ messages from the mixnet (used by `service`), and one for handling a _response_ to a request (used by `client`).
Both functions attempt to deserialise the vec of `ReconstructedMessages` that are reconstructed by the client from delivered Sphinx packets after decryption.
`handle_request` performs one additional function - parsing the `sender_tag` from the incoming reconstructed message. This is the randomised alphanumeric string used to identify a bucket of _SURBs_ (Single Use Reply Blocks) that are sent along with any outgoing message by default. More information about them can be found [here](https://nymtech.net/docs/architecture/traffic-flow.html#private-replies-using-surbs) but all that is necessary to know for now is that these are pre-addressed packets that clients send out with their messages. Any reply to their message that is to be sent back to them back be written to the payload of these packets, but without the replying party being able to see the destination that the reply is being sent to. This allows for services to **anonymously reply to clients without being able to doxx them by knowing their Nym address**.
```rust
pub fn handle_response(message: ReconstructedMessage) -> anyhow::Result<ResponseTypes> {
ResponseTypes::try_deserialize(message.message)
}
pub fn handle_request(
message: ReconstructedMessage,
) -> anyhow::Result<(RequestTypes, Option<AnonymousSenderTag>)> {
let request = RequestTypes::try_deserialize(message.message)?;
Ok((request, message.sender_tag))
}
```
Before moving on to the `client` and `service` code, one more function is needed. This allows for both binaries to parse empty incoming messages that they might receive. This is necessary as incoming SURBs, as well as requests for more SURBs, contain empty data fields.
```rust
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")
}
```
@@ -1,29 +0,0 @@
# Tutorial Overview
This tutorial involves writing two pieces of code in Rust:
- A client side binary used to construct a blockchain query and send this query to a service, which will query the Cosmos SDK blockchain and then pass the response back to the client (bear in mind this principle works for all blockchains - we're just utilising the `cosmrs` library to interact with the Sandbox testnet blockchain in this tutorial). This query will be to query the balance of an account, in preparation for spending these tokens on a [bandwidth credential](https://nymtech.net/docs/bandwidth-credentials.html) in a subsequent tutorial.
- A service which will listen out for requests from the mixnet, act on those requests, and anonymously reply to the client sending the requests.
You will learn how to do the following with the Rust SDK:
- Create clients with manual storage settings.
- Parse incoming traffic from the mixnet and reply anonymously using [SURBs](https://nymtech.net/docs/architecture/traffic-flow.html#private-replies-using-surbs).
> Services usually run on remote servers to assure reliable uptime and to unlink sender and receiver metadata. For demonstration purposes however, you will run both components on your local machine, looping messages through the mixnet to yourself.
You can find the code for these components [here](https://github.com/nymtech/developer-tutorials). You can use it as a reference while building or simply download it and follow along as you progress through the tutorial.
Notice that this tutorial attempts to use very few external libraries. This tutorial is not showing you how to build production-grade code, but **to understand how to connect and send messages to, as well as receive messages from, the mixnet.**
```admonish note title="Sidenote: What is a Service / Service Provider?"
'Service' or 'Service Provider' are catchall names used to refer to any type of app that can communicate with the mixnet via a Nym client - in this case, one embedded in its app process via the Rust SDK.
The first SP to have been released is the [Network Requester](https://nymtech.net/docs/nodes/network-requester-setup.html) - a binary that receives a network request from the mixnet, performs that request (e.g. authenticating with a message server and receiving new messages for a user) and then passes the response back to the user who requested it anonymously, shielding their metadata from the message server.
The SP you will build in this tutorial is far more simple than this, showing you how to approach building something that can:
* connect to the mixnet,
* listen for messages, and
* perform some action with them - in this case, query a Cosmos SDK blockchain.
However, once you see how easy it is to integrate with the mixnet for traffic transport, you will be able to build apps with real-world uses easily.
```
@@ -1,62 +0,0 @@
# Preparing Your Environment
## Prerequisites
* `Rust` & `cargo`
## Creating your Project Structure
* Make a new cargo project:
```
cargo new nym-cosmos-service
```
* Create the following directory structure and files:
```
.
├── Cargo.toml
├── bin
│   ├── client.rs
│   └── service.rs
└── src
├── client.rs
├── lib.rs
└── service.rs
3 directories, 6 files
```
* Add the following dependencies to your `Cargo.toml` file:
```
[dependencies]
clap = { version = "4.0", features = ["derive"] }
cosmrs = "=0.15.0"
tokio = { version = "1.24.1", features = ["rt-multi-thread", "macros"] }
serde = "1.0.152"
serde_json = "1.0.91"
anyhow = "1.0.72"
```
These are non Nym-specific dependencies for the project. `clap` is for setting up the CLI commands, `cosmrs` for cosmos-specific types and functionality, `tokio` for the async/await environment, and `serde` for (de)serialisation. `anyhow` is for catch-all error handling.
* Next add Nym-specific dependencies. Since these libraries are not yet on [crates io](https://crates.io) then you need to import them from the Nym monorepo:
```
nym-sdk = { git = "https://github.com/nymtech/nym", rev = "85a7ec9f02ca8262d47eebb6c3b19d832341b55d" }
nym-sphinx-addressing = { git = "https://github.com/nymtech/nym", rev = "85a7ec9f02ca8262d47eebb6c3b19d832341b55d" }
nym-validator-client = { git = "https://github.com/nymtech/nym", rev = "85a7ec9f02ca8262d47eebb6c3b19d832341b55d" }
nym-bin-common = { git = "https://github.com/nymtech/nym", rev = "85a7ec9f02ca8262d47eebb6c3b19d832341b55d" }
nym-sphinx-anonymous-replies = { git = "https://github.com/nymtech/nym", rev = "85a7ec9f02ca8262d47eebb6c3b19d832341b55d" }
```
The `sphinx` dependencies are for packet- and address-related functionality, the `validator-client` for Nyx blockchain specific configs, `common` for client logging, and the `sdk` for SDK functionality: creating and managing client storage and connections, and sending and receiving messages to and from the mixnet.
* Finally add the following underneath your `[dependencies]`:
```
[[bin]]
name = "client"
path = "bin/client.rs"
[[bin]]
name = "service"
path = "bin/service.rs"
```
This defines multiple binaries to run in a single cargo project, as outlined [here](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#binaries).
@@ -1,43 +0,0 @@
# Querying the Chain
Now that all the code has been written, time to query the blockchain.
To test against the account operating one of the mix nodes on the testnet, use `n1lcutqz94k739s39u26rvexql40ehf42zd27fwe` in the following instructions:
```sh
# build the binaries
cargo build --release
# open two console windows. In one run the following
./target/release/service
# copy the printed Nym address from the console - this is used by the client when running the chain query
# in the other run
./target/release/client query-balance n1lcutqz94k739s39u26rvexql40ehf42zd27fwe <SERVICE_ADDRESS_FROM_CLIPBOARD>
```
The following happens:
* `client` and `service` both start their Nym clients and log the address. `service` is listening for incoming messages from the mixnet.
* `client` sends a request to `service` using the supplied `n1...` address as the Nyx account to query the balance of, and the supplied Nym address to communicate with this instance of `service`.
* `service` queries the Sandbox testnet blockchain using the `broadcaster` http client. It then serialises the response and returns it using SURBs to the `client`.
All in all, quite simple. By using the service as a proxy, the client never interacts with the blockchain, thus is not revealing metadata to the operator of the Validator nor any entities monitoring its incoming and outgoing traffic. Furthermore, the client doesn't even need to share its Nym address with the service, as the service is able to reply via SURBs.
## Creating Sandbox Account
If you wish to create an account on Sandbox to use instead of the supplied account above, the easiest way is by building the `nym-cli` tool and using that to create one:
```sh
# start from the root of the nym monorepo
cd tools/nym-cli
# build
cargo build --release
# create account using Sandbox testnet environment
../../target/release/nym-cli --config-env-file ../../envs/sandbox.env account create
```
However, since this account is fresh, it won't have any tokens. Querying the balance will still work obviously, it will just return `0`.
## Get Tokens
We're working on getting the faucet up and running again in preparation for part 2 of this tutorial: using the tokens you have privately checked the balance of to generate a [bandwidth credential](https://nymtech.net/docs/bandwidth-credentials.html).
If you wish to get testnet tokens already then feel free to ask in the [Dev channel](https://matrix.to/#/#dev:nymtech.chat) on Matrix.
@@ -1,45 +0,0 @@
# Preparing Your Service pt2
Now to define the logic of creating the `broadcaster` for interacting with the blockchain, and querying it in `src/service.rs`.
## Dependencies
The following dependencies are for creating a client to interact with the blockchain, and deal with the returned `Coin` type in `BalanceResponse`.
```rust
use crate::{BalanceResponse, DEFAULT_DENOM, DEFAULT_VALIDATOR_RPC};
use cosmrs::rpc::HttpClient;
use cosmrs::AccountId;
use nym_validator_client::nyxd::{Coin, CosmWasmClient};
```
## Creating a `broadcaster`
The `broadcaster` is an `HttpClient` taken from `cosmrs`, created with the `DEFAULT_VALIDATOR_RPC` as its default endpoint. The service will use this to query the Sandbox testnet chain.
```rust
pub async fn create_broadcaster() -> anyhow::Result<HttpClient> {
let broadcaster: HttpClient = HttpClient::new(DEFAULT_VALIDATOR_RPC)?;
Ok(broadcaster)
}
```
## Querying the Chain
Now to write the logic for querying the chain, using the `broadcaster` created in the previous step to query for the balance of the `account` that the client sent via the mixnet in the `BalanceRequest`. This function returns a `BalanceResponse` containing a `Coin` type, denoting the `balance` and `denom` returned by `get_balance()`.
```rust
pub async fn get_balance(
broadcaster: HttpClient,
account: AccountId,
) -> anyhow::Result<BalanceResponse> {
let balance = broadcaster
.get_balance(&account, DEFAULT_DENOM.to_string())
.await
.unwrap()
.unwrap();
Ok(BalanceResponse {
balance: Coin {
amount: balance.amount,
denom: balance.denom,
},
})
}
```
@@ -1,72 +0,0 @@
# Preparing Your Service
In `bin/src.rs` define the startup and response logic of the `service`. Client connection / config reading happens as it does in `bin/client.rs`.
## Dependencies
```rust
use chain_query::{
create_client, handle_request,
service::{create_broadcaster, get_balance},
BalanceResponse, RequestTypes, ResponseTypes,
};
use nym_sphinx_anonymous_replies::{self, requests::AnonymousSenderTag};
use nym_bin_common::logging::setup_logging;
use nym_sdk::mixnet::MixnetMessageSender;
```
The imports from `chain_query` are most of the data types and functions defined in the previous sections of this tutorial.
The `AnonymousSenderTag` type is used for SURBs.
## main()
Also using tokio for the async runtime, `main` does the following:
* Create a Nym client with config at `/tmp/service`, or load the existing client from this config directory.
* Create a `broadcaster` - this is used by the service to interact with the blockchain, using the consts defined in `src/lib.rs` as chain config.
* Listen out for incoming messages, and in much the same way as the `client`, handle and match the incoming request.
* Using the `sender_tag`, anonymously reply to the `client` with the response from the blockchain **without having to know the client's Nym address**.
```rust
#[tokio::main]
async fn main() -> anyhow::Result<()> {
setup_logging();
let mut client = create_client("/tmp/service".into()).await;
let our_address = client.nym_address();
println!("\nservice's nym address: {our_address}");
// the httpclient we will use to broadcast our query to the blockchain
let broadcaster = create_broadcaster().await?;
println!("listening for messages, press CTRL-C to exit");
while let Some(received) = client.wait_for_messages().await {
for msg in received {
let request = match handle_request(msg) {
Ok(request) => request,
Err(err) => {
eprintln!("failed to handle received request: {err}");
continue;
}
};
let return_recipient: AnonymousSenderTag = request.1.expect("no sender tag received");
match request.0 {
RequestTypes::Balance(request) => {
println!("\nincoming balance request for: {}\n", request.account);
let balance: BalanceResponse =
get_balance(broadcaster.clone(), request.account).await?;
let response = ResponseTypes::Balance(balance);
println!("response from chain: {:#?}", response);
println!("\nreturn recipient surb bucket: {}", &return_recipient);
println!("\nsending response to {}", &return_recipient);
// send response back to anon requesting client via mixnet
let _ = client
.send_reply(return_recipient, &serde_json::to_string(&response)?)
.await;
}
}
}
}
Ok(())
```
@@ -1,36 +0,0 @@
# Electrum Wallet NymConnect Integration
Electrum is one of the most favorite Bitcoin wallet for desktop users and it is used as a backend wallet for various crypto aplications in smart phones. Electrum was among the first integrations of Nym. This easy setup allows users to enhance privacy when managing the flagship of blochain cryptocurencies Bitcoin.
## How can I use Bitcoin over the Nym mixnet?
> Any syntax in `<>` brackets is a users unique variable. Exchange with a corresponding name without the `<>` brackets.
### NymConnect Installation
NymConnect application is for everyone who does not want to install and run `nym-socks5-client`. NymConnect is plug-and-play, fast and easy use. Electrum Bitcoin wallet, Monero wallet (desktop and CLI) and Matrix (Element app) connects through NymConnect automatically to the Mixnet.
1. [Download](https://nymtech.net/download/nymconnect) NymConnect
2. On Linux and Mac, make executable by opening terminal in the same directory and run:
```sh
chmod +x ./nym-connect_<VERSION>
```
3. Start the application
4. Click on `Connect` button to initialise the connection with the Mixnet
5. Anytime you'll need to setup Host and Port in your applications, click on `IP` and `Port` to copy the values to clipboard
6. In case you have problems such as `Gateway Issues`, try to reconnect or restart the application
### Electrum Bitcoin wallet via NymConnect
To download Electrum visit the [official webpage](https://electrum.org/#download). To connect to the Mixnet follow these steps:
7. Start and connect [NymConnect](./electrum.md#nymconnect-installation) (or [`nym-socks5-client`](https://nymtech.net/docs/clients/socks5-client.html))
2. Start your Electrum Bitcoin wallet
3. Go to: *Tools* -> *Network* -> *Proxy*
4. Set *Use proxy* to ✅, choose `SOCKS5` from the drop-down and add the values from your NymConnect application
5. Now your Electrum Bitcoin wallet runs through the Mixnet and it will be connected only if your NymConnect or `nym-socks5-client` are connected.
![Electrum Bitcoin wallet setup](../images/electrum_tutorial/electrum.gif)
@@ -1,36 +0,0 @@
# Firo-Electrum Wallet NymConnect Integration
[Firo](https://github.com/firoorg/firo#firo) (formerly Zcoin) is a privacy focused, zk-proof based cryptocurrency. Now users can enjoy Firo with network privacy by Nym as Firo's fork of Electrum wallet was integrated to work behind the Mixnet. Read more about Firo on their [official webpage](https://firo.org/).
## How can I use Firo over the Nym Mixnet?
> Any syntax in `<>` brackets is a users unique variable. Exchange with a corresponding name without the `<>` brackets.
### NymConnect Installation
NymConnect application is for everyone who does not want to install and run `nym-socks5-client`. NymConnect is plug-and-play, fast and easy use. Electrum Bitcoin wallet, Monero wallet (desktop and CLI) and Matrix (Element app) connects through NymConnect automatically to the Mixnet.
1. [Download](https://nymtech.net/download/nymconnect) NymConnect
2. On Linux and Mac, make executable by opening terminal in the same directory and run:
```sh
chmod +x ./nym-connect_<VERSION>
```
3. Start the application
4. Click on `Connect` button to initialise the connection with the Mixnet
5. Anytime you'll need to setup Host and Port in your applications, click on `IP` and `Port` to copy the values to clipboard
6. In case you have problems such as `Gateway Issues`, try to reconnect or restart the application
### Firo Electrum wallet via NymConnect
To download Firo Electrum wallet visit the [Firo's repository](https://github.com/firoorg/firo) or [Github release page](https://github.com/firoorg/electrum-firo/releases/tag/4.1.5.2). To connect to the Mixnet follow these steps:
7. Start and connect [NymConnect](./firo.md#nymconnect-installation) (or [`nym-socks5-client`](https://nymtech.net/docs/clients/socks5-client.html))
8. Start your Firo Electrum wallet
9. Go to: *Tools* -> *Network* -> *Proxy*
10. Set *Use proxy* to ✅, choose `SOCKS5` from the drop-down and add the values from your NymConnect application
11. Now your Firo Electrum wallet runs through the Mixnet and it will be connected only if your NymConnect or `nym-socks5-client` are connected.
![Firo Electrum wallet setup](../images/firo_tutorial/firo.png)
@@ -1,89 +0,0 @@
# Matrix NymConnect Integration
![](../images//matrix.png)
Chat applications became an essential part of human communication. Matrix chat has end to end encryption on protocol level and Element app users can sort their communication into spaces and rooms. Now the Matrix communities can rely on network privacy as NymConnect supports Matrix chat protocol.
Currently there is no option in Matrix's Element client to set a Socks5 proxy. In order to use Element via NymConnect users have to start it from the command-line. The setup is simple, for convenience a keyboard shortcut setting or terminal alias can be easily done.
## Setup & Run
Make sure you have installed and started **[NymConnect](https://nymtech.net/developers/quickstart/nymconnect-gui.html)** on your desktop.
To then start Matrix's Element client via a Socks5 proxy connected to NymConnect, open terminal and run:
**Linux**
```sh
element-desktop --proxy-server=socks5://127.0.0.1:1080
```
**Mac**
```sh
open -a Element --args --proxy-server=socks5://127.0.0.1:1080
```
## Optimise setup with a keybinding / alias
### Keybinding
An eloquent solution to avoid entering a command every time is to setup your keybinding. Open your settings, navigate to `Keyboard Shortcuts` and choose to `Set Custom Shortcut`. `Name` and `Shortcut` fields are up to your preference, to the `Command` line add:
```sh
element-desktop --proxy-server=socks5://127.0.0.1:1080
```
Make sure your `Shortcut` isn't already taken by something else in the menu.
An example can look like this.
![](../images/element_nym_keybind.png)
Alternatively you can add a keybinding via the CLI, using whatever config files you edit for your given desktop environment / window manager.
### Create an alias
If you prefer to simply shorten the length of the command (or all your keybindings are already taken) then you can simply create an alias for this long-winded command (this example aliases that command to the single word `element`, but you can replace it with whatever you like):
**Linux**
```sh
alias element="element-desktop --proxy-server=socks5://127.0.0.1:1080"
```
To make this alias persist, then add this to your `.bashrc` or `.zshrc` file (usually located in your `$HOME` directory) and `source` that file. This can be done by appending the alias command directly to the shell config file with one command.
For `bash` enter:
```sh
alias element="element-desktop --proxy-server=socks5://127.0.0.1:1080" >> ~/.bashrc
```
For `zsh` enter:
```sh
alias element="element-desktop --proxy-server=socks5://127.0.0.1:1080" >> ~/.zshrc
```
You can add the alias manually by opening your `$HOME` directory, enable hidden files (press `ctrl` + `h`) and open `.bashrc` or `.zshrc` file (based on your terminal setup) in a text editor, paste the string `alias element="element-desktop --proxy-server=socks5://127.0.0.1:1080"` to the the end, save and exit. Start a new terminal and run `element`.
**Mac**
```sh
alias element="open -a Element --args --proxy-server=socks5://127.0.0.1:1080"
```
To make this alias persist, then add this to your `.zshrc` (or `.bashrc`/`.profile`) file (usually located in your `$HOME` directory) and `source` that file. This can be done by appending the alias command directly to the shell config file with one command.
For `zsh` enter:
```sh
alias element="open -a Element --args --proxy-server=socks5://127.0.0.1:1080" >> ~/.zshrc
```
For `.bashrc` or `.profile` just change the end of the command.
You can add the alias manually by opening your `$HOME` directory, enable hidden files (in Finder press `Shift` + `Command` + `.`) and open `.zshrc` file (or `.bashrc`/`.profile`) in a text editor, paste the string `alias element="open -a Element --args --proxy-server=socks5://127.0.0.1:1080"` to the the end, save and exit. Start a new terminal and run `element`.
**Now you can run Element through the Nym Mixnet with a single-word command.**
@@ -1,44 +0,0 @@
# Monero NymConnect Integration
*New Nym mixnet integration launched for Monero desktop to secure the right to financial privacy and censorship-resistance*
![](../images/monero_tutorial/monero.png)
Financial privacy is an important component of digital currencies and the use of Nym will provide users with the highest level of privacy at the infrastructure level. All users of digital currencies should be afforded equal rights to protection from financial surveillance.
A team made up of Monero community members have successfully set up a service provider to use Monero (using the Monero desktop wallet) over the Nym mixnet. This allows Monero users to easily use NymConnect to run Monero over the mixnet, thereby enhancing the privacy of Monero transactions.
## How can I use Monero over the Nym mixnet?
> Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets.
The mainnet service provider to Monero over the Nym mixnet is now ready for use via [NymConnect](https://nymtech.net/download-nymconnect/).
* **Download** the latest version of [**NymConnect**](https://nymtech.net/download-nymconnect/).
* Make sure your NymConnect is executable.
```sh
# in Linux open terminal in the same folder and run:
chmod +x ./nym-connect_<YOUR_VERSION>.AppImage
```
* **Open NymConnect app**
* **Turn it on** - Monero wallet is listed in the apps supported by default, no need for any setup
* **Copy** the **Socks5 address** and **Port**
Then go to your Monero wallet (desktop or CLI) and change the settings to run over socks5 proxy:
**Monero desktop wallet:**
* Settings -> Interface -> Socks5 proxy -> Add values: IP address `127.0.0.1`, Port `1080` (the values copied from NymConnect)
<!---commenting the video as it has a redundant part about manual NR setup
<iframe width="700" height="400" src="https://www.youtube.com/embed/oSHnk1BG_f0" title="Demo: Connect Your Monero Wallet to the Nym Mixnet via NymConnect" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
--->
**CLI wallet**
* **Monerod:** add `--proxy 127.0.0.1:1080 --bootstrap-daemon-proxy 127.0.0.1:1080` to args
* **Monero-wallet-{rpc, cli}:** add `--proxy 127.0.0.1:1080 --daemon-ssl-allow-any-cert` to args
For those who want to try it out in testnet, a stagenet service provider is also available: [https://nymtech.net/.wellknown/connect/service-providers.json](https://nymtech.net/.wellknown/connect/service-providers.json)
Now your Monero traffic is protected by the network privacy of Nym Mixnet.
@@ -1,5 +0,0 @@
# Rust SDK
The Rust SDK allows developers building applications in Rust to import and interact with Nym clients as they would any other dependency, instead of running the client as a seperate process on their machine.
[Read the docs](https://nymtech.net/docs/sdk/rust/rust.html).
@@ -1,70 +0,0 @@
# Tutorial Overview
## Components Created in this Tutorial
This tutorial involves writing two pieces of code in Typescript:
- A **User Client** (UC) with which you can access the mixnet through a browser on your local machine. You will use this to communicate with the second component outlined below.
- A **Service Provider** (SP) which can communicate with the UC via the mixnet.
Additionally you will learn how to configure a pair of **Nym Websocket Clients** which both components use to connect to and communicate with the Mixnet.
> SPs usually run on remote servers to assure reliable uptime and to unlink sender and receiver metadata. For demonstration purposes however, you will run both components on your local machine, looping messages through the mixnet to yourself.
```
+----------+ +----------+ +----------+
| Mix Node |<-----------> | Mix Node |<----------->| Mix Node |
| Layer 1 | | Layer 2 | | Layer 3 |
+----------+ +----------+ +----------+
^ ^
| |
|<--------------------------------------------------+
|
v
+--------------+
| Your gateway |
+--------------+
^
|
|
v
+-------------------------------------------+
| |
| +------------+ +------------+ |
| | Nym Client | | Nym Client | |
| +------------+ +------------+ |
| ^ ^ |
| | | |
| | | |
| v v |
| +-------------+ +------------------+ |
| | User Client | | Service Provider | |
| +-------------+ +------------------+ |
| |
+-------------------------------------------+
Your Local Machine
```
## Aims of this Tutorial
* Create a user-friendly experience for sending data through the mixnet via a simple form accessible through a web browser.
* Configure and use a pair of Nym Websocket Clients.
* Send a properly formatted message through the mixnet to the SP from a browser-based GUI.
You can find the code for these components [here](https://github.com/nymtech/developer-tutorials). You can use it as a reference while building or simply download it and follow along as you progress through the tutorial.
Notice that this tutorial attempts to use very few external libraries (the User Client codebase is basically vanilla Typescript!). This tutorial is not showing you how to build production-grade code, but **to understand how to connect and send messages to, as well as recieve messages from, the mixnet.**
```admonish note title="Sidenote: What is a Service Provider?"
'Service Provider' is a catchall name used to refer to any type of app that can communicate with the mixnet via a Nym client.
The first SP to have been released is the [Network Requester](https://nymtech.net/docs/nodes/network-requester.html) - a binary that receives a network request from the mixnet, performs that request (e.g. authenticating with a message server and receiving new messages for a user) and then passes the response back to the user who requested it anonymously, shielding their metadata from the message server.
The SP you will build in this tutorial is far more simple than this. It is just to show you how to approach building something that can:
* connect to the mixnet,
* listen for messages, and
* perform some action with them (in this case, log them in a console and reply to the original sender).
However, once you see how easy it is to integrate with the mixnet for traffic transport, you will be able to build apps with real-world uses easily.
```
@@ -1,118 +0,0 @@
# Preparing Your User Client Environment
## Prerequisites
* `NodeJS` & `npm`
* `typescript`
## Preparing your TypeScript environment
* Make a new directory called `simple-service-provider-tutorial` containing a directory named `user-client`:
```
mkdir -p simple-service-provider/user-client
```
* Create a `package.json` and install dependencies:
```
cd simple-service-provider/user-client
npm init
npm install typescript # allows you to write and use typescript
npm install ts-node --save-dev # allows you to build a typescript application in a NodeJS environment
```
* Create a `tsconfig.json` containing the following:
```json
{
"compilerOptions": {
"module": "commonjs",
"esModuleInterop": true,
"target": "es6",
"moduleResolution": "node",
"sourceMap": true,
"outDir": "dist"
},
"lib": ["es2015"]
}
```
## Preparing your Bundler
* We will use the [`Parcel`](https://parceljs.org/getting-started/webapp/) bundler to build and run our app locally. `Parcel` also supports hot reloading, making for a nicer developer experience when working on our app. Install it with:
```
npm install parcel-bundler
```
* Create the file structure for our frontend code:
```
mkdir src
touch src/index.html src/index.ts
```
~~~admonish note title=""
At this point your directory should look like this (check yourself with `tree -L 2 simple-service-provider/`):
```
simple-service-provider/
└── user-client
├── node_modules
├── package.json
├── package-lock.json
├── src
└── tsconfig.json
4 directories, 3 files
```
And `user-client/src/` should look like this:
```
user-client/src
├── index.html
└── index.ts
1 directory, 2 files
```
~~~
* Time to check everything is working. Paste the following into `src/index.html`:
```
<!DOCTYPE html>
<html>
<head>
<title>App Test</title>
<meta charset="utf-8"/>
</head>
<body>
<h1>Test</h1>
<div id="app"></div>
<script src="index.ts"></script>
</body>
</html>
```
* Paste the following into `src/index.ts`
```
console.log('test log')
```
* Add the following to `package.json` in the `"scripts"` array, above `"test"`:
```
"start": "parcel src/index.html"
```
* `npm start` should return:
```
> user-client@1.0.0 start
> parcel src/index.html
Server running at http://localhost:1234
✨ Built in 1.57s.
```
Open [localhost:1234](http://localhost:1234/) in your browser. Your web application should be up and running, with `Test` displayed in the browser window. Checking the `console.log` output is done by right-clicking on the browser and selecting _Inspect_, then navigating to the _Console_ section of the resulting panel. You should see the message `test log` displayed there.
@@ -1,121 +0,0 @@
# Preparing Your Service Provider Environment
* Now to move on to prepare our development environment for the Service Provider code. Create a directory for it:
```
# run this from the root of `simple-service-provider/`
mkdir service-provider
cd service-provider
```
* Create a `package.json`:
```
npm init
```
* Inside your newly generated `package.json`, paste in the following code:
```json
{
"name": "service-provider",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start:dev": "nodemon",
"test": "echo \"Error: no test specified\" && exit 1"
},
"devDependencies": {
"@types/node": "^18.14.0",
"@types/ws": "^8.5.4",
"nodemon": "^2.0.20",
"ts-node": "^10.9.1",
"typescript": "^4.8.4"
},
"author": "",
"license": "ISC",
"dependencies": {
"ws": "^8.12.0"
}
}
```
* install dependecies:
```
npm install
```
* create a `tsconfig.json` file containing the following:
```json
{
"compilerOptions": {
"target": "es2017",
"lib": [
"es6"
],
"module": "Node16",
"rootDir": "src",
"resolveJsonModule": true,
"allowJs": true,
"outDir": "build",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitAny": true,
"skipLibCheck": true
}
}
```
* You will use [Nodemon](https://www.npmjs.com/package/nodemon) to reload your app on code changes. Create a `nodemon.json` file in the same directory which will act as our `nodemon` configuration. Paste in the following code inside that file:
```json
{
"watch": [
"src"
],
"ext": ".ts,.js",
"ignore": [],
"exec": "ts-node ./src/index.ts"
}
```
* Finally, create a typescript file for our app logic:
```
mkdir src
touch src/index.ts
```
~~~admonish note title=""
At this point your directory should look like this (check yourself with `tree -L 2 simple-service-provider`):
```
simple-service-provider
├── service-provider
│   ├── node_modules
│   ├── nodemon.json
│   ├── package.json
│   ├── package-lock.json
│   ├── src
│   └── tsconfig.json
└── user-client
├── node_modules
├── package.json
├── package-lock.json
├── src
└── tsconfig.json
7 directories, 7 files
```
And `service-provider/src/` should look like this:
```
service-provider/src
└── index.ts
1 directory, 1 file
```
~~~
@@ -1,18 +0,0 @@
# Sending a Message Through the Mixnet
You are now ready to send a message through the mixnet!
You should have the following set up:
* A __User Client__ Web App
* A __Service Provider__ backend service
* 2 Nym websocket clients, one for each component above
Simply fill in the fields in your browser and click `Send`. In your browser you will see the message sent to the SP, followed by the response from the SP. In your console you will see the logged incoming message from the UC, and the reply message to itfrom the SP.
<img src="../../images/tutorial_image_5.png"/>
This small project can be used as a template to start conceptualizing and developing more complex PEApps. Stay tuned for more soon, and if you're searching for inspiration check out the [community apps](../../community-resources/community-applications-and-guides.md) list!
@@ -1,142 +0,0 @@
# Building Your Service Provider
> Since a lot of logic you will write in this section is similar or the same to UC code you just written, this section will only focus on SP-specific functionality
* Paste the following code into `src/index.ts`
```typescript
import WebSocket, { MessageEvent } from "ws";
var ourAddress: string;
var websocketConnection: any;
async function main() {
var port = '1978'
var localClientUrl = "ws://127.0.0.1:" + port;
// Set up and handle websocket connection to our desktop client.
websocketConnection = await connectWebsocket(localClientUrl).then(function (c) {
return c;
}).catch(function (err) {
console.log("Websocket connection error. Is the client running with <pre>--connection-type WebSocket</pre> on port " + port + "?");
console.log(err);
})
websocketConnection.onmessage = function (e : any) {
handleResponse(e);
};
sendSelfAddressRequest();
}
// Handle any messages that come back down the websocket.
function handleResponse(responseMessageEvent : MessageEvent) {
try {
let response = JSON.parse(responseMessageEvent.data.toString());
if (response.type == "error") {
console.log("\x1b[91mAn error occured: " + response.message + "\x1b[0m")
} else if (response.type == "selfAddress") {
ourAddress = response.address;
console.log("\x1b[94mOur address is: " + ourAddress + "\x1b[0m")
} else if (response.type == "received") {
let messageContent = JSON.parse(response.message)
console.log('\x1b[93mRecieved : \x1b[0m');
console.log('\x1b[92mName : ' + messageContent.name + '\x1b[0m');
console.log('\x1b[92mService : ' + messageContent.service + '\x1b[0m');
console.log('\x1b[92mComment : ' + messageContent.comment + '\x1b[0m');
console.log('\x1b[93mSending response back to client... \x1b[0m')
sendMessageToMixnet(response.senderTag)
}
} catch (_) {
console.log('something went wrong in handleResponse')
}
}
function sendMessageToMixnet(senderTag: string) {
// Place each of the form values into a single object to be sent.
const messageContentToSend = {
text: 'We recieved your request - this reply sent to you anonymously with SURBs',
fromAddress : ourAddress
}
const message = {
type: "reply",
message: JSON.stringify(messageContentToSend),
senderTag: senderTag
}
// Send our message object via out via our websocket connection.
websocketConnection.send(JSON.stringify(message));
}
// Send a message to the mixnet client, asking what our own address is.
function sendSelfAddressRequest() {
var selfAddress = {
type: "selfAddress"
}
websocketConnection.send(JSON.stringify(selfAddress));
}
// Function that connects our application to the mixnet Websocket. We want to call this first in our main function.
function connectWebsocket(url : string) {
return new Promise(function (resolve, reject) {
var server = new WebSocket(url);
console.log('connecting to Mixnet Websocket (Nym Client)...')
server.onopen = function () {
resolve(server);
};
server.onerror = function (err) {
reject(err);
};
});
}
main();
```
`main()` is still the function in charge of initializing and executing your application. Note that the SP's client is running on port `1978`. This is so we don't have a conflict with the client we have running for the UC part of our tutorial code!
`handleResponse()` works in a similar manner as the function with the same name in `simple-service-provider/user-client/src/index.ts`. This implementation logs to the console instead of passing messages to a UI.
The `\x1b` prefix you see in `console.log` adds colour to console ouput. The number that you see following the `[` and preceeding `m` is the colour code that can be compared [here](https://en.m.wikipedia.org/wiki/ANSI_escape_code#Colors). Its a nice and quick way of styling our terminal output.
When the SP receives a message from the mixnet, `sendMessageToMixnet()` sends a response back to notify the the user that the SP recieved their request successfully.
## Connecting to your Nym Client
* Follow instructions in the [Nym websocket client documentation](https://nymtech.net/docs/clients/websocket-client.html#initialising-your-client)to `init` and `run` a client.
```admonish caution title=""
Remember to `init` and `run` this client using port `1978` to avoid port clashes.
```
* Refresh your browser window. You should see a successful response, including a Nym address, in your console:
```
> service-provider@1.0.0 start:dev
> nodemon
[nodemon] 2.0.20
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): src/**/*
[nodemon] watching extensions: ts,js
[nodemon] starting `ts-node ./src/index.ts`
connecting to Mixnet Websocket (Nym Client)...
Our address is: 6V5eEguz4rUsfntVLKQuD2ymgdY5iDKCV2GY2EH3CxG4.AKdk22atwRaVkN2PLEDsWUKKDc3ieNm1avKqVGgmJx8s@FQon7UwF5knbUr2jf6jHhmNLbJnMreck1eUcVH59kxYE
```
## Set Service Address in User Client
The final step of this tutorial is to update our User Client code with the address of the now-running Service Provider so it can send it a message.
Copy the SP's Nym address from your console and set it as the value of the `targetAddress` variable on line 2 of `simple-service-provider/user-client/src/index.ts`.
```
var targetAddress: string = '6V5eEguz4rUsfntVLKQuD2ymgdY5iDKCV2GY2EH3CxG4.AKdk22atwRaVkN2PLEDsWUKKDc3ieNm1avKqVGgmJx8s@FQon7UwF5knbUr2jf6jHhmNLbJnMreck1eUcVH59kxYE';
```
@@ -1,42 +0,0 @@
# Building a Simple Service Provider
```admonish warning
This tutorial was written before the creation of the [Typescript SDK](https://sdk.nymtech.net), and involves running a Nym Client alongside your application processes, instead of relying on the SDK to integrate the Client process into your application logic.
As such, although this tutorial is still a valid way of approaching building on Nym, it is a little less streamlined than it could be.
A more streamlined rewrite of this tutorial will be coming soon.
```
This tutorial is the best place to start for developers new to Nym. You will learn how to build a minimum viable privacy-enabled application (PEApp) able to send and receive traffic via the mixnet.
This tutorial is less about building an immediately useful application, and more about beginning to understand:
* Sending messages through the mixnet to another Nym client
* Receiving messages from the mixnet and handling them
* Anonymous replies with Single Use Reply Blocks (SURBs)
That said, this tutorial will give you the skeleton of an application, onto which you can add more useful functionality.
@@ -1,262 +0,0 @@
# Building Your User Client
## Adding Core Functionality
Most of the work here will be configuring and adding functionality to `src/index.ts` file, allowing you to establish and handle the websocket connection to your local Nym client, and create and send messages to the SP.
* Replace the existing content of `src/index.ts` with:
```typescript
async function main() {}
function connectWebsocket(url) {
return new Promise(function (resolve, reject) {
var server = new WebSocket(url);
console.log('connecting to Websocket Server (Nym Client)...')
server.onopen = function () {
resolve(server);
};
server.onerror = function (err) {
reject(err);
};
});
}
main();
```
`main()` will the majority of the app's logic. It's best to declare it at the start of the file and call it at the end to run when launching the application.
`connectWebsocket(url)` returns a `Promise` that attempts to create a websocket connection to `url`. If the connection is successful, you will get a notification in your running application in the browser, as well as the connected Nym client. If it fails an error will be displayed in the browser.
* Now to implement the functions that will handle DOM (Document Object Model) manipulation. Add the following below `connectWebsocket()`:
```typescript
function handleResponse(resp) {
try {
let response = JSON.parse(resp.data);
if (response.type == "error") {
displayJsonResponse("Server responded with error: " + response.message);
} else if (response.type == "selfAddress") {
ourAddress = response.address;
displayClientMessage("Our address is: " + ourAddress + ", we will now send messages to ourself.");
} else if (response.type == "received") {
handleReceivedTextMessage(response)
}
} catch (_) {
displayJsonResponse(resp.data)
}
}
function handleReceivedTextMessage(message) {
const text = JSON.parse(message.message);
displayJsonResponse(text);
}
// Display websocket responses in the Activity Log.
function displayJsonResponse(message) {
let receivedDiv = document.createElement("div")
let paragraph = document.createElement("p")
paragraph.setAttribute('style', 'color: orange')
let textNode = document.createTextNode("received >>> " + message.text)
paragraph.appendChild(textNode)
receivedDiv.appendChild(paragraph)
document.getElementById("output").appendChild(receivedDiv)
}
function displayClientMessage(message) {
document.getElementById("output").innerHTML += "<p>" + message + "</p >";
}
```
`handleResponse()` parses the type of any messages received from the websocket, and handles forwarding the message on to the appropriate function depending on this `type`. You can find documentation on these types [here](https://nymtech.net/docs/clients/websocket-client.html#message-types).
`handleReceivedTextMessage()` ensures that data is `json` data before displaying on the UI.
`displayJsonResponse()` is responsible for displaying received messages on the UI, creating a new `<p>` HTML element for each message that needs to be displayed on screen.
`displayClientMessage()` displays the address of the connected Nym client.
* Declare the following variables above `main()`
```typescript
var ourAddress: string;
var targetAddress: string;
var websocketConnection: any;
```
`ourAddress` takes the value of the connected Nym client address.
`targetAddress` will be the Nym address of the SP.
`websocketConnection` populated upon a successful response from `connectWebsocket()`.
* Add the following to `main()`:
```typescript
async function main() {
var port = '1977' // Nym Websocket Client listens on 1977 by default.
var localClientUrl = "ws://127.0.0.1:" + port;
// Set up and handle websocket connection to our desktop client.
websocketConnection = await connectWebsocket(localClientUrl).then(function (c) {
return c;
}).catch(function (err) {
displayClientMessage("Websocket connection error. Is the client running with <pre>--connection-type WebSocket</pre> on port " + port + "?");
})
websocketConnection.onmessage = function (e) {
handleResponse(e);
};
sendSelfAddressRequest();
// Set up the send button
const sendButton = document.querySelector('#send-button');
sendButton?.addEventListener('click', function handleClick(event) {
sendMessageToMixnet();
});
```
And between `main()` and `displayClientMessage()`:
```typescript
function sendSelfAddressRequest() {
var selfAddress = {
type: "selfAddress"
}
displayJsonSend(selfAddress);
websocketConnection.send(JSON.stringify(selfAddress));
}
```
`sendSelfAddressRequest()` sends a `selfAddress` message to the connected websocket client, passing the response to `displayJsonSend()` to be displayed on your UI.
`main()` now contains logic for: connecting to a local Nym client, getting its address with a `selfAddress` message, and displaying it on the UI. Now your app can display its connection status, letting you know whether it is(n't) connected to a running client!
* Underneath `sendSelfAddressRequest()` implement a function to send messages down the websocket connection to the SP:
```typescript
function sendMessageToMixnet() {
var nameInput = (<HTMLInputElement>document.getElementById("nameInput")).value;
var textInput = (<HTMLInputElement>document.getElementById("textInput")).value;
const messageContentToSend = {
name : nameInput,
comment : textInput,
}
const message = {
type: "sendAnonymous",
message: JSON.stringify(messageContentToSend),
recipient: targetAddress,
replySurbs: 5
}
displayJsonSend(message);
websocketConnection.send(JSON.stringify(message));
}
```
Nym clients accept messages in either binary or JSON formats. Since you are sending JSON data, you need to `stringify` any `message`s you wish to send through the mixnet.
You are sending [replySURBs](https://nymtech.net/docs/architecture/traffic-flow.html#private-replies-using-surbs) along with the message to the SP. This allows the SP to reply to you without you having to doxx yourself and supply a 'return address' in a readable form to it. TLDR; SURBs allow for anonymous replies from mixnet services!
* Below `sendMessageToMixnet()`, add the following:
```typescript
function displayJsonSend(message) {
let sendDiv = document.createElement("div")
let paragraph = document.createElement("p")
paragraph.setAttribute('style', 'color: #36d481')
let paragraphContent = document.createTextNode("sent >>> " + JSON.stringify(message))
paragraph.appendChild(paragraphContent)
sendDiv.appendChild(paragraph)
document.getElementById("output").appendChild(sendDiv)
}
```
`displayJsonSend()` displays sent messages in the "Activity Log" section of the UI.
* Replace the contents of `src/index.html` with the following:
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Mixnet Websocket Starter Client</title>
<link rel="stylesheet" href="../assets/styles.css"/>
</head>
<body>
<div class="content" role="main">
<div class="toolbar">
<h3>Mixnet Websocket Starter User Client</h3>
</div>
<div class="section-container">
<label for="nameInput" class="form-field-label">Moniker</label>
<input id="nameInput" type="text" value="An0n" name="nameInput">
<label for="textInput" class="form-field-label">Comment</label>
<input id="textInput" type="text" value="I would like to use your private service" name="textInput">
<div id="send-button">
<label for="send-button" class="submit-button">Send</label>
</div>
</div>
</div>
<div class="" style="margin-left:20px;max-width: fit-content;">
<div style="color: white;margin-bottom: 2rem;">
<h4>How it works</h4>
<p>Once you have started your Nym Websocket client, you can fill out the form and send data to the Service Provider via mixnet using the <b>"Send"</b> button.</p>
<p>Below, you can see the activity log. <b style='color: #36d481;'>Sent</b> messages will display in <b style='color: #36d481;'>green</b> while <b style='color: orange;'>received</b> messages will display in <b style='color: orange;'>orange</b>.</p>
</div>
</div>
<h3 style="margin-left:10px">Activity Log</h3>
<p class="output-container">
<span id="output"></div>
</p>
<script src="index.ts"></script>
</body>
</html>
```
Lets add the finishing touches to the UI by adding in the stylesheet which we specified at the top of `index.html`:
```
mkdir -p assets
touch assets/styles.css
# grab the stylesheet from the remote repo and save it to the newly created css file
curl https://raw.githubusercontent.com/nymtech/developer-tutorials/main/simple-service-provider-tutorial/user-client/assets/styles.css -o assets/styles.css
```
* Return back to your terminal and run:
```
npm start
```
Return to [localhost:1234](http://localhost:1234/)) and you should see an updated UI.
<img src="../../images/tutorial_image_2.png"/>
## Connecting to your Nym Client
Follow instructions in the [Nym websocket client documentation](https://nymtech.net/docs/clients/websocket-client.html#initialising-your-client)to `init` and `run` a client then refresh your browser window. You should see a successful response, including a Nym address, in the 'Activity Log' of the UI
Your User Client application code is connected to a Nym websocket client, and ready to send messages through the mixnet!
<img src="../../images/tutorial_image_1.png"/>
In the next section, you will build the Service application you will send these messages to.
@@ -39,5 +39,5 @@ Follow this [video](https://youtu.be/quj8H2qeOwY?t=97) to see the steps on Teleg
**Now your Telegram runs over NymConnect.**
NymConnect is currently available for several applications and service providers. Support for more apps is on the way. For any bug reports or feedback please reach out to us on Telegram or our [Discord](http://discord.gg/nym) server.
NymConnect is currently available for several applications and service providers. Support for more apps is on the way. For any bug reports or feedback please reach out to us on Telegram or our [Discord](http://discord.gg/FaTJb8q8) server.
@@ -0,0 +1 @@
# Preparing Your Client pt2
@@ -0,0 +1 @@
# Preparing Your Client
@@ -0,0 +1 @@
# Blockchain Service pt1
@@ -0,0 +1 @@
# Preparing Your Lib
@@ -0,0 +1 @@
# Tutorial Overview
@@ -0,0 +1 @@
# Preparing Your Environment
@@ -0,0 +1 @@
# Querying the Chain
@@ -0,0 +1 @@
# Preparing Your Service pt2
@@ -0,0 +1 @@
# Preparing Your Service
@@ -0,0 +1 @@
# Preparing Your User Client Environment
@@ -0,0 +1 @@
# Preparing Your Service Provider Environment
@@ -0,0 +1 @@
# Sending a Message Through the Mixnet

Some files were not shown because too many files have changed in this diff Show More