From 2f98912778a846e48c403d88cd016d01eab755ed Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Tue, 20 Jun 2023 13:56:38 +0200 Subject: [PATCH 01/74] fix nym-connect version --- nym-connect/desktop/CHANGELOG.md | 2 +- nym-connect/desktop/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nym-connect/desktop/CHANGELOG.md b/nym-connect/desktop/CHANGELOG.md index 84a79d7886..7335dacb94 100644 --- a/nym-connect/desktop/CHANGELOG.md +++ b/nym-connect/desktop/CHANGELOG.md @@ -2,7 +2,7 @@ ## [Unreleased] -## [v1.1.14] (2023-06-20) +## [v1.1.13] (2023-06-20) - NymConnect - add sentry.io reporting ([#3421]) diff --git a/nym-connect/desktop/package.json b/nym-connect/desktop/package.json index df00561a19..60ea3b4830 100644 --- a/nym-connect/desktop/package.json +++ b/nym-connect/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@nym/nym-connect", - "version": "1.1.14", + "version": "1.1.13", "main": "index.js", "license": "MIT", "scripts": { From d8f80434b44c8cfaa9a2a0370f47dc2d54966c48 Mon Sep 17 00:00:00 2001 From: mx Date: Mon, 26 Jun 2023 17:36:22 +0200 Subject: [PATCH 02/74] * updated libwasmvm.so linking instructions * added note on upgrading to v0.31.1 --- .../docs/src/nodes/validator-setup.md | 45 ++++++------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/documentation/docs/src/nodes/validator-setup.md b/documentation/docs/src/nodes/validator-setup.md index 9551fdc162..a125bcb440 100644 --- a/documentation/docs/src/nodes/validator-setup.md +++ b/documentation/docs/src/nodes/validator-setup.md @@ -61,6 +61,7 @@ The validator binary can be compiled by running the following commands: ``` git clone https://github.com/nymtech/nyxd.git cd nyxd +git checkout release/ # Mainnet make build @@ -77,43 +78,17 @@ At this point, you will have a copy of the `nyxd` binary in your `build/` direct You should see help text print out. -The `nyxd` binary and the `libwasmvm.so` shared object library binary have been compiled. `libwasmvm.so` is the wasm virtual machine which is needed to execute smart contracts. +### Linking `nyxd` to `libwasmvm.so` -```admonish caution title="" -If you have compiled these files locally and need to upload both of them to the server on which the validator will run, **or** downloaded a pre-compiled binary from Github, you need to locate and link these files in slightly different ways, outlined below. If you have instead compiled them on the server skip to the step outlining setting `LD_LIBRARY PATH` below. -``` +`libwasmvm.so` is the wasm virtual machine which is needed to execute smart contracts in `v0.26.1`. This file is renamed in `libwasmvm.x86_64.so` in `v0.31.1`. -To locate these files on your system **if you downloaded a pre-compiled binary from Github** run: +If you downloaded your `nyxd` binary from Github, you will have seen this file when un-`tar`-ing the `.tar.gz` file from the releases page. -``` -WASMVM_SO=$(ldd path/to/nyxd/binary | grep libwasmvm.so | awk '{ print $3 }') -ls ${WASMVM_SO} -``` +If you are seeing an error concerning this file when trying to run `nyxd`, then you need to move the `libwasmvm.so` file to correct location. -e.g. if you downloaded your `nyxd` binary to `/root` then you would replace `ldd path/to/nyxd/binary` with `ldd nyxd` in the above command. - - -To locate these files on your system **if you uploaded your validator after compiling it on a local machine** run: - -``` -WASMVM_SO=$(ldd build/nyxd | grep libwasmvm.so | awk '{ print $3 }') -ls ${WASMVM_SO} -``` - -The above commands will output something like: - -``` -'/home/username/go/pkg/mod/github.com/!cosm!wasm/wasmvm@v0.13.0/api/libwasmvm.so' -``` - -When you upload your `nyxd` binary, you'll need to tell it where `libwasmvm.so` is when you start your validator, or it will not run. If you have compiled them on your server then this is not necessary, as the compiled `nyxd` already has access to `libwasmvm.so`. - -Upload both `nyxd` and `libwasmvm.so` to your validator machine. If `nyxd` can't find `libwasmvm.so` you will see an error like the following: - -``` -./nyxd: error while loading shared libraries: libwasmvm.so: cannot open shared object file: No such file or directory -``` +Simply `cp` or `mv` that file to `/lib/x86_64-linux-gnu/` and re-run `nyxd`. +### Adding `nyxd` to your `$PATH` You'll need to set `LD_LIBRARY_PATH` in your user's `~/.bashrc` file, and add that to our path. Replace `/home/youruser/path/to/nym/binaries` in the command below to the locations of `nyxd` and `libwasmvm.so` and run it. If you have compiled these on the server, they will be in the `build/` folder: ``` @@ -616,6 +591,12 @@ nyxd tx slashing unjail --fees=7000unyxt ``` +### Upgrading your validator + +Upgrading from `v0.26.0` -> `v0.31.1` doesn't require many modifications, simply grab a binary from the [`nyxd` releases page](https://github.com/nymtech/nyxd/releases) and once the chain has halted at the decided upon haltheight, stop your `nyxd` process, replace your binaries, and restart your process. + +You can also use something like [Cosmovisor](https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor) - grab the relevant information from the current upgrade proposal [here](https://nym.explorers.guru/proposal/8). + #### Common reasons for your validator being jailed The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs. From f14b40a76905734b025528527a2ddbfd1825ab95 Mon Sep 17 00:00:00 2001 From: mx Date: Tue, 27 Jun 2023 16:06:03 +0200 Subject: [PATCH 03/74] hotfix on broken releases page link --- .../docs/src/wallet/desktop-wallet.md | 44 +++++++++---------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/documentation/docs/src/wallet/desktop-wallet.md b/documentation/docs/src/wallet/desktop-wallet.md index b44abd2f29..830add582b 100644 --- a/documentation/docs/src/wallet/desktop-wallet.md +++ b/documentation/docs/src/wallet/desktop-wallet.md @@ -5,23 +5,23 @@ The Nym Desktop Wallet lets you interact with your Nym node and to delegate stak You can download it for Mac, Windows, or Linux. -[![download nym wallet](../images/download-wallet.png)](https://github.com/nymtech/nym/releases/tag/nym-wallet-{{platform_release_version}}) +[![download nym wallet](../images/download-wallet.png)](https://github.com/nymtech/nym/releases/tag/nym-wallet-v1.2.4) ### Bypassing security warnings -On Windows you will see a security warning pop up when you attempt to run the wallet. We are in the process of getting app store keys from Microsoft so that this doesn't happen. See the section below for details on steps to bypass these. +On Windows you will see a security warning pop up when you attempt to run the wallet. We are in the process of getting app store keys from Microsoft so that this doesn't happen. See the section below for details on steps to bypass these. -#### Linux +#### Linux -You will need to `chmod +x` the AppImage in the terminal (or give it execute permission in your file browser) before it will run. +You will need to `chmod +x` the AppImage in the terminal (or give it execute permission in your file browser) before it will run. -#### Windows +#### Windows _You will still encounter warnings when opening the wallet on Windows. This is because - although the wallet is approved by Microsoft - it has less than 10 thousand downloads at the current time. Once the wallet has passed this threshold, this warning will disappear._ -Follow the steps below to bypass the warnings. +Follow the steps below to bypass the warnings. -* Select more-info after clicking the msi installer app: +* Select more-info after clicking the msi installer app: ![Windows Warning](../images/wallet-warnings/windows_warningv1-0-2.png) @@ -29,7 +29,7 @@ Follow the steps below to bypass the warnings. ![Windows Warning](../images/wallet-warnings/windows_warning2.png) -* Follow the installer instructions: +* Follow the installer instructions: ![Windows Warning](../images/wallet-warnings/windows_warning3.png) @@ -39,7 +39,7 @@ Follow the steps below to bypass the warnings. ### For developers -If you would like to the compile the wallet yourself, follow the instructions below. +If you would like to the compile the wallet yourself, follow the instructions below. > Please note that the wallet has currently only been built on the operating systems for which there are binaries as listed above. If you find an issue or any additional prerequisties, please create an issue or PR against `develop` on [Github](https://github.com/nymtech/docs). @@ -85,22 +85,22 @@ sudo apt install pkg-config build-essential libssl-dev curl jq ### Removing signing errors when building in development mode -If you're wanting to build the wallet yourself, you will need to make a few modifications to the file located at `nym-wallet/src-tauri/tauri.conf.json` before doing so. These relate to the wallet being accepted by Mac and Windows app stores, and so aren't relevant to you when building and running the wallet yourself. +If you're wanting to build the wallet yourself, you will need to make a few modifications to the file located at `nym-wallet/src-tauri/tauri.conf.json` before doing so. These relate to the wallet being accepted by Mac and Windows app stores, and so aren't relevant to you when building and running the wallet yourself. -On **all** operating systems: +On **all** operating systems: * set the value of line 49 to `false` -* remove lines 50 to 54 +* remove lines 50 to 54 -As well as these modifications for MacOS and Windows users: -* MacOS users must also remove line 39 -* Windows users must remove lines 42 to 46 +As well as these modifications for MacOS and Windows users: +* MacOS users must also remove line 39 +* Windows users must remove lines 42 to 46 ### Installation Once you have made these modifications to `tauri.conf.json`, inside of the `nym-wallet` folder, run: ``` yarn install -``` +``` ### Running in Development Mode @@ -112,7 +112,7 @@ You can run the wallet without having to install it in development mode by runni yarn dev ``` -This will then start the Wallet GUI and produce a binary in `nym-wallet/target/debug/` named `nym-wallet`. +This will then start the Wallet GUI and produce a binary in `nym-wallet/target/debug/` named `nym-wallet`. ### Running in Production Mode @@ -165,25 +165,21 @@ To import or create a new account, first you need to create a password for your 6. Come back to this page to import or create new accounts ### Importing or creating account(s) when you have signed in with mnemonic but a password already exists on your machine -To import or create a new account, you need to log in with your existing password or create a new password. +To import or create a new account, you need to log in with your existing password or create a new password. > Creating a new password will overwrite any old one stored on your machine. Make sure you have saved any mnemonics associated with the password before creating a new one. 1. Log out -2. Click on “Forgot password” +2. Click on “Forgot password” 3. On the next screen select “Create new password” 4. Follow the instructions and create a new password 5. Sign in using your new password ### CLI tool for wallet encrypted file (password) recovery: -The mnemonics that are stored in the local password protected file can also be decrypted and recovered through a simple CLI tool, `nym-wallet-recovery-cli`. +The mnemonics that are stored in the local password protected file can also be decrypted and recovered through a simple CLI tool, `nym-wallet-recovery-cli`. ``` nym-wallet-recovery –file saved-wallet.json –password foo ``` The saved wallet file can be found in `$XDG_DATA_HOME` or `$HOME/.local/share` on Linux, `$HOME/Library/Application Support` on Mac, and `C:\Users\username\AppData\Local` on Windows. - - - - From 51d66c3e0ce0d42979eff97cfd923bc4752ca4ff Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 28 Jun 2023 11:21:24 +0100 Subject: [PATCH 04/74] Made a few additions to upgrade notes --- documentation/docs/src/nodes/validator-setup.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/documentation/docs/src/nodes/validator-setup.md b/documentation/docs/src/nodes/validator-setup.md index a125bcb440..153622740b 100644 --- a/documentation/docs/src/nodes/validator-setup.md +++ b/documentation/docs/src/nodes/validator-setup.md @@ -593,10 +593,19 @@ nyxd tx slashing unjail ### Upgrading your validator -Upgrading from `v0.26.0` -> `v0.31.1` doesn't require many modifications, simply grab a binary from the [`nyxd` releases page](https://github.com/nymtech/nyxd/releases) and once the chain has halted at the decided upon haltheight, stop your `nyxd` process, replace your binaries, and restart your process. +Upgrading from `v0.26.0` -> `v0.31.1` process is fairly simple. Grab the v0.31.1 release tarball from the [`nyxd` releases page](https://github.com/nymtech/nyxd/releases), and untar it. Inside are two files: + +- the new validator (`nyxd`) v0.31.1 +- the new wasmvm (it depends on your platform, but most common filename is `libwasmvm.x86_64.so`) + +Before the upgrade height, copy `libwasmvm.x86_64.so` to the default LD_LIBRARY_PATH on your system (on Ubuntu 20.04 this is `/lib/x86_64-linux-gnu/`): + +Then just swap in your new `nyxd` binary and restart once the halt height is reached. You can also use something like [Cosmovisor](https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor) - grab the relevant information from the current upgrade proposal [here](https://nym.explorers.guru/proposal/8). +Note: Cosmovisor will swap the `nyxd` binary, but you'll need to already have the `libwasmvm.x86_64.so` in place. Luckily, the name of the wasmvm in v0.26.1 was `libwasmvm.so`, and the new name is `libwasmvm.x86_64.so`, so you can have it already sitting there without disrupting service. + #### Common reasons for your validator being jailed The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs. From 0f41dda0138f03303a83d234e74805e8c373d314 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 28 Jun 2023 11:21:24 +0100 Subject: [PATCH 05/74] Made a few additions to upgrade notes --- documentation/docs/src/nodes/validator-setup.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/documentation/docs/src/nodes/validator-setup.md b/documentation/docs/src/nodes/validator-setup.md index a125bcb440..153622740b 100644 --- a/documentation/docs/src/nodes/validator-setup.md +++ b/documentation/docs/src/nodes/validator-setup.md @@ -593,10 +593,19 @@ nyxd tx slashing unjail ### Upgrading your validator -Upgrading from `v0.26.0` -> `v0.31.1` doesn't require many modifications, simply grab a binary from the [`nyxd` releases page](https://github.com/nymtech/nyxd/releases) and once the chain has halted at the decided upon haltheight, stop your `nyxd` process, replace your binaries, and restart your process. +Upgrading from `v0.26.0` -> `v0.31.1` process is fairly simple. Grab the v0.31.1 release tarball from the [`nyxd` releases page](https://github.com/nymtech/nyxd/releases), and untar it. Inside are two files: + +- the new validator (`nyxd`) v0.31.1 +- the new wasmvm (it depends on your platform, but most common filename is `libwasmvm.x86_64.so`) + +Before the upgrade height, copy `libwasmvm.x86_64.so` to the default LD_LIBRARY_PATH on your system (on Ubuntu 20.04 this is `/lib/x86_64-linux-gnu/`): + +Then just swap in your new `nyxd` binary and restart once the halt height is reached. You can also use something like [Cosmovisor](https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor) - grab the relevant information from the current upgrade proposal [here](https://nym.explorers.guru/proposal/8). +Note: Cosmovisor will swap the `nyxd` binary, but you'll need to already have the `libwasmvm.x86_64.so` in place. Luckily, the name of the wasmvm in v0.26.1 was `libwasmvm.so`, and the new name is `libwasmvm.x86_64.so`, so you can have it already sitting there without disrupting service. + #### Common reasons for your validator being jailed The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs. From ee98820bb4fa859496bc5021a415a56ca668eb49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Wed, 28 Jun 2023 23:45:45 +0200 Subject: [PATCH 06/74] Use different service provider directory when medium toggle enabled (#3617) --- .../src-tauri/src/operations/directory/mod.rs | 96 +++++++++++++------ 1 file changed, 65 insertions(+), 31 deletions(-) diff --git a/nym-connect/desktop/src-tauri/src/operations/directory/mod.rs b/nym-connect/desktop/src-tauri/src/operations/directory/mod.rs index a518dc29b1..6195d41283 100644 --- a/nym-connect/desktop/src-tauri/src/operations/directory/mod.rs +++ b/nym-connect/desktop/src-tauri/src/operations/directory/mod.rs @@ -10,39 +10,58 @@ use nym_contracts_common::types::Percent; static SERVICE_PROVIDER_WELLKNOWN_URL: &str = "https://nymtech.net/.wellknown/connect/service-providers.json"; +// List of network-requesters running with medium toggle enabled, for testing +static SERVICE_PROVIDER_WELLKNOWN_URL_MEDIUM: &str = + "https://nymtech.net/.wellknown/connect/service-providers-medium.json"; + static HARBOUR_MASTER_URL: &str = "https://harbourmaster.nymtech.net/v1/services/?size=100"; static GATEWAYS_DETAILED_URL: &str = "https://validator.nymtech.net/api/v1/status/gateways/detailed"; +fn get_services_url() -> &'static str { + std::env::var("NYM_CONNECT_ENABLE_MEDIUM") + .is_ok() + .then(|| SERVICE_PROVIDER_WELLKNOWN_URL_MEDIUM) + .unwrap_or(SERVICE_PROVIDER_WELLKNOWN_URL) +} + #[tauri::command] pub async fn get_services() -> Result> { log::trace!("Fetching services"); - let services_res = reqwest::get(SERVICE_PROVIDER_WELLKNOWN_URL) - .await? - .json::>() - .await?; - log::trace!("Received: {:#?}", services_res); + let all_services = fetch_services().await?; + log::trace!("Received: {:#?}", all_services); - log::trace!("Fetching gateways"); - let gateway_res = reqwest::get(GATEWAYS_DETAILED_URL) - .await? - .json::>() - .await?; - log::trace!("Received: {:#?}", gateway_res); + // Early return if we're running with medium toggle enabled + if std::env::var("NYM_CONNECT_ENABLE_MEDIUM").is_ok() { + return Ok(all_services.into_iter().flat_map(|sp| sp.items).collect()); + } // TODO: get paged log::trace!("Fetching active services"); - let active_services = reqwest::get(HARBOUR_MASTER_URL) - .await? - .json::>() - .await?; + let active_services = fetch_active_services().await?; log::trace!("Active: {:#?}", active_services); - let mut filtered: Vec = vec![]; + let filtered_services = filter_out_inactive(all_services, active_services); - for service in &services_res { - let items = service + log::trace!("Fetching gateways"); + let gateway_res = get_gateways_detailed().await?; + log::trace!("Received: {:#?}", gateway_res); + + // Use only services that are active AND have a performance of >= 90% + let filtered_services_with_good_gateway = + filter_out_poor_gateways(filtered_services, gateway_res); + + Ok(filtered_services_with_good_gateway) +} + +fn filter_out_inactive( + services_res: Vec, + active_services: PagedResult, +) -> Vec { + let mut filtered: Vec = vec![]; + for service_type in &services_res { + let items = service_type .items .clone() .into_iter() @@ -53,33 +72,48 @@ pub async fn get_services() -> Result> { .any(|active| active.service_provider_client_id == sp.address) }) .collect_vec(); - log::trace!("service = {} has {} items", service.id, items.len()); + log::trace!("service = {} has {} items", service_type.id, items.len()); filtered.push(DirectoryService { - id: service.id.clone(), - description: service.description.clone(), + id: service_type.id.clone(), + description: service_type.description.clone(), items, }) } + filtered +} +fn filter_out_poor_gateways( + services: Vec, + gateway_res: Vec, +) -> Vec { let perf_threshold = Percent::from_percentage_value(90).unwrap(); - - // Use only services that are active AND have a performance of >= 90% - let services_with_good_performance: Vec = filtered - .iter_mut() - .fold(vec![], |mut acc, sp| { - acc.append(&mut sp.items); - acc - }) + services .into_iter() + .flat_map(|sp| sp.items) .filter(|sp| { gateway_res.iter().any(|gateway| { gateway.gateway_bond.gateway.identity_key == sp.gateway && gateway.performance >= perf_threshold }) }) - .collect(); + .collect() +} - Ok(services_with_good_performance) +async fn fetch_services() -> Result> { + let services_url = get_services_url(); + let services_res = reqwest::get(services_url) + .await? + .json::>() + .await?; + Ok(services_res) +} + +async fn fetch_active_services() -> Result> { + let active_services = reqwest::get(HARBOUR_MASTER_URL) + .await? + .json::>() + .await?; + Ok(active_services) } #[tauri::command] From 2953837f25f779d31d2cfb2c477dce92fb6809c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Wed, 28 Jun 2023 23:47:00 +0200 Subject: [PATCH 07/74] Add medium toggle to socks5 client (#3615) * Add medium toggle to socks5 client * rustfmt --- clients/socks5/src/commands/init.rs | 1 + clients/socks5/src/commands/mod.rs | 18 +++++++++++++++++- clients/socks5/src/commands/run.rs | 6 ++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/clients/socks5/src/commands/init.rs b/clients/socks5/src/commands/init.rs index 7c8fa68719..76337b84ac 100644 --- a/clients/socks5/src/commands/init.rs +++ b/clients/socks5/src/commands/init.rs @@ -94,6 +94,7 @@ impl From for OverrideConfig { use_anonymous_replies: init_config.use_reply_surbs, fastmode: init_config.fastmode, no_cover: init_config.no_cover, + medium_toggle: false, nyxd_urls: init_config.nyxd_urls, enabled_credentials_mode: init_config.enabled_credentials_mode, outfox: false, diff --git a/clients/socks5/src/commands/mod.rs b/clients/socks5/src/commands/mod.rs index 60d6b6e0b7..61e992d4d0 100644 --- a/clients/socks5/src/commands/mod.rs +++ b/clients/socks5/src/commands/mod.rs @@ -19,7 +19,7 @@ use nym_client_core::client::key_manager::persistence::OnDiskKeys; use nym_client_core::config::GatewayEndpointConfig; use nym_client_core::error::ClientCoreError; use nym_config::OptionalSet; -use nym_sphinx::params::PacketType; +use nym_sphinx::params::{PacketSize, PacketType}; use std::error::Error; pub mod init; @@ -72,6 +72,7 @@ pub(crate) struct OverrideConfig { use_anonymous_replies: Option, fastmode: bool, no_cover: bool, + medium_toggle: bool, nyxd_urls: Option>, enabled_credentials_mode: Option, outfox: bool, @@ -91,6 +92,10 @@ pub(crate) async fn execute(args: &Cli) -> Result<(), Box Config { + let disable_cover_traffic_with_keepalive = args.medium_toggle; + let secondary_packet_size = args.medium_toggle.then_some(PacketSize::ExtendedPacket16); + let no_per_hop_delays = args.medium_toggle; + let packet_type = if args.outfox { PacketType::Outfox } else { @@ -101,6 +106,17 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config { BaseClientConfig::with_high_default_traffic_volume, args.fastmode, ) + .with_base( + // NOTE: This interacts with disabling cover traffic fully, so we want to this to be set before + BaseClientConfig::with_disabled_cover_traffic_with_keepalive, + disable_cover_traffic_with_keepalive, + ) + .with_base( + BaseClientConfig::with_secondary_packet_size, + secondary_packet_size, + ) + .with_base(BaseClientConfig::with_no_per_hop_delays, no_per_hop_delays) + // NOTE: see comment above about the order of the other disble cover traffic config .with_base(BaseClientConfig::with_disabled_cover_traffic, args.no_cover) .with_base(BaseClientConfig::with_packet_type, packet_type) .with_optional(Config::with_anonymous_replies, args.use_anonymous_replies) diff --git a/clients/socks5/src/commands/run.rs b/clients/socks5/src/commands/run.rs index a6bc88344b..5d54038c06 100644 --- a/clients/socks5/src/commands/run.rs +++ b/clients/socks5/src/commands/run.rs @@ -60,6 +60,11 @@ pub(crate) struct Run { #[clap(long, hide = true)] no_cover: bool, + /// Enable medium mixnet traffic, for experiments only. + /// This includes things like disabling cover traffic, no per hop delays, etc. + #[clap(long, hide = true)] + medium_toggle: bool, + /// Set this client to work in a enabled credentials mode that would attempt to use gateway /// with bandwidth credential requirement. #[clap(long, hide = true)] @@ -77,6 +82,7 @@ impl From for OverrideConfig { use_anonymous_replies: run_config.use_anonymous_replies, fastmode: run_config.fastmode, no_cover: run_config.no_cover, + medium_toggle: run_config.medium_toggle, nyxd_urls: run_config.nyxd_urls, enabled_credentials_mode: run_config.enabled_credentials_mode, outfox: run_config.outfox, From ef7beaa12f73727ad4566ab16f954ca4a397d634 Mon Sep 17 00:00:00 2001 From: serinko Date: Wed, 28 Jun 2023 12:16:47 +0200 Subject: [PATCH 08/74] created user manuals & monero.md --- documentation/dev-portal/src/SUMMARY.md | 4 ++ .../src/images/monero_tutorial/monero.png | Bin 0 -> 321359 bytes documentation/dev-portal/src/monero.md | 42 ++++++++++++++++++ .../dev-portal/src/tutorials/monero.md | 42 ++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 documentation/dev-portal/src/images/monero_tutorial/monero.png create mode 100644 documentation/dev-portal/src/monero.md create mode 100644 documentation/dev-portal/src/tutorials/monero.md diff --git a/documentation/dev-portal/src/SUMMARY.md b/documentation/dev-portal/src/SUMMARY.md index a2e6cbeb6f..7f9e1e7df7 100644 --- a/documentation/dev-portal/src/SUMMARY.md +++ b/documentation/dev-portal/src/SUMMARY.md @@ -14,6 +14,10 @@ - [SOCKS Proxy (CLI)](quickstart/socks-proxy.md) - [NymConnect Beta (GUI)](quickstart/nymconnect-gui.md) +# User Manuals + +- [NymConnect Monero](tutorials/monero.md) + # Integrations - [Integration Options](integrations/integration-options.md) diff --git a/documentation/dev-portal/src/images/monero_tutorial/monero.png b/documentation/dev-portal/src/images/monero_tutorial/monero.png new file mode 100644 index 0000000000000000000000000000000000000000..3c7fadd32a8fa1ad29a881e627d463716c91b485 GIT binary patch literal 321359 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 G0v>&HD?&0O)SO~0n z0=;C(rC&;S+_w)tdi(|Jdc2(74M-6A=q4aQP!VDWHYgu)Lz&u!E%V*1g`nCdj{S<) zd8EuoP~1_{Ume%gZ(p_%;ZgEPvP8a6S8USPkzd#{IUbdc}6 z1}7hPWj;zr>FMqPIVUci1%a)>y#*f_)%CY*OEMx8F|bAjMQ@hY_%n_zF-^pk9hJB? zP+mWVw&uMFX9kywbfk|=^Hu{k?=5RGrKMfAiCQ|+oW95Jk=6P7N{`D*3XAxQ&vR;a zUR0*}C(;h?v6JxVv2vMRwN`$~--(Cr#TA`Pn;k4<%st;%3l#iWaGvxP%Hy4$p|*`T zHUBId9L=b_yO0jt$T-(HKI&^paZXG~I~w(xeC)E5fBaMtZ)SUw$P1-gM%+~Uzel@l zjSB_3CbE;uQOl^feL_<)uF*G0@PRKgfKceDV15A`gXR-7c}sO~@_1GNS%#=kNRxYg zR@KI)|GFQ z_hg=sS_an?OYU$`BE62deDF?_DI$tb=EbQWtMn_? z*A722&&sT(hWBPaW-948<3~r^KX=I|=i?;3(mU>~+3Bv+?|NuPApPRs0LWDc-l2|} z0=!Ax;x7>sW7VKadWt>nizflo_n(gqSJTyJWdG{-ED!BbVoEip+7c=ZR3h!Uyd!g( zq8#8P;5iUxA3wXiz|zY4&TL&*ORP`y#ymgc-rG^E#2Fz0>8Thd41&iB0M{kdqBgRF6PaHs{cpR zcZXx$zW?9$-g}Rbke!umWebr}HkoB-m6g3!R<pIWZ%*Mq9(rxE#$gi`IW{4j5_ZVI>V`1}#7`!ehlmSVUkXaor984$? z5&kv!&T4!%427)PSyA!~&~et1%sV9__lQt25*HyhT#eR`HciiBb88>U&$R=r@K$I!J+aKx&+qcjhmHEE_F*fLjCn z$(p5uk5;Ptd&L}u0PR3{xuz1FUVv{S6%Z=dLHYrC_I^mBMSB{|O%2^}UZwFM-++^g zOE_4EAypap_o0>WE^BKnIk0vD5(lR|0$aTgxNphq-_!r605y?2Uwan<*kSHgQ^@bH zwd+SC5{O110}?_@AYPU4AGZ($w1b9`5Eei{wP1Aw`IMuWMiQ_5C`gT2;3I+}B;j)h zC@z#ydB8V6r~07eLobw4z%B@9e0|i(6tjs|^O-RV`0}v$GSt3s>3o)SpVwmooKawd zO!LCpzg1=h-$mh7r*!X^eji6TYjoN0kUAPZe^JG}iqvnJ|c}HIe9W zsoD+J;~-Hlt_Vpo#T9sgLi|5|9OCvdBvrSn}`Wj1|g^ND!`ZV_mJaYpy< ztm4${Vmaa2pL4(UH^(fY#&1{TSg3!*;mtc&$;YfbW>Mo#N_pI|;p;OZv4yDF(W?Q$ZZelPB4QbiFFFwgJ8tPg9^*N`eR>h0;59#st8hb%2 zruKfv;a@tB6CoI}lx7lc9`##S&VC6zI*$==%k$E~d*-MqFOz47b;jbQySmg92ZQFf z+2>+or?m7-(+)^6)56@}e&!B7jWhrDE&r^b;;&~WKhD*$UVD{B$Y<~E?2*Hs|L>SV zR7x&RzeUj?D*ndp1pS0jTPk-G7V1HOUe5gfJ{R%wOCU+vHEj7i)@#Y(K52u_7}ofI zc~$3DCE0peL*;YyA|GYmQEa)+BDasJ7_?W;Y9%eUD<+|@T(+emOpqA5Tt8<{IA`#p zWGyd<{pay-HeA&>a!7+3fw-URSeOcvDma(Oz%fMdWSU$vow)N7Mbc6{tlJ>>4$g`9vXE0F73* z{!WaOv5XitHdr*V73kvPc{srv4_WHK>m8z`Hk6zs zgtzZ%b;K-e*%kwh9h86$qlpd$FC2vYJAh%vwAJrCC`(XYCx8LOKiiLl@Bf|5FMFSlM2`W&@%u)#X74tOpnj$d!iwX5t@C`4_^93i2YMmDHGd zNVmsy!t=8TT>FS4s5oL_SB<)frctS+l=WZh8x<>lGtlE=f$c=-{*;p>z1RfLYH7LyoJw$v zBiZBl_;^~sfy?f)3_0);JO07+oHN)a7o3Fg3f!ew;0Fya;nE!!vamtJ!CN0jjiXzf zNQm62bFz)|TywQIQa4t)xAoH=`^zg-kM65rvZE&XPk|_4hI$RfAdeN`)`2`c=&h+fDS!|~j8K2<*)hgq>hvRhh zk@>lF&|zff8cM@asgLS zIjL}hy9y8Bvyhw=GSJ@IbS8bI#O9@Js!j>?)9t*sOSS>KYh|(0+CxLhhh;o)2RoMd zq)$**l<>!H;A(5O&0_z%t^6riVH}e(Bru!7qdi<3A;j-Y@u6{(3xv9?sN>0a+Vr*K z1z?J}F0|DMLXWsAH#-H(JE6LaUCR>xBKYg0k_w*s!O9KN^KCKrKQXBrz5sxN zY`U=VfshB$z)$_AYF~iF z55VE~Yw&)vpbr=1YXMtt^60}y5EH_q3CkAJgH^Zx71&HcDUvwI1PZ5GJtoCrD4i=~ z$Ohao5S9e3mJz+S%5dtSmvt%V_W}@whY$*N>&;ReY2TuUb#ELUBs+i-2Sr|exDC_> zz_F{=D!X^Uf%UzGE7`%zh$vD88TVoCOC4P^0EensI-<{_MAQu)^e@?%cmm{vlH1^s z2T3%Swz%-k_BU}4d9~9+mt;`Pl4+a27)T+Jx-TS>^XES%nrI@V}X zVt64pa+U1xNBRZf{ksP)Pp%W2x+*vPHny~UCl&oFEqtoyUY$_AfPU3SKH0(S3$7mD zrpk&o9bV8kns^nywp`ELkWZWH-S9z%5706>gkF7hd4;?4M!2_t%iJi&rEFbdqwDDm z?I_RU%G~HfO@%5JwrZgvsJ0teX&`-RJNh_dqc9_zL5T#vq(qaY!(>UvTv*_S7M^D_ zNvIerxx~!Fb{6MZc+O{Dn8lYZ(86g7b?UWtM=+;)vW`2!kL~93z3cB}J^H-mS-N$2 zs6pc;@@dlB>91_AOQv3c^`AC{RY9Rx>S6lbgnKrNYfg7W3Gwk5SKlyQk8~r4=tHvi zR|&%GN!|{tlsYw^%NQ!`whG&+^)z)iakM%+NG+2qo&%N|&+UafHj>%eKSGN5yKJQ- zI6k<4dBZ6>>O>>i<@49;*6xAwuYRy2u?zn zF@#R)AeNC=20Ubd%fYFpOol)DQB5xTWOeo+{9qNiU!H8CC(-UR(;4uKouyI1oNa=7w zrcSARuZ!?h_gTsnzgFO}MYWUpw5#vAY^OF`QF$ zizc?evA~O~^PAVJ%n+`|;DKuv?&FdSrn#FZKk4}ANpOns$4kCMcQU&%ELViSlQ4hVZm`8C!`vaZSMEf?wOQ1&~J8mgYGJ_^ZY~w)2iVlSnGz7kG~BV zCyae!%gXvWFfw?1_#QI7$}!!p;WdjGe)n?F z-d339!%uyx55D`pP>J*=fUR(lg*^cGV*m$2##4ginD|J zoK>bKpVvH16`zhv0+TJ+qQ`$Va;BV7$vg6>dmvLpD`_|I^?&?t4@1ZRF@>C>C-<0D)Su-CYcSXlq?L^}g>uvM0k-*ZPwz-0QrB zy9xY@V0C(w5rmY0Fg5_-2O1p61O5t_NM-Z&r9W9m$8 zzBFPcL;i1Ng3=JO0D}-j7JY@G0UX_S{Y#Kho%R*tT#=6pI$RK7QYUnVIk7G%j?rmf zb{=FW$Tg07r~sTmzEX&`-)^kFNA^U@y<58Dk1l8fyEpf_^G8v(HQ>;9+W+vO*39(Y zu3dRcI4_PrcAT()QPuL=HOh7uko$C;ZgzYPnm=MsV!!mZ-46CwWS_*soc^u;#|&&g z7;7qZSwu>kw{qJf+s7)U%p zrVlU+j8m&~m3-Y!FB0++1x+eDUwN;YzKn^w0)=6)EkUG90vum-iv=JvC;|i>a6_F6 zw)kGgGcWF^+GX}H84#)^E&cLYEW;WPR!Z(Rp|3j`4|f8ung&mId9R@%Ufx=K+wDPO zKIX)C0au7Po+G&t=s#m>$kBaWp$BPW@Dnn zP2$O&0qsi|K|<`wFu{CT79|=Zk=Tjvg;&T}_%vmunpLDUOJ*#eY(ITWW3V~1^@}r0 zONE-w>RV2xUBW7Sn-KbsHmCJ~OWJBd+g$`G1soT92|&sEFIFHjVSMzHEnZLc5s!u; zv-};~&Eb*S`%q*bZh5Xib&<05%H#%*yn{mTP@{E~`VUG;nYZ4-$|@-i;7ri0q8BVL zuMmY)PS%Tr$IrVi)}{tpGI{U?JTMnLzpB<-^x{E6437c8Agvs85uhmTxk4VXw*Q=8 z1YNg+#DtuwFDz$nJTWgSxK^m%|44^#!KX#*os$zUQ5{eH(x@YyBiJ)SXLl18xn=Qv zuW7uskrcRzJUH_KfB*YDu38Yl0D6lq>06=c#Np?2~w5SZUvk@-9;D8Pn0iN*WjY}lGzlOaGD*`<2 z!0I6A0!30lrL)8>a$>qNFzO&hALPTpasw<4Tr}Mfpax?#06vaFcf_;oM^^!7LQz<- zlML5wJ=9m|%4px?MIMRF)H;P`jg z50`x(d?k3d-gO(Id3w;k#%Y`zWi!B6UfVuoEhZ%mO7M% zuEEpO`+n?Bj7H}@jjv2j%D!FkGHr08g7**JJcK5JiVtPZ0rw=f1tDj2uiu!q@ zlB}ifD`nC$jehB+`q5EQaY>0$CWObSeKAR0oBMT#!$DYM*Y?YEN#hs`0y4YxcUvs1 zFU{{{{B3@dF?`mi^WUOq=e(A!P@@XV@XwMYPPrW<$`?;PtV zusD+qx9%ygDdlEfuo}M-`o*@kbH(Qz{iASp`g**f^z(x6>pkB$Y+%L6QgN{TBLrzH zYOw(5MN6)c-?b|EvUOqtvP#OhQJRjDGUG1e_!+3Hz&d5$>dZVmfxe^a=V6s=S zr);#%F^1$WkgaLMbGk&bM46C9d61Hf&wji5n-b`I zgB7e&SCQaBKqeAg0mz{TiXIKVG#Czg1_m^22&wP}ud+kzhZV*;1C|16U+8Th(=@au@XbfLuVBic zCIK-Xs_|K5nLorIT3wJK&p-OKhK3)s)qs@(dDz6D6$s`e8wjm|FMc!7FtZ)|5VgS|N0Eq)rAt zZ@9`3p?48#o&e&-p#CA)X`pUQ>g+zG)qOqOSwbTtSk#eAJz$wiiZu`%UG%M%#JiLm zX9=+Zz8!}X9uCqX_yQp3fgNDDP8gzA$1*%*Nb}avcq1wbVtqIs@bQneUlY<8D#gEZ zlUkdm7zttm7IH+#P4{7vIpx*z6`j(V9KJWU!hfI-NgcMHBUWX~8kcDS*vXKE-Z&0d ziZJvjSOKgRtCmVS+UL#<-01g^#@_}J5e6cQ?#*uYv&-O#x`;BGmX!X^Gzl`k$V%SS zWPVPk%=g+yymGU*hVG)+eN!feL$W57reRQ|f=A$?g@xO=&m5+>pG{K_IS63%i-j}3 znMWxnz^dx9SG(O}=LW6oS>*-OKr1+N^m1ej8ic)N86cfro50|xjwRA?&;2X zvZPbkMJLhJ!XyHr*5r9>U}t#mE39cq6`?Up%9c-`vy*dGGUv@Mex@#8WUjEcUH@;k z!`>mq2y%H~CkS5W^<3#!g#Bd^9qv0c{bC9V#Lp%Zog@>ytmx`q2~CvwU9fI#Bx-k^Vws$=UGZs$s(;3nQwFywFPw|eA@(^ z#}_?1SNxEex%Ws}nITt)he>Jfl^p{LbDIb`!KIJ)ok^h`-64!r^>%sOc*NBDn`CVO zu4t&cU-S@lmmphlo~?j&c*$-l#hwV1qP0KZt>5v_@uix!T!w6@GW$69({KCNj(jIY z7XVU(rPuT8AyMS>g;(5ODo+XmMQpC(UfcMi%!b)7$ou_R@0r>01zy{SQ#==H)l$MjqB6WSUBq~S!uFRA;~x-^$N z4Xm#BH}so4p$k(|+VCO77SEyuQe-=*;~)rBHt3`RK?!QeK?ZDCz<{^V!O>A?_kA>7 zSrmwWWoxR$kp*mh!=2Y*)!2Q&cTgA`8(YMsWm|A==TY0E!9~?0d7eJ+KfhK`+WDCj z>R2^{S&f_4L;rQd;fuqQl(}UC21Xive!png!BoJ=3-UfPz*fOM^$+Yc51DTjz zK<5Cc8USqJBTG~92#fVl9Ib91$0{t<_MwS57hF#oVrVu_P z^H8V?)Jz!oPmz5@%hs7Y3=}*Rkhr;H%IalFBvaTOBVX)%ep=5Jwn%VO^TP)bazw?T zt@A0*BXMV`C(y~&PYm@3VW_ePEOos|;Q$6BAQ3=M12Hz&1bPkeE5M}%XJ#<$>pH7n z;Ry!c=nE=l){^c)FoW2O7ea^x=#hXuYiTnHR-D%!c|X2a0l^HaF3V43u9xQu2?h!i zJDEB47)NIb-E5(S1x%f^?C-9Yvjv1nzkgF@;^!ev5gK`HF*uZs@Al)dr-{TKQ1`hW z7mmslUKnDUr-BUcDv|wO{Tn>tXXGkC9a~f04ksd9U%YlrKcn!@=HHgfFvq_D7Ck6@ z1$j9TZrkCrRtnWm?3_GaEM)~~AixO{6P+st1)e?n9{E&lik*9DAJF*!MG-^HGS|a* z=lKb;1$nSA!}Mq3N#QUT8aW4tts1Ybg5*|JzBsHiIpjll${Y5C(r*E5om}h$DN*1W~N4xvkEE!%GazStw~KMTD-O& z7x22^ih_t(O}gGQ23F$Y8n(P8ri=d481td4?|MVEiyrX0YXjlj_Y}LtQFKbx>n-zH ztaWI_)(6@B!feMW9cj2Ty@Z=^vl~xZ?1ZvfTl?~7PG&Y^(8FnPGbD*9i!p|O|mk^v%H?Vg*Gic!xIi&+K1rWHP4`Ukt z;^zZ$>;-78X3Q!~R~AxJ8oo|SvmwqA%9p`_-ADUPZLNArsg!3(N8zi7jA(9V6u&^~ zLYzoL9f#Slqs&dcgoIDnqbypbX#!!QT1E3oxfi!5^G_KtY*KDl@$s$ZkK|x>Myxqd z)S{B|gb~*Ev*P_b!_Tskbop`dQiCI7o*K?VY=HTB6P>ePMYD!YJMLdXEUJeLVV<<; z&p%i0Dncf>=8a~5EDQ=Q)sP8S6E7SXB-VNP*Hj}(wet1QiXnE@9=89bWa!$+TQazA zg^bvxR_?G<&HwEGy=7tcMqipuzsza)dyd#HHYdEN*;dDWQKOuqK2|{4D$w7bz3j5#Xpw9#CAp9;^Cu|`r zcO{-O3Q95o(H*A9-s=OF9#%mVMgbgmrZQr{ASwdnMyQY-h8x(tP&fvRS0G?n?cRo) zA$)Yrjx!6}0tuc$VU0A;CKZo;(_#KfFnXqEgB%DyjcOQt`G|KtTY}GRHn!qvy?JC- zHN$;r<3?WpxAF<_W}W-|htc%{Ay4QPpO&E&0b935)f@0nSXO5kw>=`%Xiq+H*)(BY z3O?BMl@_T|jrAjQzBx^E;(e(`OYE8X@9QVBxL=*mfHU05)wKrzqBv6zz22{%0gaKO za3A}?BL<>zu!t?ekjZ-yJD*;O1=%4rkx~*CR}^5*qbcNdU-+{OmXp?_qJ}F1;Ot;g zGst03nos2Ew--(yNtp^=)}~ERwKhuQfxibah%V{zgkak0&(Y#t*gq7bBkgp$Dp|Fm zgT246`@YUW@c!?~eC}jcDYs@0c;1HR>T5o_zXuU*61!~N#p0KXKK^mxmj=X?$%vNI7Miq(07! zCnD6m42^+2Alx>V{EJ8F0^WNRu48KES&ToHrBkXgsW*X@6?P7fv)7hN{?D5=$miHu ztUcgbr_&aQ^T}9q&{;dHR=N~7DpR!0g#kq>kn;x6GbRHeac%fd^5_LAG{GIKGQPn+UX4d zgU~K|P|C5<9dY|@1u{xU-zj?bGFoir+6_T*A@}C7VUGf8R|ScjpC z6WY|8j={zP^F+*`Q{Ux&kL7hL*e8(e(du-?3WGs4#U%PWfv%U;UKPTaJAC!Zhr1aroI%A%PyFc(z)D zcrjE3%bg%^ub6&os=F1X#rzeb;FJ4tl9m8KWs)c(i{sqpj+3AuYS{Omko=;x7WhI0TtiMwa5~ zc+cH%CSlq-m}=@LRGJ+5>emXLPVs8og&#tHvMCwK75)8Go*V#q#>k1lxOB;?;cp0m z5(zd16btmm$7kJY!KY92ND+}CYq%7NBy6x|gwih`dbAX`1kt#HC zF!3kLlQT7Qp0Aes1D8ZZ*8`v)fCqjM&h^H25|n+U{M2K?QlT2?n$z9DyY$6Lc5D@j|{!gGfQ0EEGqY&mO<>RAT-B}euGczrZWG|2P= zy&%80<|*7HD%HoC*V<*HXGqx zlnIw{WZ0tLmTN)~%%XYSy}6g7FH<4CDOH!h_ z7h=1*VQhRe61I&chK@r#Kui7H=EFeSd6&E$2jhQO811?B;Q}DawD$T`?<@U)b=T2J z=;F-OdZ&b7d^aD`KxM`1Lgn{CtXA9;v^jDqw56p({36}Uys_z6qS16@oH_zBX10GR}SZ_H~; zii+vD8^ZlLI%)=Q)^iQMf9#+Dlu#8iz|gS>CQJ}h*Dhp$DtB)hjy#>;DjUIk4^bi- z2rm#24&*LG>LJr7Dj)+tB^+*Xc#hm%_p7S^>-+(+uiwuvi7?^7dx8==-EQ9b)EovL zXZX~Zq?AlLLtg>3n`V$_saa>O#=P0VNN= zLR1wH^APuBgY2!)72Klkx`%4qabD#PIhpz$V!ZnX*sS#e8mR72@Y># zR!d7}^GE)LNX*s^de?7Dd>Bm%R(CA5=}V1Q8h%!7VV*M)K+Y1>B7r>?QW%$tll6ut z&NDDvCHCKY6u=lSGe2b8L~kw_cL5mto^s;~*jyK}ttEt;9n*xmY@0;0Qd`CbV_$I( zCjAb(=Az_M$Wvm(FasZ}U zrzf)3nu7oZk`;`UR|12fHfIi#ZxT{<>EPRr#`+=1225?7SMi&kkvGSLQ>& z@)9{nyuPdL+erT*q(RlIWTs;3gj>sY{Nzdk-APu|st?|g%$B7ZX{#RxU%L6bHIlBg zZ);|fwk~cXbO^sI#<=1-s8dk(iYPN3nNLWFVpMb#9J7>rDuYav0)cT)jUz?R`eNdK z|K-F#h5_K>@p`mkH~4k^UyJWSST_oAflvM?)^;Mz^u_AuC^mxrrEnjJ?Y94ZnMJpj zR!NGM0L}x4JaNDw({Eh4$<6%T*z~oeT}4JiQy~P11O5y_*H`3nZE<>8pM4hr#|Avb z9lO+Ja%&fmZ@xMhAMbQF0~%n~;8+ zpSByEfygn3rhp)g5<`@w8*!EY0SNTaP=rn!808ty`2Z12-=!-~sP)f?#+G*RCgdMe z6Fte!uCX7a2C)eWN`_Jb%W7%~MRDj&T*DT)Fp>Gh2_9jL@*eUz(wklW_Pb`S{7&uh+&eZ}RUX zg~~KWtWKDv3V(-#=wP`N1j(6FudY>?+#LKuQZs$|p;4>aNM%Si&x=TGS9+JK3Nsh? zFtLoIDA>4h}Kj0nVbz96H2&`2I>wf;f8}`4>XD6Jfrc%{Ara7DS5}+Sl8H@ zjd}QicxU``GRnUHdB-w(&MnK=>iNyU7_onEueXOo^nOuCb;rQ&^^av)0oB3djd`O( z3o?0)bAu|vPezm}_taHAmk)Ao^;h9X$lLi3UblF*6gR=@ZHvFPHB+!*nJmIq zEeR}_W;xdr6EtW19ymFrv}b(S%xWq1rZc^!(|Fz)h2WEO$dW#pjU?U1MUBv{FpfGwz`J!P)fKs4((4?zmZtBt#j z$m1U#$Q1xUGhFeA@dr^&pNltZ|K1#6Mer{JUJW|AFmOlopH=9~s=s9o^)2w{R@uJ5 zEC)~&sz|&Yo3zw?{BNqaP|yDiTbZBgxE9e=wguGv@dY>HoHf^#Jh=&#^YNceTz%JC zl;H*7_)D6~%#Tj4fpDm9Q8;dSik$7!W}x$hT$hWozF$9w9Go=vgqw?2Hf9^Kf0!#; z>^2M(vAqW<6KHW)@y0%k^sImi_B9&}eS$gKCvBJyj`iGG8uX#AF3Ok@@4ww|f-k{a zztcr1rb42W8M#I|3WZhX+mf6GoXy-{jK=4m>YTzcw%clI!+Kn zSEQ>0O{mlp9q8mu;boePb%yKvQO0#^(1O1|cybRDN&sb2@W0^@F?e4|F2A!(19t`N zlfWl@zxaHG&*vtu(O}kY)e?kSnvN0RRFz+N=zw?4$jw)tonVwM)EY~Eux|Lnz6(oD zYe3mWLmsQld&$G0n;UN=$yxnzER!i%M<3^$8QTqfO6+?44?H9b1LJ2HnOSYAmhz** z^mu4$Xz{Vmo!76jF$vOp*cQ20FW+C!=#p0MAU;>rWej=H@TK6|sqyaDYdh>=NFCKi zZet!AouWeWq=I*!!C)9^d9~Y(Q0d|F@}&6KqnYNhQCF;nYu4)gN~v z8}$vdd8>;1mmrSLegZcicmPGg^31rYaEc_YXkZ`k3iBqp*yw(Ba6Rh$Hwd1wi z6*9gVjtUsvqltfitvcfKkC)G?f9c>E8Yj^T%Ffg0IkRZ2E=a`$1iP$Qw2#0@i-p#B z;ktUpc?wou~Ug7 zM^75gdk80}b=+s>G1C0hCi?&Y#03a>5o&OwkFfHmuN^B1x1;q9#ZyM%JmVnBgqFK* zl^>4zhaDqI6)U{oZneVo0rP$BtxRDi5OzG#}WdJ8BcBH0oS zIlw+dEt+AB00VAKSSOsWF}xetO0b8(F$`)@6mGz3=%kVASpIcK1_2Li@7PvxA3}&) zt*OV#TRLbzr}e!67AH8f0a}M&+xJRD77=2Lf-k|H11VEBfH(maW&eX~!zcU3tj`~P zlALol)GwWv%lKFGJKUJ!-S}0`m7dWO=^4G~iH>u0a!UEi)a1+!zm86X$^*G#i9V-* zbfk!%UQcRc(`vE*>r8qO_NdO8bB>@2C;rmAVaD9|?;|z& zR>#@0h#ngP%o|%z4}nBcU$LpbCpu9xR^ty$OpNP(v*b>~;DRia?~ndk!ZB}il(Yqy zlT5%bTo%b9B^ob=1>$#PC2{gCQW_DmmoANTdo`>*Y0FK#dpTNyQh_9;Nu>2pj&5D^er#-QxSux_MpPQt_iGNn);|&NJM5qOe4oYNU&m9j<5EuH zJQo+QVeqx+W;(A~x?6y;ZNFY$QttbthcYxl@~;1iZHA2NW?``@oKBB4~_Vj(xpTiMn3hLP$9Lf%c>n%VO| zZ`m;Tj6fh$9O47)?VsYRUDr!JImD7wy#6apZ&?kdS&vCwX|wxZ?%hL3V5>0rP~`X;Q!a6L03pYfQ`iE{>zBnfh(S#s~zNXU^at;r>0Nq+rDX&8!99O zeM8p`@tDOgFo7WdBcnS&d{FwSOskIH(%RYzK@rd{kOyAz)jPT@Ze9;H`5rcuwR&Mj zIDEXFtcUN02FkNTSU0SqeS7cl)S4O^tU=(HOY@k`uW+R*R_v|I{vWj!2Shl9;w@( zV&?yyey#{ST`pHrssLkog~^L(lKP1a!}+*Dsr2@GrI416#4BrnQtl_$nL!miNkOSG zj}Z}H(DSN_USOwN6(!A#{@P1b6xDm5yWO^P8R-K(0H*}GkDBtEiyvPy4E4^{l`2h& z))qKp5l3QI;6lS{e_ZrQK;ajxm)}>5V(OEY#?M`U$N12_b%Y)sK7c_^KzAS1!lRHd)yJq0KKL zlJ*%$8|Gn=%qMOl;~Vjwade3r6cxZCII4Z_PIbF|#Ssc&{&fdOe!eaJk&zn8FCIMY z*!|wDzf(*6;N&=FyiVKWjjfv09T7PrBPm&rv8dEODPw%Weg9#}(YdaQ(L3j#9~{qJ z8Y5$?Zu>tchTjNj$J|~q^0-De1%JMeR}SG z_GPdP+Pd)E1(FcxG$tlLN4)qUEWbOfPeppISngV4VPT=|u~g9wgz0Y2q;8NHP|roh>bLm}-9C(e$J?XY1Gc}F^2esl9$Y3b zOk?}-5(l0$Ar6Uf`T>f1z0o3xG4o=O{_>aAO*{9=^0SI7hOxMt=}+!-o#Ldg&T#Kf z?4~Q6icy&BBMH`qeh3m>qfFe?5l8qB+WMd0%l=rK1Y1roEPWHFtK!z+Z4BQ7G4$$_f#-up` z>;vd2kiQNYjzMUTrUOJeg11CPAS+zkL##sOSM0OWegKIfA|I4z;#owm%1+>l=m)%E zGtxWz2=a|k&*+B_Z_DTHiN_inNUGecpq$F_bOIz;h_MA$6_RN2GKP9X{lGYMU^%*fC*R3w0bPu;5xs>I^yb%!Q_`RR21(e*Jv0DWbyAqFYOtW|EqymCU&0=oa@vb=}*W#l@lt!L^WO69@GqQBeWApq=5Z2m`emPi7f9>#sz+}Tba&+yAtF|C48Siox zqXA%qM5eku{&?fJ61lS07iJh+!kmQ6XBztXR9On12!`@eR&Fq3pJF6$+R-?;H>W33 zd?7E2*wQ6Lq8;23pB{hw$qJ%0l75qa@?2v>cMO12 zsI~R`{7a6rdU;A+4S`Z{e5SKBp|Rvl@fi(1qh6WAVLC0L2X&jR4!iWh{>!R756@v9 z3)+Xg1$k-j#UIT$SCUw5^q4mqR<^#t^8?QbG>)no8#hr=M5>Ukr`qpB7t?V6JwWe~ zgz+8pZo8cyoTvho1O`c+W`6c2JA0kQ5)yG35}!_UhcGs7f!tS)Hd9~YrMDcK~GQY~yX(c~HkDlo0kU=YpLPZa;S zYdZ^3AWXZLW(RFv2(yQfVsuFZ_-U~*5Y1Hg;?~67omRVF0Zl(`k+GBE%2ZC@oz`zm)V>1>0LsSE;42=jU#{Bd@wa<`(tbz0`z4>Z1~8b(Rb7Skeii zaEpTDk^`{U8s#V3s4xE56O#R$AFME{!fZP1OciSQ-MhI@%d1X$KQURqph+s>dT70HB;Sw)jDxcL+X=><|LhFT&^X!l^F|qjN zUD?|mTYkrr2mfO4g-lF~OTFiP#LGCr2(E^tX_Yj8eg!;eDDZb`##M3+1T9Cmz*$hv zj}ygb!c1^}vfyELuqfk$B7O)``f7|fhN%e{as-z{+n?1ZG5vPUKifwa-;dkLc>a=M zW~P^^E0o94oh`R#{g@;5okiI8H;(}v4z_hf-vq_UXn^#Czi_nucBoqPj+-{ISX|x@ z2b2|o);-YCHL1J5Z@nu5bdBGS_p$!m@3OBtXkPwUBt=V%2UJpFeLan8gsM=O1SKiw z!$IJg&rohd-E3iDI~JT5h1rxa+d*;!&_+p3P3r5L7ZV};7>zKHY#ZwQ&Eu6CEipcA z@2He4#^YnvOS6){<5YygSXpj=%P~%Qm6W)#VbDxE$P*j#Z6T{VWfFZMSW~SJetf1> zPc=IQ-W3JvNPqIcL2My-tuND4Z}Vz?2XixWOFqjBBnIaO$R)bK7=|#_26`jDiufO3 zO}7Kl3jzmGcEx&25>#`+8ZT-F!)*7WD4LZ)4*tA6&R_nWeOSwjC3v*?X^G*sg$9;R zcp9_%WWn$SWE(8A5KMIzE-}Neqwb@xKn#uk2n3uP@Y8CE3m>*igKG-bYQBxPj`gq` zK8N}^u@xkugjzt$3B759XB{7>iEeC3E&i0L#xO;Ipxk4PEvp>XOF5En z^nQDWbAquJf6#tnya_g>-dW2$_zoh<%K=4jD^~70Uu){7N7Jce7^`>zGh!ue`PPOY zey;^Y+0ecuk$-FR^&6O8qY8_im1)xb&O2n^^2(xwgg6@bS!X?d$R9ivu#N|QNiyuVZmLqXCBIkph?KGWcm;jvAsFrRaMWA2$( zTlV0>2j9(_A0K=V$CK|r2sh*Z_+55{BIG)je5 z`56h*js4V=h5lGxx9G0j2qd9xJNz0is>^op#hXL#Ah)mV;j;yb!<{VskSI-=7_Ph6 zW8SGfL@zeV*#?_p%%puH+;uLoQ`n9(qEs}bfqnl9hvW%;T`d>gO);1XDy`&lFY7+X z2lU9qZod5Sz>1g5y>F5?!bxKNv0vRFpRH`g#|pu$iR4^?8xzH{hs@uH;{gIe%~?hp zpfV$@A^Wm>Gd(=|Abx^27XH7C$@GJmin4mXYd9B*RcO_oGtreg7nGMX8yOK{gg@1+ z;1d>wes1;a5d{_@r`q-%gOWvE4K1#6_lWf8gfmwtBs9y6hP6X_Uu+^`#C_~R5_^7_zJGjYr{=E0w ztm5vlRTHl}f=SOR2nuq;NmnP@B%UNS7p~uN4!IMAD@&2?>RP4wSc~ddbp!Vep0ai2 zxveib^f*Tc&fw>SB~d%}NEQ3jT;{VOo3?8F1wO8h605h}=YuHAi3(kv8T_`s;7v+$ z#+e+n)AU$E7(09SuhDvAN?N>t^P`o|Q0YT(uh;iaf7n4%htv7HcKwYK$qmSxYvnc4 zT=p^>NMp&)Q`J8Z2as*y@pY?6enL?lnyA9Zxg5OVR4LDth|R5Ygyso(2*XV$mhA~} zCetlTe(<)jng4le3oj#ewod1x>5E?4_ZJTTO1J-4gagTBYOb5y!I0(C_fTJ+NOyFx zkL7mwSEKDdmTFZ>o1bPFGLaRm!kb-Eh-$yY&i}3xKKT zT>8%z4*slN7eAi~oA0JNobA>L9S%p2!iRXjqGX}_M<3^lzy-$Z`b&?lh!YysZNXTA z)LZOKjx5Bd8qbV1(jI^1kFz!NAP7j@)qOylqjEYFoW^Oa?8Iu&;||sgIF@OvyR{0h zy?7?x#-nvrf@x~njD3@a#sCmi=9i!SSWXu?PB~_jw4ZdM@a5yMqJ00j0O5~xn+xDraJ=TLe z7^ZN(qNVpO`+Shjy#Nw+21;Biir`Z$*3)fKF!ID{JjJp)>}Eh?w2I|WeUOS&KoMv9 zp`QNGMJ;#y^JY=J4BkY-zfUy6t+VAm)iEe^7@te*<;&V%h6OB3K0;`lKPGCGa&n4l z`}*R{$J^&)E7(EK76;Mgzos-{Q`nTY8V&V>#~M0uKGm@d zUQ07>MB2M-hArKh`YJKWc4?~)CemuCm!xngJg7;m{z9^KdwKoU2fzg!n=&OkJP+?57vM_%8uZ zP70HS@}y)s9yK8@yf<7!;y_5dRxXQ`TnhYb`RCUVvoeisVI+7OPLvq(h*nWUve zb@e-XeJ6i{^B(Iu24Mm|d-9g`yUo6$J|kf@81s-X`%8aXooQl(E=hKc-I^ap7<`lQ z7&DPw-^Xf1XbeeWzZf?@o+_R}c2S9U5a0T91#BVTLDG|z5ErUw+9a0kj(r9*^6uGs zs|8JY7~~06q2zb}{pssA+4%N@E>24ihiK|&B|zPZnLz5mYnp&&eauert?;~spQGPR$VJ_d*+b4Qgl&Z~%V zD>IX2xcHL<=ko-6d+mI!ee~VJxW+6`!sD3@;^_!Wj$GIEep|uvAD@)pa`HVPsNLrz#j_!1 z$X$|WeF<4Bn_6Z$Qp!AGwPazv)dtB>w83$f%vz4ekX|@iVUvl1K0f+<_P`_37_nl< z$O3lF$tm0Zkvtu%3ZV0R>w-HFSO|u&6R(Vch0f8aA&WJJ+zhToA+mWzzHJk*A2ry2 z6OiL+6u(97=ZN0E-MTq8Gxj{_^4Nn26F2vK%g$}72N#eim|hLnkqX75A06jJv*mcX zyq!f_{(9krq)Q($u8WW=D2z(vvdJ=pmJ`}2*(TvBI}H647$RI;!Rt#QL)@x@pp}_l^4{n}aF#N!!`1wh2Uy`O zI-hEP9(=&~10PAi>kG_VxL=2*5ywVLLCb%H{e!_;V{L+hmYI>K$yMj7)^Jqmgc-WyDGnB2(>oxZ)C#a$mc{MUlMJ~&9p!JKw+!wuQC1pxsnGBtd1OMqI=9Di&3y0i|i zwb696Jb`kJy_*$AClz1bK3E39Be)oAm`@c0jw8y5h+vuivtSjuBrFE@(!{3A+H{Y7 zqigUni$RNx>*n_RMEQQsDCTDDT_^%83x$t!9JORvZ{3_fX}v{Og3Z8qZ#Ugqxr4as zWM^T#boBY@zhxlC<4i}?9G?s$q|v+$G5;l!C+5~ZnDlhVM9~GZNkvO*DQ!dvJLSEd zgU($wPVyT&E5vt{9P0Q#=?Y*64;&R0sumL`_ek&(nK!Lm<>;J4xsjSj{}CpUx-iJ81mGK4gGY#Dhm2~537|8jdJgsYGO7Qcb_PX zs$7-;ew6j+t8dYPHt`&g`y2$_fIo#x_QDu=sPio;>ZH}Ivi}B2A+-|Sl>{*iI|#QeW>;(ki%)Y z0V;mToqpGEn_Rxdl48z!YYe{`uLJyQa$#nz`3s2|O z)YN3ml_4%u7{#060*??3;eWe?)DUigqMGzac)Nk?1L?;^XlGDyNRPNO&i^gOL)QaD z>j`1$W9akrz3E%FUaq{?4Oq|)299nd*^V$G5yuotdh19|48k}3r}AbJaiYKj%_OX+hjfy_Y%&H{aJWQ( z!5!>hNFxzMGF@cX-*2?e+C=(eWy{uPW3egW21sAYxfDVPJ;Icpx6`AJOshAg z_m6GmpAt^UpJF^n5lKBA7PuE|`6=JE`o*X8_9K?9*|sZ@*Jwe1=Bx&VQ1b6*9avJp z%!E)qzdhaLj^Y2AG*Z0Sr0GmFNcu72L;cbrW~W2?b(I{jwj0(iIggSE?`WNT`$|Yn z!}Hv7{AXA))%obc`$S( zzb}zo&P0^;lV3SQ(~T@=_r=Z|Mn6LfQX*yuB6RT2c!qxG%a>T%ku~9|-6ObgLlvf> z(C2BUoagdM#kU`XvRAKUoYnr%3s5`-2}-Z&@@`Nw_6{aB>OP?hH?B5tS;?!c$=}9% z=5R>(*salqRi%w7ibVL8QbErvw)?*rqPGh)4q}-)y?HklU&$o}NWb5YllZZJx|@4> zOpn6zS?`K;gMb5aqyV+h?f~t&1n@!)=Ln-XEDnZ4_{ah*>>;(1KKZuRXafK2yR+yR7RN@)#t8yq33%+eN zKjw@n2p^s{gI5h0a{SCGeUJRnN*wW|b8SvDw6bZ1?86M*hEvML2GEVfki`e$-vlYz zYHThQW$)z5Z=1p}La{SeY%S6mAk2KjQ>s7CV<3qIDe*{RQ9|doNvBsw4P6%fE1Jfxs+*@G#lpR0b(1}i-!Bm=yF8R z0s6^V@wWiMpZL|i3CO|2D%1^(y^UIp%eQ|?G5Oxj*X#_%!mob(;|`?6Sbs1SSc0z$ zfjYy3$I8lTPMPMB1W?8T_MwVG5Zrj*9}q)Y1(t(ANQSF3(B`goo1asky=UoE%@>qB z%)A}kc*Sn4^8@3||~2 z>;1$>MM8$Zd9rscyVY5@=nB|y{+Mm38mXjwXB~C}_qm%N)F>sQHHt_?6d`7^)gn8j#p zXjtCQJ(WZ_Q3_TMl2u)r_*VDqV|^dC8S{V)OeL%{)iVn+CJcSJ6eDKAOF9fV z=)Dj}e-iXb)izh@G}PMRR1xqGr2kxRRN&F5vh7n!tYpC+ znk|xwFn7RuFYUKuhg|kxbo<=Vyr!9QN5L&G&G9MdDtmPNaq)bv z*eCPqENYKf&k}?!C#V4_NP zfw2*2K@cs?gN+)Ti_rz5j&Z)Ix0~Wf0tm)sgn6;Nyo_Wvz!HqhQ?v&s3eQi@YBr~npXQHvyb3=Ao;FJ1s*{*!hFeQ@zB z&vs1M=|vjztg&}xa0cf@CH~~qWvLLV3MuZp7HGHZ-hyC!;0I7$B*Qk(Lfk~6vhewH z&r)x;f$N17jz19XkP7rYpLZz)TJeV^NA3nSu|8Z8W{!Qw6KB}H1MwlLDB5jcY zl`F*4YJn`Mtb%vKCJ1~M)Q!ll6`5E~kz_m&1~6LzECV=4W=nmqihsg?gsy!yHPQq|f-rdscKv#TGPb-F5ua zE(8+q%T9XsIgc}csLM}s7RxO9B1GqRz>lQ9;q?3f?z9@O%?Fal-Is*5D;78TLggDe z>GZZR^L}5gz|x#7Pth2~=orZR_mh(Wv)l(IJiMF9LPpp&h=CSx5+Fwu{WA7O-KrI} zj)i#9twP%b%EWu1NOWZjOUDIw$}L(WoKV{)X9)NdeP04T=9DTFCw7@ zygbIk7c1rrDOU&$T~NHc%K+tO8GyuM~5mI?hpl0^_2 z@%OrrDGfZ;ODh99FlqHduJAdq1i(s8UcszX+*5^C*Agh&lD1oUtIp+U^jT&ceJQf|I_5?K?ABC8FVZi}LR^)X9 zGh9Y-6d)I@fXj=RO0ch7L55JM)gCmcvBW~M4GcupB5F)bX%v1Ck76e70tYfUVgN-u zwzxRD@)TSxAh2x2+8EkOPdd8}StING)inq$AZ5m6VBFh5z$MGhsJ~-r=ZyflDG+@)pKcVYGZ`R8b;GuB(t zx_(;bRN5>r$O#T$tk1GOm`H~^SHG*1e46s>AKruT3F?OL%<+yec*mdw2qtrjIdP>F zb8^+g*xe)?t=d;CaQN}5W%G~2SC_r#$0qVZ*O^0MO8Hx73rAtMxx*!$@FgqchNaxoSt5bUb3qsgDDOb4D){9 zuZK02Zd~AC^V@k(ad`w6ISc!8rC1pmI@Le;?61}SERF+~6vrb8PwRtuNy)=v4zRJ^ zW6TK#N#30x>)(;v;G>@MKOGTJqFS~57}+xq<^tGrz4(RQjIxdC~ormb6U zLbpg&CC_##{yRk_yh*=&x#|Ct)2vG)=tM_V{VrHnX8R^Q%|Bm$Mic7ro?~&Is&f*U zeWj?3Gi1`cyw|z*4*=7cG`F2Y*`q}N{J74nqw|1Nv`MSO7{&dZ95+Gz4UnSuN;LxT zpgj`7DcYj-(-Q`>l4sWM>|>32Tb3nBEgGYF=4&GOZmR%TP(6K*WRKxd;|GZb&LOxi zh4dQzJ3K__lPp%1jZ<^%c%i|t5Ly1+v={+DCT(41>7p`})Twu4#z$e;{ck;aUJpt^ z^Wz`raFS5^xzb;z9;{;~{AR|yuA^{&;&0)x;j~wT4IF=fr9@6-u;<~!mNBh-eCHm# zFF=+BmG#zLbc{}d+h2nLHUKAAePd&-{VtsO$o3Sf24EAALo1v9(1A=@h=bXnN;fI% zx7-tDV-M<;gGco~d!}`g!NoBHn?629bSUY6Eu%jWOq2JPfug3;?KsMJhlk!%Kg5`5 zN;Xx?kR2_!h(L-VKFnmLn7G_!i2;u?OjWpG6KZ7T*H=1Ta}*c@iRjt5sG{2FUypKv z6#QZbSt5nQOYPm2TK=1>v8XvdPcCPp=Q%la@6OwrqOCeV%I0p*^jivizau+_cQkgx zOhs!-CCw8d{~^FljLbvU>SOeEW1g_qxu;0BdaI@GYRQAz`Q`Ve*%^{-yT37qN|JN8 z*>;Y)Bt%#CeeGKtzV|M>ef~1VKlNbRld`zW`hL8WW3N8F*i%fvb0HVyu9gGlAIo5%DuDALWzdZbPG}LzZ|yBG`Yd+0Tlv>y&CGF=$@|M zJe!m`C)o^NJ8xGSH5ND)#J!h4bi3JkockMFjthk`dQ9RQ#c-kZp6_!k7@vdtPx03p zZqNlB@FQ6w0Hn)vIXlV;q_@S>ke5$%C>UfRq2~=QwylS7SYw>oHLCv0Z>jf1K{SLs z8M3MPOPW!R7RO8tqD9CCSkWxOj)FMgRL~dK|NC(Rk^cwOn)SeZ=lZ&SYN`MXKz1Xq zLKXot#nG3?j%O9@`^W{op_a?a$A=P8Mt~!XT=`+Kv9-|F#O(RvO1tFY@~m}xO#$#yO)P)CQ&~;Ooe)qmAS!SPvn!w?-&hh)2 zn(JWB`K^6KxvG4n=97?E!abfxm$r5_5a)jmXqKs-`(YzF+MX<(nL!y2A@yd1EyB<6 zSV&UM=ZR*~YOF|d2W?&Sxqic73IMZm)Az`MXE#LC@q=&JL3ZT!^*f-4pVLS?}I^5TVB0y8eeh;3pUmvjtfzkSnufSb2ZZjX6z z|5F#+yx4-wME0IK3WluRUJcVO^XeHr+HR|OsknuGUo7QS)Hv<`q2t+Z9znVUqkjO9XB9a|^cJMxTyC99ZlwA#n zDd#@J%VEB^qSW$54Hac&cZA5FaSe^W;rI+uqfXp zTql(~|NAcM%bKm(Xy>|zJhkn!TyN77a`Y#;=lgXzu=Mo6R5+^K2b-GreWv2Y!;|{$ zf5^7x+X(6D#4ww-Y<_UJ7BeLee|W=gv+u_GQqf5TA56KdR=Cf52_m#S<+5A?85ei` zO~V`<%acfPjs_`J2GaZ;Is#YUW!M^O&xrtcSv8D`~F5jN82|M7N( zj0J-D29jM#{|@1un)-hkEgQnI**=AiVEbrw3r6p4}Vzw6z<~EBS3cXcaHl&AKF!%T>G5|uV1az{untBb)vzfaJ z(BB($xpPSi)^LFGAeT1q4*=a9wA}B&)DsmoaGf+r`TYM@Yq%JJ>cNyg_ye3VTVKKA zfgHRd`s!+G{14J|<9(^FROq~8>~siQ-t$4)$EmSyHPWFFQ(V!l18L+F3uj&&(g_R- zzsWzK0oi6Zf%uuE*+KR6aP?Z=MmUf}boFe8K7S<0tI}n>6ZTS>tUe~mCX>6zzl==A zfcqp_qac~+Ka6L$iTgSW@h)hH`>Q9PB6=vsmXrt72reWMBekpB+k~;UukNxp_ zV02@x=jsd#%je&1fcfLWHs<2o(X73RX765Kf|=(f&+D!A_VFMcNWQIYPshJ3JkvKl z)-(Kkl!|U|q{_iU`;?4Vwc8WN;xTGWWYRbK`Wu;j0`pYL8dcVAW_nEZ`e zW@&UR5>E0ZD!)k>wAr0rJflIJ99IapKPIu5H2+O|xL0Qv7y&tI*!rO7l@9IfA1fQn z`V2&qt>+u1($8audJaUmG7v|ZdpaM~q6wiV@}L-m%m_R{LQ98^+WF>bdQ|s0Zw(0GVP%`Vk!8?yzszPP(HCDFr#w5u$o+Wiu~xJH9tQVE zo$`cI;Rv>dl0H{fPp_KGJzGS#%lz?NlTlI?M{u#&@b;kEW)jyxTy1<3!JSS*r4&A@ z__|^pHq>xDTDnRwbClx4#(vMW2H%Uj3rcb%v9f3?=l?Ls>~AU4`S^l*i*is6+eat@9C(_n<7uPzI~RdzftP zc>#`665v^IfKdi(9z%@z=N7K^_U5i6P<|8?kN61}Po|m>|EBFNmB68Q<;w_f2W~4K zJ1}N#og}`z@p#*E;85T zMD#wvz8vmQ&~!lQ4FOs31w+hPPw%D@F^FvNWFl2d@ZteB8x~N95i!3m6z)MbcoASX zu9@*vN`jC@=2FNbXJ*zwb!z()MWv(+)sQBI<7Tva9mgSK7Ur|M2b8l&SwL2 z3plP^xsv&Fz&Y10ixtX-_+Ti7FKd_vqcNae2I;VKY)ru`3odR$(v2@OvZ4ce{e<&7 z|I&{P%&rCJR5?XvqcL!1!>VmHT$WHpFo79VSY)#Jf$1v!)EBJS$= zcpc+;!vyEC)0gVGR$bn?+;${}f4a(k|kLd zqk8G-sm1X9gT68kh3x!WPB;|J)%7`r0z#Y)L399vg3`g!PFG0$L|)YsZ*s z;8kY%T>q*3(<|{qJM=N;?3+^=l`QA8Z;n1W7ovBe>byR!?E_Z+D#N(#%~bW9-uWiKb;cNVQI2~MLdB|{W*6#u83mjW(@_BClKqU(C) zc=USfpI9_osMeB?M}pwKya*PY>PMH-$Z_>!jt|k95K|-zdC|MCwnp)f7{3!TRupTo zQ!3I(dzkK<*aTT^&OZ4wkQ?}W%eiEbh3}g^XQYoUN5$3gs`w(fc&;`}q_4Ng)Er zTOfKG_@!O@#ZJ-HT;>)tdRq|+J|?!sJlU% zBMW6%dbxPU`t4|#27JGmNV4Ii76&Z<~o0^vk%YVlV!iQo4 zqYhJh(xwKtx9Gmn!SiS8uXRA_lj9-}gH~rIGhfWbi^EHNJvBzklDi^K$Hm&^9?h&* z;iL3y)t_n|kX(?&4plB;RD9uY6a21U7QX=1F*=%stHcW~D$R%b_$HHysx0}N*k4^U zL*zL!*Y@$`Oc9zu5G&&AF>1XE^hbTtE%G1BQQ znb}vwblIg}ue(%@vbSV`pwqs)@S(D0+G7aHAd}RAzS+!ZUfKz9_)ER=IdPhX3s?T`(37)y~>o*KI#7M6mJ_V1t zk56-LxO~agJeAe1P;(kVeG1wAqRi<{MZmjnu~yWmi$1e6J^t$g#|lW&NWOWX*FQyQ zBLr6hW_w_KKpq&;vp~rzU}wx$Pj_yA3#uB>(m;?dCX4&HJoDb~HoT5A&%eT<^%z#h z=H}*|zesSfYoO1^*zb2ktS1dv#=vWw$s5R+C<~unIZe{&*ACRWdWxX)A|-yH@Yl7x zkcI!`ItxD;fTfWN#R`=-^z;2Y&0Nu$_JT={b#j@2c>SMGCXPiEIATE|SZ%z^fyTIb zgdz`gCfn%}3if_F!=hwa{267?{hfZZI+sc7w~&}FM_781;_O5YM17zR6}P$Zp6>oF zAsn_WiIk=5EAd?YesQ@Gfs~C)SBB; zhAwqE;@jG$&%Nygk7q6?fwz#O~XH=FHQw_ zpH{f*@T6PRzA(Ey2}(z^1yWg^ISbu&EB(FJxpqIE^pHUo^2`IFsfxD$+7_WHb?Aex zGUZ20-wf*BRS91TJSo3#=^^WHF zVxxAOf=(B!&$E9YnUA_29P)fbTAv?X9x}f(rJsD5j`~($j8VH2D5VilfTw|;gyU|CdHhPn?ddaP@#y+!yhxZoWRgCz{ z-sPiniH?s0By2JH*V~g;WT|QDYqCbMzYRo8vXFkt(3I#e$6U%r)mwV}O;`{pAknga zdd=)?DIGB@)2#zlwR&kv733TwA-ztyjR5C4_G z9;lC3|D^h9wz?J2iY+3`SGev8dwE__#l0GJh}{hL^CZOYzjb{ z733cc4?;(KtJMJf34{iSQGXEVtrMwCGn4uJURg{SKX@8osGU!aW-FD3G)>SAB}D zV8;yxUG_u+QB0fM<^OpBdOJ+FEp~>oE8f0KDjsrm5;+g*;y38JmRE|Ypn6$uGWyKD zPisa(8>UUyWm9GpmymGV-fAI^O3c1h#Vl5nZhY)1kLtJ9{rb1G z4JhWjb#^%+4%A04JC1395kcbjFCh4}N?Q#$ZO%43E;v0bf5;39c{STS(wa-O`S$g- zRiXQ{58uA*c<#KJ+%~?J<*z^M*T%p{6^SKYm%zfCe9C3kh>k=lky3g2+gCq_-+6$= zMHjimO)HajuWm&95dDI~y4EnGSJcJwl*RB4Yce(iSqH^{ooX`!#b_l;i!|fq3oaF$ zBMcU;i7ead7sa|?oy#C?+DwFlnE-p=0;cE({o|^&N%dKMNQ2ncVh25l@xctuDw4jX zHL8=s&EK=eT?&aw4B1=WJXP||*5KqO{ls~HWFk`Akn~ZmJ*6*BX!vN*_C7G`KDM8q z62Z^m$V@VhEyo{ydD&{FI*uDtLll( zaBeG8O?O?C;ArkX#+bglrj3g$agO$#DtMZ}qlo}4iyc_@yJDah6rk`Uz^Vo(za*nY#M-|&-%HW+xpNqBFW57mKz0-ScK z$DC+mlFzSUqQi6UA@YVj`SETCyAtvI&3Oz0X?2toNi$>#q;sp9AD57+ZQnv0yY)2b zp9t4fJILxqIIkVP~EhP>nS4<3O5_9OYMH_>Jh0lAuGie#tn zH*Hstr4Z%a_N%g|=j6+GiRn&5MQMVI2b{Z42<(lTiNKq^k1~c4~-`c%lH$+8y!B&Bmjec_9i!w8f#KK@?Dx8m$Xu#V|N35mhRm~8K%7n zDRueAe1!sjgOJ(-t#mXhZTeFdkqX*@=d&V#V4nAPVOf#7sit%9(T+RU!^W%N!O=F9 z&nF4y$xc_D!ZgK|O(t9Mnl`zzFjfOma0tkYJg18nSUz`;7Unh4SSjcZzoxh+KfSNd zYEfT7fko+IB)H~5q@sFNNJ$h^&U|xOl{g1V&Wd+l|6R!Gaqa-1)^GSgb8#o6V0in> zZoY%55*paS1LQGZTEHF6cqgBT3GbMB9i}w^kN{!&mADs}pM!_pR`4tzU0pHZ_HnX! z6Gmxq@s2a#QaSiZB`Pb(1@12q5fQ7H1)L(+wNK*UWME8eK0`abf;r}`k1p|B-RNda z6rU~TwFA0CxgMvqEkY9hB0xUC1nb-+I^V5$s1QTWZOQucOl-_fT$m0VG3LO-4)Ky; z641wuT+q+5`@V*ehmW;3J)0>r-dIz@{3Fj6Wio9S(D{m0L5?)q+v=%S?k}qlGO$G> zXe(3SpZX}wd&70}+=8q^E!XT+%Ou5AGt$eKcy$Ohr&lk0RqvsQIYje5*w?fS zyrNZtPh177s_0V;eK#Mr@W82^NXi91MP7qC^&fA~{ z^S5DWrt8X&f5(Pp3}`lu<8FrgWB?o&;8h{CXAuhgLz3I`Nsn{yd?zTVZ*xt@zu(EX zXp%!*eC{TmdrNp2s{VV{m%lyNi9BvwSnQ(%iwBaGDFd%x360fB-9GG?2K^Rl9-b>& zm0Z(X9)-mcdcow z6emw*`^ycqdImhi5enWjHZ--}h@Pm2r$f-Yafy3C`nawpf!ZUwK7HdIzt zs@|5i!=|p@Qf0SDkiEKLEi=-sWGZJm0ul@t)#Fr3_t75N{Z?5&rTb|W1Bo-Hr@_#d z0xKRE`w^xCh#7fh9DcMiKg3BbrY2~ zL?1+onfK@HhdzmrzI0QNQxHh)g!e`~oE*z7YdIn8t+49%;NUkI*q5^)2a4BmATA8P zHAy{ZWJ3h`ST+_|yj-jcxiD@)3i*GZEZ|Fv;o>q@1QIOe#~nMccw?dJV!?9qg97>#DKW(Id1 zc#$|?&9T^!jET5NPL8tVeTJizlvg}C_0`Hz(e|quHlH%ZeJ2b`oTG#RTZ{G9ztWEA z^Nj(-QVUW?U4(%sr8LOJ#`Ftdk6z5nuXS-Fua}9L>UE3qXb`$6;ii#iACWek%#&Eyb1zX7?6<>=D zq}pz((5*-4sTK7f9f#`u`AxyW{2^_A%TQhLOTMG^=b`f4TLb7XuM98;yJ)YC>5kS7 zdsh7p9{*;hTUv1EVgTMcwNrdA%O^&dH(TQXg@F?q3;~>^&(b+H#eZK_Dnja;S&7Ac zY}R0Q_QuGoK+}PzO~m|b;kJ!7$uQV|6&%?HT*lMD_v?$pLjgWV^o!uXuioek z-I7n@-Wl=~H_`r3CX{F+K=n27^fyv#fc!yck+93;h)S zmjfSIn!l$l5Gf?iqHJ}^0z2qijIlGF$#YLWX9ETvspkS+(k4|argbv%0WPT@+xAd{bBvoZQX0e<91rgR~K*Lq||Zj(2avWT}EWjEpECR6|)- zCU7^cD9q7_8(+KTAG2;PTG45`YB5pN=l?Kl8gTr?#>SeTH*C7?bKhQ`U%W8eJx2Gy z9(#5tWZ)JDTU6TUlcLwfzal1YWNQfyEyd?Zyge3^*gRn$6liChwe`1a;tPc|!VM-#_Ri&^nT$l7LD4dbU^Kkdxt8pKi6sxI9}=A5mC0 z4NbY?VP)|K=lGtxiM5+1aTR-s;O1C3UJbt${egPnxzMX9RGog+Mj)5zJ4%Qszze!u zd07963bl01i^uQ*(bOY@fXbvp!zYgZ0~e2ewHZUm*7c zV=oHQNh(R_LTa4H0XdpXO9_`3-iFwj*T-7MU#V9;u^ig~#-kzlwUeBL=uv7`7mjH5 zbPADoZo;vfa-WG7_HGT?eRIqUmP(nMLE+Xz)a$Az*VC$H z%(PMB;dGb`ACfT(Wk^x5OrLwD)QB}eU^r#P**jXRy* z#S@&Ve!^1mhl;dAQp+l4C&b7~2ncI9Ao)Ij`KX2J@`U%&$TRctFuv^ks0B~sQ%rVH zPd_F3IV?AuccEW3z99>I9X?7fVit$~KSTezg;agW9z{8G7TQMdPmuac%OqQsI^qqc zS1CNvzYX%0*#}rEF`KGywS2L&82Dk!q+lGXc&DPnTM7jo?g2Q{1`fHpiCKjBQf8=O z!Et}AlBJW)29e+%^NFWw|DM??WaIE<#RHN7jHSrNoB>SNAbAPa)}7VBXNWQ)1eTsD z_qn%HWyI-Wn+ddJxXXa8OhQ>LUTrcL(E<@!6ot^y+?eU&~Z}ar>>iX?1*r9aVkhgPJ4T&?U z3jQRGNLGHW3HE=$+d^}hp>V%Rf%Rpd@H8~U7KogE3_3#!NZ_1GRW`hM7y9_w;-kYb zVOqVhkl9(jrg;~%#&>-g&}sB2`^lU;aS84h=o20}nFV+vQ>yBZug8Kodei3fY>gI| z7Z@`a+uo9A&m!|3#7|Dt<#+^~03QR!v{~my=7G;bYOCC;okf@>q*cH@wXo5-$gC8i z!%7d%dQ9-S9uM{=8F+?iv-?Kuq>AOz2nwskc>TkEMaXy55_qa}XK z6l`*nCO>Ct_A&l}?YM6=G&;8)qH!s}u?+BPNUrv-Pb zt!OFi&vHJ?e*fM_2##dL>8ML#wR!)xlr43z>)`($c67o!Kn!Dle#2OG4k6kasQnuYu11&&m_LJ!CT#dlbDeONh9RT(Y zs)F8r;grW}-7)Ds;T~$W?T!O!@)$+vJYZv0U_qH(4MoAvR35WMcGFD(fFb& zHSuSmw4xTgRw4jNi@nO;8Ef~#i5vBo6`h{)sC^XWd^YEsW2D{L8Fs*c1FrD+x)Jdh z;TL;UvCVnn3waRJ;19a+Z?24SZy74!& z3Afm!v(7d}hz!K-JtqNBm)17$%!vUhyg5M-s~ z{#M;l9icxeXU*#JB49UwA$1}n`YOS%lF|r9&aHoczK7?=dw!cvDGDc&-WlJ!OXE6l zBkfKCcX0n##jZGZ1sX%<)=YRRlmY$nWK_$zaa*~b^v{1xnv`Ne@pvnV;9!p3`$M#a zQ8hs5^bvRy> z-$Mgca0Dk= zW46az)`WKwCJfu~i}K;BK10(w6VtUpy)}O9{XNPGqA85gKq7BBOf3c_5|0++xC$yIj~5?rr`cG* zF6FTa1q7U|aHT(0tR~YCd@ zUUXT#fVCc?oH(I+p@i?8 z3XpDWhqC}a!-N?`z3>NLP^#qLyPeZ&t{AjObbRAcN-}RC_ymwy8+GY3yZv7`Nl76H z{NC?h?ftaSGmZ;~BU(?nRgIGc(+sTWGnws^`;E{29ufI&W^rif zQSJDXK~*I)k98Um6;<`UONz;Qez<;Sxf^gXa&`vbOu$#2P} z^?R4^zda(tx(+X$a6e8Q)q+G@A=R*8ISw+GK}%;+)EFca5F zCb3m9EgFq<2K>4O(Z!i-AM1PvjO34%wOXGwiEmMAqb?sNJA$a`0Yhp*$qF=saAOg| zX^+HV>sjH67In0T*5epx7ea&Ta`=~P>x{RiOzOfpP@neg!dj`wWpMIJI8IL5+>U?h z-^?9c1~wnF|6nw2{*^Dr_pENL;<~sXWBrRydxge4&pe|vlW8m$iq#Vr-c;A{U~(2H zY`SC{ zMhm?$d#cRJy;Nna%C)@rg|smBC`1C`eU?wTW$873at`6^S)v5-@PTBBJ=i}tHJ``L zyVY;9Kd3a0LJ)#Tm-FVMMCLmb`FD-|vC=NzAFP;lcf^fqPY$uX*Z6$ISnClZ?36pV4+z7;Q=)@3K< zbC_U;Lisw|+|LGmS{46dZ(r1M;R8oCHhA5(dfI1Mww)1;D3vXGEtDY`4l(kKV%%=N zzTa2IwoOL&0ZPWVsw)=2%dO}IxMJ^Wtf#8j~d+^u@=7DC{@1oRqe

;r?ng4Xr7+mXxS`NI6P^xC4{U#Y1sn=fi8TQ1@L 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%0D{|lwGpiV}dH+oMS^xtTunkzP0~LT>$J8@^JMT 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 ~lzgZu>(L3<_f>D?9_hw;fc?p1^ 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

(r?NX%#lDplwG6(gA|o#*54het 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 xuaB;__; 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


v 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 Interface -> Socks5 proxy -> Add values: IP address `localhost`, Port `1080` + +![*In case the service provider isn't in the list, insert it manually*](https://youtu.be/oSHnk1BG_f0) + +**CLI** + +* **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 + +Follow the instructions and the Monero mainnet will be connected through to the Nym mixnet. + +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) diff --git a/documentation/dev-portal/src/tutorials/monero.md b/documentation/dev-portal/src/tutorials/monero.md new file mode 100644 index 0000000000..2e9e78c2bf --- /dev/null +++ b/documentation/dev-portal/src/tutorials/monero.md @@ -0,0 +1,42 @@ +# 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? + +The mainnet service provider to Monero over the Nym mixnet is now ready for use via [NymConnect](https://nymtech.net/download-nymconnect/). + +* Donwload and open the latest version of [NymConnect](https://nymtech.net/download-nymconnect/). +* Click on the top left options and go to Settings +* Go to “Select service provider” and turn it on +* For Mainnet, search for this provider or insert it manually: + +```sh +i1TiuoNp4jp9weffCW7tPnkb4hRTPydRjX8iXFVaYDG.88Z1hruuvbzWpdCE2xYnTbPNrr49j4s7mmUQC5wvRRLZ@3EPuxwGn2WP2HdxybzoDa5QsohYSP76aQQRUJuPMvk23 +``` + +* Go to the main NymConnect interface and connect to the mixnet + +Then go to your Monero wallet (gui or otherwise) and change the settings to run over socks5 proxy: + +**Monero desktop:** + +* Settings -> Interface -> Socks5 proxy -> Add values: IP address `localhost`, Port `1080` + +![*In case the service provider isn't in the list, insert it manually*](https://youtu.be/oSHnk1BG_f0) + +**CLI** + +* **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 + +Follow the instructions and the Monero mainnet will be connected through to the Nym mixnet. + +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) From c0bb5503cff5db66c3c5fb05eace8ec4e253db27 Mon Sep 17 00:00:00 2001 From: serinko Date: Wed, 28 Jun 2023 12:28:20 +0200 Subject: [PATCH 09/74] removed redundant copy --- documentation/dev-portal/src/monero.md | 42 -------------------------- 1 file changed, 42 deletions(-) delete mode 100644 documentation/dev-portal/src/monero.md diff --git a/documentation/dev-portal/src/monero.md b/documentation/dev-portal/src/monero.md deleted file mode 100644 index 2e9e78c2bf..0000000000 --- a/documentation/dev-portal/src/monero.md +++ /dev/null @@ -1,42 +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? - -The mainnet service provider to Monero over the Nym mixnet is now ready for use via [NymConnect](https://nymtech.net/download-nymconnect/). - -* Donwload and open the latest version of [NymConnect](https://nymtech.net/download-nymconnect/). -* Click on the top left options and go to Settings -* Go to “Select service provider” and turn it on -* For Mainnet, search for this provider or insert it manually: - -```sh -i1TiuoNp4jp9weffCW7tPnkb4hRTPydRjX8iXFVaYDG.88Z1hruuvbzWpdCE2xYnTbPNrr49j4s7mmUQC5wvRRLZ@3EPuxwGn2WP2HdxybzoDa5QsohYSP76aQQRUJuPMvk23 -``` - -* Go to the main NymConnect interface and connect to the mixnet - -Then go to your Monero wallet (gui or otherwise) and change the settings to run over socks5 proxy: - -**Monero desktop:** - -* Settings -> Interface -> Socks5 proxy -> Add values: IP address `localhost`, Port `1080` - -![*In case the service provider isn't in the list, insert it manually*](https://youtu.be/oSHnk1BG_f0) - -**CLI** - -* **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 - -Follow the instructions and the Monero mainnet will be connected through to the Nym mixnet. - -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) From fbcc2907bbbc40d3b57b4e703dca700d6cc4e6fb Mon Sep 17 00:00:00 2001 From: mx Date: Wed, 28 Jun 2023 15:31:39 +0200 Subject: [PATCH 10/74] fixed dead image link + added monero x nymconnect page to sidebare --- documentation/dev-portal/src/SUMMARY.md | 5 +++-- documentation/dev-portal/src/tutorials/monero.md | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/documentation/dev-portal/src/SUMMARY.md b/documentation/dev-portal/src/SUMMARY.md index 7f9e1e7df7..9e47db42bf 100644 --- a/documentation/dev-portal/src/SUMMARY.md +++ b/documentation/dev-portal/src/SUMMARY.md @@ -35,6 +35,7 @@ - [Building Your Service Provider](tutorials/simple-service-provider/service-provider.md) - [Sending a Message Through the Mixnet](tutorials/simple-service-provider/sending-message.md) - [IPFS Service Provider (coming soon)](tutorials/ipfs-service-provider.md) +- [Monero X NymConnect](tutorials/monero.md) # Community Resources @@ -43,10 +44,10 @@ - [Community Guides](community-resources/community-guides.md) - [Change Service Grantee Information](info-request.md) - [Rewards FAQ](community-resources/rewards-faq.md) ---- +--- # Misc. - [Glossary](glossary.md) - [Code of Conduct](coc.md) - [Licensing](licensing.md) ---- +--- diff --git a/documentation/dev-portal/src/tutorials/monero.md b/documentation/dev-portal/src/tutorials/monero.md index 2e9e78c2bf..853eb9e8b5 100644 --- a/documentation/dev-portal/src/tutorials/monero.md +++ b/documentation/dev-portal/src/tutorials/monero.md @@ -2,7 +2,7 @@ *New Nym mixnet integration launched for Monero desktop to secure the right to financial privacy and censorship-resistance* -![](./images/monero_tutorial/monero.png) +![](../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. @@ -10,7 +10,7 @@ A team made up of Monero community members have successfully set up a service pr ## How can I use Monero over the Nym mixnet? -The mainnet service provider to Monero over the Nym mixnet is now ready for use via [NymConnect](https://nymtech.net/download-nymconnect/). +The mainnet service provider to Monero over the Nym mixnet is now ready for use via [NymConnect](https://nymtech.net/download-nymconnect/). * Donwload and open the latest version of [NymConnect](https://nymtech.net/download-nymconnect/). * Click on the top left options and go to Settings @@ -23,9 +23,9 @@ i1TiuoNp4jp9weffCW7tPnkb4hRTPydRjX8iXFVaYDG.88Z1hruuvbzWpdCE2xYnTbPNrr49j4s7mmUQ * Go to the main NymConnect interface and connect to the mixnet -Then go to your Monero wallet (gui or otherwise) and change the settings to run over socks5 proxy: +Then go to your Monero wallet (gui or otherwise) and change the settings to run over socks5 proxy: -**Monero desktop:** +**Monero desktop:** * Settings -> Interface -> Socks5 proxy -> Add values: IP address `localhost`, Port `1080` From 8d2ef605ed34011011470704be763b4a064f6ab3 Mon Sep 17 00:00:00 2001 From: mx Date: Wed, 28 Jun 2023 15:35:54 +0200 Subject: [PATCH 11/74] quickfix --- documentation/dev-portal/src/SUMMARY.md | 1 - documentation/dev-portal/src/tutorials/monero.md | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/documentation/dev-portal/src/SUMMARY.md b/documentation/dev-portal/src/SUMMARY.md index 9e47db42bf..c9ad0b8d71 100644 --- a/documentation/dev-portal/src/SUMMARY.md +++ b/documentation/dev-portal/src/SUMMARY.md @@ -35,7 +35,6 @@ - [Building Your Service Provider](tutorials/simple-service-provider/service-provider.md) - [Sending a Message Through the Mixnet](tutorials/simple-service-provider/sending-message.md) - [IPFS Service Provider (coming soon)](tutorials/ipfs-service-provider.md) -- [Monero X NymConnect](tutorials/monero.md) # Community Resources diff --git a/documentation/dev-portal/src/tutorials/monero.md b/documentation/dev-portal/src/tutorials/monero.md index 853eb9e8b5..24b5320c54 100644 --- a/documentation/dev-portal/src/tutorials/monero.md +++ b/documentation/dev-portal/src/tutorials/monero.md @@ -29,7 +29,7 @@ Then go to your Monero wallet (gui or otherwise) and change the settings to run * Settings -> Interface -> Socks5 proxy -> Add values: IP address `localhost`, Port `1080` -![*In case the service provider isn't in the list, insert it manually*](https://youtu.be/oSHnk1BG_f0) +![*In case the service provider isn't in the list, insert it manually*](https://youtu.be/oshnk1bg_f0) **CLI** From 131952c036af3cb5e621fe902d91d4c0e8c876f9 Mon Sep 17 00:00:00 2001 From: serinko Date: Wed, 28 Jun 2023 15:45:12 +0200 Subject: [PATCH 12/74] changed video link --- documentation/dev-portal/src/tutorials/monero.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/dev-portal/src/tutorials/monero.md b/documentation/dev-portal/src/tutorials/monero.md index 24b5320c54..81ec844d74 100644 --- a/documentation/dev-portal/src/tutorials/monero.md +++ b/documentation/dev-portal/src/tutorials/monero.md @@ -29,7 +29,7 @@ Then go to your Monero wallet (gui or otherwise) and change the settings to run * Settings -> Interface -> Socks5 proxy -> Add values: IP address `localhost`, Port `1080` -![*In case the service provider isn't in the list, insert it manually*](https://youtu.be/oshnk1bg_f0) + **CLI** From a3da077ce9447b034c278d166d53d4a65e7c06e9 Mon Sep 17 00:00:00 2001 From: serinko Date: Wed, 28 Jun 2023 15:51:46 +0200 Subject: [PATCH 13/74] reverted cargo.lock & changed video size --- documentation/dev-portal/src/tutorials/monero.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/dev-portal/src/tutorials/monero.md b/documentation/dev-portal/src/tutorials/monero.md index 81ec844d74..af035c1be9 100644 --- a/documentation/dev-portal/src/tutorials/monero.md +++ b/documentation/dev-portal/src/tutorials/monero.md @@ -29,7 +29,7 @@ Then go to your Monero wallet (gui or otherwise) and change the settings to run * Settings -> Interface -> Socks5 proxy -> Add values: IP address `localhost`, Port `1080` - + **CLI** From d47633faa8a40fd64c9bb0e8d429c43c4b1db0a4 Mon Sep 17 00:00:00 2001 From: mx <33262279+mfahampshire@users.noreply.github.com> Date: Thu, 29 Jun 2023 08:47:10 +0000 Subject: [PATCH 14/74] Update documentation/dev-portal/src/tutorials/monero.md Co-authored-by: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com> --- documentation/dev-portal/src/tutorials/monero.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/dev-portal/src/tutorials/monero.md b/documentation/dev-portal/src/tutorials/monero.md index af035c1be9..77439d0728 100644 --- a/documentation/dev-portal/src/tutorials/monero.md +++ b/documentation/dev-portal/src/tutorials/monero.md @@ -12,7 +12,7 @@ A team made up of Monero community members have successfully set up a service pr The mainnet service provider to Monero over the Nym mixnet is now ready for use via [NymConnect](https://nymtech.net/download-nymconnect/). -* Donwload and open the latest version of [NymConnect](https://nymtech.net/download-nymconnect/). +* Download and open the latest version of [NymConnect](https://nymtech.net/download-nymconnect/). * Click on the top left options and go to Settings * Go to “Select service provider” and turn it on * For Mainnet, search for this provider or insert it manually: From 6c3653c12849128e8fb20e51b81131d6f670ab46 Mon Sep 17 00:00:00 2001 From: pierre Date: Thu, 29 Jun 2023 15:44:56 +0200 Subject: [PATCH 15/74] build: new workflow placeholder --- .github/workflows/push-release-data.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/workflows/push-release-data.yml diff --git a/.github/workflows/push-release-data.yml b/.github/workflows/push-release-data.yml new file mode 100644 index 0000000000..85e6ff194b --- /dev/null +++ b/.github/workflows/push-release-data.yml @@ -0,0 +1 @@ +# WIP From c9489fb48ecfa978373c7cedca1dc9af94abd126 Mon Sep 17 00:00:00 2001 From: pierre Date: Thu, 29 Jun 2023 15:57:02 +0200 Subject: [PATCH 16/74] build: add workflow to push release data to strapi --- .github/workflows/push-release-data.yml | 155 +++++++++++++++++++++++- 1 file changed, 154 insertions(+), 1 deletion(-) diff --git a/.github/workflows/push-release-data.yml b/.github/workflows/push-release-data.yml index 85e6ff194b..86bf1cc1e4 100644 --- a/.github/workflows/push-release-data.yml +++ b/.github/workflows/push-release-data.yml @@ -1 +1,154 @@ -# WIP +name: Push release data + +env: + strapi_download_url: 'https://strapi.feat-nym-update-nym-web.websites.dev.nymte.ch/api/downloaders' + strapi_updater_url: 'https://strapi.feat-nym-update-nym-web.websites.dev.nymte.ch/api/updaters' + +on: + workflow_call: + inputs: &wf-inputs + release_tag: + required: true + description: Release tag + type: string + release_id: + required: true + description: Release ID + type: string + release_date: + required: true + description: Release date + type: string + download_base_url: + required: true + description: Download base URL + type: string + changelog_url: + required: true + description: Changelog URL + type: string + archive_url: + required: false + description: Binary archive URL + type: string + sig_url: + required: false + description: Archive signature URL + type: string + version: + required: true + description: Release version (semver) + type: string + filename: + required: true + description: Binary file name + type: string + file_hash: + required: true + description: Binary hash (sha256) + type: string + name: + required: true + description: Name + type: string + category: + required: true + description: Category + type: string + platform: + required: false + description: Platform + type: string + workflow_dispatch: + inputs: + <<: *wf-inputs + category: + required: true + description: Category + default: 'wallet' + type: choice + options: + - wallet + - connect + - binaries + platform: + required: false + description: Platform + default: 'Ubuntu' + type: choice + options: + - Ubuntu + - Windows + - MacOS + +jobs: + push-download-data: + name: Push download data to Strapi + runs-on: ${{ matrix.platform }} + + steps: + - id: get_sig + name: Get sig + if: ${{ inputs.sig_url != null }} + run: | + output=$(curl -LsSf ${{ inputs.sig_url }}) + echo "sig=$output" >> "$GITHUB_OUTPUT" + - name: Push download data + uses: fjogeleit/http-request-action@v1 + with: + url: ${{ env.strapi_download_url }} + method: 'POST' + # bearerToken: ${{ secrets.STRAPI_AUTH_TOKEN }} TODO + customHeaders: '{"Content-Type": "application/json"}' + data: | + { + "data": { + "releaseId": "${{ inputs.release_id }}", + "releaseDate": "${{ inputs.release_date }}", + "downloadBaseUrl": "${{ inputs.download_base_url }}", + "changelogUrl": "${{ inputs.changelog_url }}", + "version": "${{ inputs.version }}", + "filename": "${{ inputs.filename }}", + "name": "${{ inputs.name }}", + "category": "${{ inputs.category }}", + "platform": "${{ inputs.platform }}", + "sha256": "${{ inputs.file_hash }}", + "sig": "${{ steps.get_sig.outputs.sig }}" + } + } + + push-update-data: + name: Push update data to Strapi + runs-on: ${{ matrix.platform }} + # only push update data for tauri apps (desktop wallet and NC) + if: ${{ inputs.category == 'wallet' || inputs.category == 'connect' }} + + steps: + - id: get_sig + name: Get sig + if: ${{ inputs.sig_url != null }} + run: | + output=$(curl -LsSf ${{ inputs.sig_url }}) + echo "sig=$output" >> "$GITHUB_OUTPUT" + - name: Push update data + uses: fjogeleit/http-request-action@v1 + with: + url: ${{ env.strapi_updater_url }} + method: 'POST' + # bearerToken: ${{ secrets.STRAPI_AUTH_TOKEN }} TODO + customHeaders: '{"Content-Type": "application/json"}' + data: | + { + "data": { + "releaseId": "${{ inputs.release_id }}", + "releaseDate": "${{ inputs.release_date }}", + "downloadUrl": "${{ inputs.archive_url }}", + "changelog": "See ${{ inputs.changelog_url }} for the changelog", + "version": "${{ inputs.version }}", + "filename": "${{ inputs.filename }}", + "category": "${{ inputs.category }}", + "platform": "${{ inputs.platform }}", + "sha256": "${{ inputs.file_hash }}", + "sig": "${{ steps.get_sig.outputs.sig }}" + } + } From 4b13a5cf611bff2a943a79d56d58b089e0d58536 Mon Sep 17 00:00:00 2001 From: pierre Date: Thu, 29 Jun 2023 16:07:54 +0200 Subject: [PATCH 17/74] build: add workflow to push release data to strapi --- .github/workflows/push-release-data.yml | 154 ++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 .github/workflows/push-release-data.yml diff --git a/.github/workflows/push-release-data.yml b/.github/workflows/push-release-data.yml new file mode 100644 index 0000000000..0e9a931bc0 --- /dev/null +++ b/.github/workflows/push-release-data.yml @@ -0,0 +1,154 @@ +name: Push release data + +env: + strapi_download_url: 'https://strapi.feat-nym-update-nym-web.websites.dev.nymte.ch/api/downloaders' + strapi_updater_url: 'https://strapi.feat-nym-update-nym-web.websites.dev.nymte.ch/api/updaters' + +on: + workflow_call: + inputs: &wf-inputs + release_tag: + required: true + description: Release tag + type: string + release_id: + required: true + description: Release ID + type: string + release_date: + required: true + description: Release date + type: string + download_base_url: + required: true + description: Download base URL + type: string + changelog_url: + required: true + description: Changelog URL + type: string + archive_url: + required: false + description: Binary archive URL + type: string + sig_url: + required: false + description: Archive signature URL + type: string + version: + required: true + description: Release version (semver) + type: string + filename: + required: true + description: Binary file name + type: string + file_hash: + required: true + description: Binary hash (sha256) + type: string + name: + required: true + description: Name + type: string + category: + required: true + description: Category + type: string + platform: + required: false + description: Platform + type: string + workflow_dispatch: + inputs: + <<: *wf-inputs + category: + required: true + description: Category + default: 'wallet' + type: choice + options: + - wallet + - connect + - binaries + platform: + required: false + description: Platform + default: 'Ubuntu' + type: choice + options: + - Ubuntu + - Windows + - MacOS + +jobs: + push-download-data: + name: Push download data to Strapi + runs-on: custom-runner-linux + + steps: + - id: get_sig + name: Get sig + if: ${{ inputs.sig_url != null }} + run: | + output=$(curl -LsSf ${{ inputs.sig_url }}) + echo "sig=$output" >> "$GITHUB_OUTPUT" + - name: Push download data + uses: fjogeleit/http-request-action@v1 + with: + url: ${{ env.strapi_download_url }} + method: 'POST' + # bearerToken: ${{ secrets.STRAPI_AUTH_TOKEN }} TODO + customHeaders: '{"Content-Type": "application/json"}' + data: | + { + "data": { + "releaseId": "${{ inputs.release_id }}", + "releaseDate": "${{ inputs.release_date }}", + "downloadBaseUrl": "${{ inputs.download_base_url }}", + "changelogUrl": "${{ inputs.changelog_url }}", + "version": "${{ inputs.version }}", + "filename": "${{ inputs.filename }}", + "name": "${{ inputs.name }}", + "category": "${{ inputs.category }}", + "platform": "${{ inputs.platform }}", + "sha256": "${{ inputs.file_hash }}", + "sig": "${{ steps.get_sig.outputs.sig }}" + } + } + + push-update-data: + name: Push update data to Strapi + runs-on: ${{ matrix.platform }} + # only push update data for tauri apps (desktop wallet and NC) + if: ${{ inputs.category == 'wallet' || inputs.category == 'connect' }} + + steps: + - id: get_sig + name: Get sig + if: ${{ inputs.sig_url != null }} + run: | + output=$(curl -LsSf ${{ inputs.sig_url }}) + echo "sig=$output" >> "$GITHUB_OUTPUT" + - name: Push update data + uses: fjogeleit/http-request-action@v1 + with: + url: ${{ env.strapi_updater_url }} + method: 'POST' + # bearerToken: ${{ secrets.STRAPI_AUTH_TOKEN }} TODO + customHeaders: '{"Content-Type": "application/json"}' + data: | + { + "data": { + "releaseId": "${{ inputs.release_id }}", + "releaseDate": "${{ inputs.release_date }}", + "downloadUrl": "${{ inputs.archive_url }}", + "changelog": "See ${{ inputs.changelog_url }} for the changelog", + "version": "${{ inputs.version }}", + "filename": "${{ inputs.filename }}", + "category": "${{ inputs.category }}", + "platform": "${{ inputs.platform }}", + "sha256": "${{ inputs.file_hash }}", + "sig": "${{ steps.get_sig.outputs.sig }}" + } + } From 9d7a6b2aec11d500e659898080c9f402cb8b7e13 Mon Sep 17 00:00:00 2001 From: pierre Date: Thu, 29 Jun 2023 16:09:38 +0200 Subject: [PATCH 18/74] build: update workflow to push release data to strapi --- .github/workflows/push-release-data.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/push-release-data.yml b/.github/workflows/push-release-data.yml index 86bf1cc1e4..1a14ba3adb 100644 --- a/.github/workflows/push-release-data.yml +++ b/.github/workflows/push-release-data.yml @@ -84,7 +84,7 @@ on: jobs: push-download-data: name: Push download data to Strapi - runs-on: ${{ matrix.platform }} + runs-on: custom-runner-linux steps: - id: get_sig @@ -119,7 +119,7 @@ jobs: push-update-data: name: Push update data to Strapi - runs-on: ${{ matrix.platform }} + runs-on: custom-runner-linux # only push update data for tauri apps (desktop wallet and NC) if: ${{ inputs.category == 'wallet' || inputs.category == 'connect' }} From 9aaa74204bfdcaf7ae168ca41d99b056f922a011 Mon Sep 17 00:00:00 2001 From: pierre Date: Thu, 29 Jun 2023 16:26:03 +0200 Subject: [PATCH 19/74] build: update workflow to push release data to strapi --- .github/workflows/push-release-data.yml | 47 +++++++++++++++++++++---- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/.github/workflows/push-release-data.yml b/.github/workflows/push-release-data.yml index 1a14ba3adb..0469f08dbc 100644 --- a/.github/workflows/push-release-data.yml +++ b/.github/workflows/push-release-data.yml @@ -6,11 +6,7 @@ env: on: workflow_call: - inputs: &wf-inputs - release_tag: - required: true - description: Release tag - type: string + inputs: release_id: required: true description: Release ID @@ -61,7 +57,46 @@ on: type: string workflow_dispatch: inputs: - <<: *wf-inputs + version: + required: true + description: Release version (semver) + type: string + default: '1.0.0' + release_id: + required: true + description: Release ID + type: string + default: '1234' + release_date: + required: true + description: Release date + type: string + default: '2023-06-26T10:09:16Z' + download_base_url: + required: true + description: Download base URL + type: string + default: 'https://github.com/nymtech/nym/releases/download/nym-wallet-v1.0.0' + changelog_url: + required: true + description: Changelog URL + type: string + default: 'https://github.com/nymtech/nym/blob/nym-wallet-v1.0.0/nym-wallet/CHANGELOG.md' + filename: + required: true + description: Binary file name + type: string + default: 'nym-wallet_1.0.0_amd64.AppImage' + file_hash: + required: true + description: Binary hash (sha256) + type: string + default: 'xxx' + name: + required: true + description: Name + type: string + default: 'Wallet' category: required: true description: Category From 4025fed8821ec395f2f0a83a80e7f700644bc1ab Mon Sep 17 00:00:00 2001 From: pierre Date: Thu, 29 Jun 2023 16:51:58 +0200 Subject: [PATCH 20/74] build: update workflow to push release data to strapi --- .github/workflows/push-release-data.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/push-release-data.yml b/.github/workflows/push-release-data.yml index 0469f08dbc..96bda89178 100644 --- a/.github/workflows/push-release-data.yml +++ b/.github/workflows/push-release-data.yml @@ -57,6 +57,8 @@ on: type: string workflow_dispatch: inputs: + # ⚠ since inputs are limited to 10 max for workflow_dispatch + # `archive_url` and `sig_url` properties were omitted version: required: true description: Release version (semver) @@ -128,7 +130,8 @@ jobs: run: | output=$(curl -LsSf ${{ inputs.sig_url }}) echo "sig=$output" >> "$GITHUB_OUTPUT" - - name: Push download data + - id: strapi-request + name: Strapi request uses: fjogeleit/http-request-action@v1 with: url: ${{ env.strapi_download_url }} @@ -151,6 +154,9 @@ jobs: "sig": "${{ steps.get_sig.outputs.sig }}" } } + - name: Strapi Response + run: | + echo ${{ steps.strapi-request.outputs.response }} push-update-data: name: Push update data to Strapi @@ -165,7 +171,8 @@ jobs: run: | output=$(curl -LsSf ${{ inputs.sig_url }}) echo "sig=$output" >> "$GITHUB_OUTPUT" - - name: Push update data + - id: strapi-request + name: Strapi request uses: fjogeleit/http-request-action@v1 with: url: ${{ env.strapi_updater_url }} @@ -187,3 +194,6 @@ jobs: "sig": "${{ steps.get_sig.outputs.sig }}" } } + - name: Strapi Response + run: | + echo ${{ steps.strapi-request.outputs.response }} From ef36c29b911415de06bcc44eff5230661f660a75 Mon Sep 17 00:00:00 2001 From: Pierre Dommerc Date: Fri, 30 Jun 2023 12:13:04 +0200 Subject: [PATCH 21/74] feat(nc-desktop): add matrix and monero to providers list (ui) (#3623) --- nym-connect/desktop/src/pages/menu/Apps.tsx | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/nym-connect/desktop/src/pages/menu/Apps.tsx b/nym-connect/desktop/src/pages/menu/Apps.tsx index ebe31deb44..5de95cc9c3 100644 --- a/nym-connect/desktop/src/pages/menu/Apps.tsx +++ b/nym-connect/desktop/src/pages/menu/Apps.tsx @@ -3,34 +3,31 @@ import { Divider, Typography } from '@mui/material'; import { Box } from '@mui/system'; const appsSchema = { - messagingApps: ['Telegram', 'Keybase'], - wallets: ['Blockstream', 'Electrum'], + messagingApps: ['Matrix', 'Telegram', 'Keybase'], + wallets: ['Monero', 'Blockstream', 'Electrum'], }; export const CompatibleApps = () => ( - + Supported apps Messaging apps - - - + {appsSchema.messagingApps.map((app) => ( {app} ))} + Wallets - - {appsSchema.wallets.map((wallet) => ( From 7a1a7c003efe7eb9834a48565c6e4e298064ce5b Mon Sep 17 00:00:00 2001 From: Pierre Dommerc Date: Fri, 30 Jun 2023 12:13:04 +0200 Subject: [PATCH 22/74] feat(nc-desktop): add matrix and monero to providers list (ui) (#3623) --- nym-connect/desktop/src/pages/menu/Apps.tsx | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/nym-connect/desktop/src/pages/menu/Apps.tsx b/nym-connect/desktop/src/pages/menu/Apps.tsx index ebe31deb44..5de95cc9c3 100644 --- a/nym-connect/desktop/src/pages/menu/Apps.tsx +++ b/nym-connect/desktop/src/pages/menu/Apps.tsx @@ -3,34 +3,31 @@ import { Divider, Typography } from '@mui/material'; import { Box } from '@mui/system'; const appsSchema = { - messagingApps: ['Telegram', 'Keybase'], - wallets: ['Blockstream', 'Electrum'], + messagingApps: ['Matrix', 'Telegram', 'Keybase'], + wallets: ['Monero', 'Blockstream', 'Electrum'], }; export const CompatibleApps = () => ( - + Supported apps Messaging apps - - - + {appsSchema.messagingApps.map((app) => ( {app} ))} + Wallets - - {appsSchema.wallets.map((wallet) => ( From ed48a2ddd4a8c86bd865407d62fe62f6b3c99997 Mon Sep 17 00:00:00 2001 From: mx Date: Fri, 30 Jun 2023 12:50:48 +0200 Subject: [PATCH 23/74] fixed broken example file import --- documentation/docs/src/sdk/rust.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/src/sdk/rust.md b/documentation/docs/src/sdk/rust.md index 1408d85faa..ba1c079725 100644 --- a/documentation/docs/src/sdk/rust.md +++ b/documentation/docs/src/sdk/rust.md @@ -50,7 +50,7 @@ As seen in the example above, the `mixnet::MixnetClientBuilder::new()` function If you're integrating mixnet functionality into an existing app and want to integrate saving client configs and keys into your existing storage logic, you can manually perform the actions taken automatically above (`examples/manually_handle_keys_and_config.rs`) ```rust,noplayground -{{#include ../../../../sdk/rust/nym-sdk/examples/manually_handle_keys_and_config.rs}} +{{#include ../../../../sdk/rust/nym-sdk/examples/manually_handle_storage.rs}} ``` ### Anonymous replies with SURBs From b258cd8733b9365dddee0dfcbf9b5d33d52c0402 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 3 Jul 2023 09:28:14 +0000 Subject: [PATCH 24/74] fixed broken git url for last-changed mdbook plugin --- documentation/dev-portal/book.toml | 2 +- documentation/docs/book.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/dev-portal/book.toml b/documentation/dev-portal/book.toml index fe2a9d1c9e..38dc43286f 100644 --- a/documentation/dev-portal/book.toml +++ b/documentation/dev-portal/book.toml @@ -79,7 +79,7 @@ copy-fonts = true no-section-label = false additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "last-changed.css"] additional-js = ["theme/pagetoc.js"] -git-repository-url = "https://github.com/nymtech/dev-portal" +git-repository-url = "https://github.com/nymtech/nym/documentation/dev-portal" git-repository-icon = "fa-github" # edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}" site-url = "/developers/" diff --git a/documentation/docs/book.toml b/documentation/docs/book.toml index bfecb66a7f..1ff5cb8daf 100644 --- a/documentation/docs/book.toml +++ b/documentation/docs/book.toml @@ -49,7 +49,7 @@ assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install` [preprocessor.variables.variables] minimum_rust_version = "1.66" # vars for links: TODO think on how to streamline updating -platform_release_version = "v1.1.23" +platform_release_version = "v1.1.22" wallet_release_version = "v1.2.5" [preprocessor.last-changed] @@ -87,7 +87,7 @@ copy-fonts = true no-section-label = false additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "last-changed.css"] additional-js = ["theme/pagetoc.js"] -git-repository-url = "https://github.com/nymtech/docs" +git-repository-url = "https://github.com/nymtech/nym/documentation/docs" git-repository-icon = "fa-github" # edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}" # site-url = "/docs/" From 2ddf9646ec303f30b2920c1cdf059db279c9fa6f Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 3 Jul 2023 09:31:56 +0000 Subject: [PATCH 25/74] push fix attempt 2 to get actual commit message on CI deployment --- documentation/docs/book.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/book.toml b/documentation/docs/book.toml index 1ff5cb8daf..a88de3ee74 100644 --- a/documentation/docs/book.toml +++ b/documentation/docs/book.toml @@ -87,7 +87,7 @@ copy-fonts = true no-section-label = false additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "last-changed.css"] additional-js = ["theme/pagetoc.js"] -git-repository-url = "https://github.com/nymtech/nym/documentation/docs" +git-repository-url = "https://github.com/nymtech/nym/docs" git-repository-icon = "fa-github" # edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}" # site-url = "/docs/" From 45b74008f1817b8824c051ad47351e036e024f37 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 3 Jul 2023 09:36:23 +0000 Subject: [PATCH 26/74] fixed broken links to platform and wallet build instructions in readme --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ddd904302f..fec13cd406 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr * nym-gateway - acts sort of like a mailbox for mixnet messages, which removes the need for direct delivery to potentially offline or firewalled devices. * nym-network-monitor - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing"). * nym-explorer - a (projected) block explorer and (existing) mixnet viewer. -* nym-wallet - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework. +* nym-wallet - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework. [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=for-the-badge)](https://opensource.org/licenses/Apache-2.0) [![Build Status](https://img.shields.io/github/actions/workflow/status/nymtech/nym/build.yml?branch=develop&style=for-the-badge&logo=github-actions)](https://github.com/nymtech/nym/actions?query=branch%3Adevelop) @@ -21,7 +21,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr ### Building -Platform build instructions are available on [our docs site](https://nymtech.net/docs/binaries/build-nym.html). +Platform build instructions are available on [our docs site](https://nymtech.net/docs/binaries/pre-built-binaries.html). Wallet build instructions are also available on [our docs site](https://nymtech.net/docs/wallet/desktop-wallet.html). ### Developing @@ -32,9 +32,9 @@ For Typescript components, please see [ts-packages](./ts-packages). ### Developer chat -> We used to use Keybase for developer chats, but we have since migrated to Matrix and Discord. We no longer check the old **nymtech.friends** Keybase team. +> We used to use Keybase for developer chats, but we have since migrated to Matrix and Discord. We no longer check the old **nymtech.friends** Keybase team. -You can chat to us in two places: +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](https://discord.gg/nym) @@ -84,4 +84,3 @@ where `s'` is stake `s` scaled over total token circulating supply. ### Licensing and copyright information This program is available as open source under the terms of the Apache 2.0 license. However, some elements are being licensed under CC0-1.0 and MIT. For accurate information, please check individual files. - From 4ad02d5328d2a426f87c7415fb21f9d1733a22d5 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 3 Jul 2023 09:40:00 +0000 Subject: [PATCH 27/74] fix attempt #3 --- documentation/dev-portal/book.toml | 2 +- documentation/docs/book.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/dev-portal/book.toml b/documentation/dev-portal/book.toml index 38dc43286f..0a94135968 100644 --- a/documentation/dev-portal/book.toml +++ b/documentation/dev-portal/book.toml @@ -79,7 +79,7 @@ copy-fonts = true no-section-label = false additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "last-changed.css"] additional-js = ["theme/pagetoc.js"] -git-repository-url = "https://github.com/nymtech/nym/documentation/dev-portal" +git-repository-url = "https://github.com/nymtech/nym/" git-repository-icon = "fa-github" # edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}" site-url = "/developers/" diff --git a/documentation/docs/book.toml b/documentation/docs/book.toml index a88de3ee74..9c7a1bf8bb 100644 --- a/documentation/docs/book.toml +++ b/documentation/docs/book.toml @@ -87,7 +87,7 @@ copy-fonts = true no-section-label = false additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "last-changed.css"] additional-js = ["theme/pagetoc.js"] -git-repository-url = "https://github.com/nymtech/nym/docs" +git-repository-url = "https://github.com/nymtech/nym/" git-repository-icon = "fa-github" # edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}" # site-url = "/docs/" From 1aad69a5270a76995eb26a4faae0d7439d025f78 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 3 Jul 2023 09:43:04 +0000 Subject: [PATCH 28/74] tidyup extra '/' in fixed last-changed git commit link --- documentation/dev-portal/book.toml | 2 +- documentation/docs/book.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/dev-portal/book.toml b/documentation/dev-portal/book.toml index 0a94135968..2306f90225 100644 --- a/documentation/dev-portal/book.toml +++ b/documentation/dev-portal/book.toml @@ -79,7 +79,7 @@ copy-fonts = true no-section-label = false additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "last-changed.css"] additional-js = ["theme/pagetoc.js"] -git-repository-url = "https://github.com/nymtech/nym/" +git-repository-url = "https://github.com/nymtech/nym" git-repository-icon = "fa-github" # edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}" site-url = "/developers/" diff --git a/documentation/docs/book.toml b/documentation/docs/book.toml index 9c7a1bf8bb..b70997a556 100644 --- a/documentation/docs/book.toml +++ b/documentation/docs/book.toml @@ -87,7 +87,7 @@ copy-fonts = true no-section-label = false additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "last-changed.css"] additional-js = ["theme/pagetoc.js"] -git-repository-url = "https://github.com/nymtech/nym/" +git-repository-url = "https://github.com/nymtech/nym" git-repository-icon = "fa-github" # edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}" # site-url = "/docs/" From 6403d0055bc1d3d3956b6c42443bddf29cf58534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 3 Jul 2023 18:01:10 +0300 Subject: [PATCH 29/74] Fixed compilation errors on latest nightly (#3638) ref: https://github.com/rust-lang/rust/issues/113152 --- contracts/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock index fc4605b2e0..456b9e013c 100644 --- a/contracts/Cargo.lock +++ b/contracts/Cargo.lock @@ -1646,9 +1646,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.52" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" dependencies = [ "unicode-ident", ] From 9f1f765f7303421f903ebde2e1053d8c60f66244 Mon Sep 17 00:00:00 2001 From: serinko Date: Mon, 3 Jul 2023 17:13:50 +0200 Subject: [PATCH 30/74] created matrix<>nymconnect user manual --- documentation/dev-portal/src/SUMMARY.md | 5 ++ .../src/images/monero_tutorial/monero.png | Bin 0 -> 321359 bytes .../dev-portal/src/tutorials/matrix.md | 35 ++++++++++++++ .../dev-portal/src/tutorials/monero.md | 43 ++++++++++++++++++ .../src/tutorials/pic/element_nym_keybind.png | Bin 0 -> 12224 bytes 5 files changed, 83 insertions(+) create mode 100644 documentation/dev-portal/src/images/monero_tutorial/monero.png create mode 100644 documentation/dev-portal/src/tutorials/matrix.md create mode 100644 documentation/dev-portal/src/tutorials/monero.md create mode 100644 documentation/dev-portal/src/tutorials/pic/element_nym_keybind.png diff --git a/documentation/dev-portal/src/SUMMARY.md b/documentation/dev-portal/src/SUMMARY.md index a2e6cbeb6f..79c0bc59bd 100644 --- a/documentation/dev-portal/src/SUMMARY.md +++ b/documentation/dev-portal/src/SUMMARY.md @@ -14,6 +14,11 @@ - [SOCKS Proxy (CLI)](quickstart/socks-proxy.md) - [NymConnect Beta (GUI)](quickstart/nymconnect-gui.md) +# User Manuals + +- [NymConnect Monero](tutorials/monero.md) +- [NymConnect Matrix](tutorials/matrix.md) + # Integrations - [Integration Options](integrations/integration-options.md) diff --git a/documentation/dev-portal/src/images/monero_tutorial/monero.png b/documentation/dev-portal/src/images/monero_tutorial/monero.png new file mode 100644 index 0000000000000000000000000000000000000000..3c7fadd32a8fa1ad29a881e627d463716c91b485 GIT binary patch literal 321359 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 G0v>&HD?&0O)SO~0n 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

;r?ng4Xr7+mXxS`NI6P^xC4{U#Y1sn=fi8TQ1@L zw-mz*6$~Riv@{~JTGnR^Y?s$Gr2dlT1pUCWu2U$eXc&XN&4=PiYoIWvo8KH#wEEDDdy4KdJ6;unodE#~N7O)fIG@p+yP zq0jJlUp(?BXw9*r(lAW4NO`MLrj4_-QoR>#^f#`z&oG5~>c++u=^Jh6(@dKbE~Z~} z#GTgTf{KaXem@Es-TMB}$OydE7k_v!iILdo$%!AFLwM!lkI1&+0UEOyyUWcIuhmH` zRPM=A8cfvr%l)o&&(XaH)`!ltALT?;LhqI3OLFM1)g2f0E6>E3%O#Pn-z0nU?P;$L zkFOs3=--UWwgL`jKD?kwK<@C{jog@GBBl>&zsEJ@U{m|!8#|s}*0kFJsq=I zcELcOM~`@g)T~Y!T{37kpGrMoDtmsA`<*RR&yhB}o_>#N5(X!HI8OFghcoyr(4FoM z+181=uiP(+N*MD}j%}1HAGp`>qx2HZEVUSw^B@yAh=Vsw9Yj*9-c79C>uOjQMG6Q{ zFN|*dutj-RpaLbYF4!kbz~BZqJPy2#fe(K5C!;|@uSjSy(ZWH%gI%4^UiwQGlAU1g z|9Jsi*+SleIVnY%g)*Y+0O#e4`+b7MQMdWOw2=pDkM-Lu^+Z*3;e#DjbxSfTStX=m z%@;wef>*p6R`bwX1YM~qgEoDe-Z$7L&L9nlbchxjaMk|XZJn$?P7vWak)HMEY5tCm z#Ct*9gGHB>Q35sEx)F`3*JO0=D}J(%CA>6Fj49T)n9oQ)O7K=LEHDQb8tF ziC|HHFYK)s5(=IhnEqu798+U*z=)+UHoPmI{mdd|Y@DA;hgHKOgiw#NR6i;DQLqq+ zc1&6-xPA+%&Uw9tR3@%tJ%1Xp*`nGICIeR9#xpnkv(Aq|jpPgZ=Ks}wvtl=Z@N%~$ zs8dHn>Y3ebDH?5*u20UO@e#991s=-2__?TI9Ga}hvW0FLPYKoI7Z-k_*Yb7I&|5dK zadtsZAcX4DuE@aWQ7*qRzbi9JPRj!}b<>X$Klm^Vg`;pk$)GO0Y%~19kEh-x4%}0; zO_IUb_rr23H-o=}n!x_6M7`NcVrc1fDTb#nI+e3J@LYf9FL88g|IwIGUXh`zVUmRe zIli{kXk1BN?4Jr( zAWPi|p1%!#0C2=hFoYC1K(s&eVHC%d6d6D{Fwqpk zUb)pWv)&Z|$Dgo?j8wzBJZ(MutmRlHDGzLLPbWuth}!TdQKGA-xB;2+*3V1}6;MIP zJFO0>W(;OHX`*N@ikFZ*^6Jw5S(^A-W^x-wm%j5!WA96`+g<2omh2mG#(*F2#e{HY zPK%$Ilsr|JN`52|@HJ(*NT8|lG0x)|JaEvRTDb-<)=M(pz(IW^Ax+7q{B+Q_U^Wh&=NekFd&yIF%@^4Qg-bJ z%Vs>-iZLN5|GnqQrK-RY&S)?58LQmCN^Y9F@8L1roXfY?c%h(c-B0L6i@^$k9>`$h zliBC1{M^DT^LMBpXs*;psVnt(tas_{9aU8#ShKGkHrZ5qaknV(NMQAQOAX&Q!kiuF|S9Rg^1?w0nBwPvoaDIC&(vepcsg4Oqg(o5-=z zo3Q1&lReE8`jvOb2~WP3x}@#GXW?A(%5dtTlG*qsxXLD$+Vg2cVXr1u5w3ACbz{l5 zA7U-`1POq%MUmI6iTuNcyEJ}j93H>VgYi61PJO9&cJ3DEA0p_@mwkph(@8gX1Usa( zXLO;N#vCzEZjJ&94N=kI?@;Aiq||e^E17HeE*9SO;3>}+ReEyPzT1=1pDR9o^cX*-rJ;Jzq~PhCCU$;85pNPhr=} z7UpnvdWf=`+=#l`KK>erzrfo>JG_>M56Lf!9+mKzA{{xVPqQ(8ug->zT4UNl3epw6 zfTf#_gd^TERlMA8Bx4J7K5JR#>tt2)PbX#WNfPpRUs%&ixNhS!zR}Z9YOrqPW8c^dC^+X*S7iR1e@}X!O1(3j9HGESgR-$E zyPjFY;3dBE1@yDI|FJU2I%?l{hr#*jlI(Com^SqbugHg0 zI_%q0?{7<&gX?7Itgg@mB_*5}3#-g?FSk{Ye)VGBxh}dcy|MbM+zKWeqG3PzsTo<^+we-$M%^ z)hVI-#t@|p?Mf)W3`3Lz3hNw&yb%RS|HMp#EsxNHkAPuN535uvqjFiX$0d?sCh|x9 zb@^rx&F9Wnmm@`^JQS22(}9AGevsYKci==%pZN9TTHC&wTON8|Dr#1{_CvIk?!=Zl zksQ@7VOZFE>qY~8sw-m@(KR$4L-39veZv6p2jN6ck4i;x+a22cK!CucXgp8ttcZXK z;L|}Sjm&P@ZMO+T+cR}{-Lobeys3cF1X^XpP%;}Ahn0pIz2l_*A>&)8Ccy*m@}(3a z0YeGEy6+J9Q|;}c6d`U3$lxC*J@Y*aGe+#@CkG!}PMjb)bmW9BD=Ql(@HIB`gvJK< zH_(R1fs{E*2Zt!Wwqu1YUq+xU*dq>FSy_*GVi7jrJ3k3I=N?!w6GIV z&_P{vPJUFpM`Hk`0LMjNqKyHX0Y+KD_7>8;SK#}LM&^9=HNiktmSmxW;y8CE%QxX4 zlNaT1L(akpp)se4v!Y5d5EEC3)P#WSdpUAkGB6F#Y*aWogYTF3o7LnOEQc??Nz)JC zDMoJle&HBDX&-$E`;gj*>QFG8YM@srbtXC=#H{`zos5xz47~-neKYh!1nq)^f}ued zBL5HuYN`T{Zkb?4wklkpqioSF;23SkQBO>mAa$r92NN6xU`Rwt*srjzKo+)QrADKM z{rhZuk4-G@jEF|$EN%|6TUTG5>l zfR?VCzau0%7jzgfiLm1VG)*rrFX5^lvVhrsUmV264=^sNefKQjc^nCX7l)M!9Uu%( zny3#qV45eh&%4*ro&l{0fV|w0Zb*{vzuCJucmgJXgA?SDrw(oCRL+bZ7N9o7@_$5@ zpMM4*nbDd7>B2J^708+cimcJ6<73oGk4Jw^iDD@Q`egnYyx|XY+X&D#EZNHaW~&QLH=dvLTvaQ5R(q{{ zzb2{$sx<`%doGaa$|FsdX$13e%0D{|lwGpiV}dH+oMS^xtTunkzP0~LT>$J8@^JMT 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 ~lzgZu>(L3<_f>D?9_hw;fc?p1^ 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

(r?NX%#lDplwG6(gA|o#*54het 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 xuaB;__; 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


v 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 Interface -> Socks5 proxy -> Add values: IP address `localhost`, Port `1080` + + + +**CLI** + +* **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 + +Follow the instructions and the Monero mainnet will be connected through to the Nym mixnet. + +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) + diff --git a/documentation/dev-portal/src/tutorials/pic/element_nym_keybind.png b/documentation/dev-portal/src/tutorials/pic/element_nym_keybind.png new file mode 100644 index 0000000000000000000000000000000000000000..d0bd38349417af4eda6a7538f2be37394ebb1de4 GIT binary patch literal 12224 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 Date: Mon, 3 Jul 2023 16:53:39 +0100 Subject: [PATCH 31/74] Feature/node tester package (#3634) * create node tester package dir * start building node tester package * refactor code + build updates * fix up types * add more methods and fix up types * use node tester sdk inside wallet * fix frontend state * Use Node 18 instead of 16 * Fix up dependencies and yarn workspace * Fix lint error * Try to fix up linting error * Remove explorer linting and move it to the existing action * Add wasm-pack build to linting GH Action * change lerna to use workspaces and fix linting errors * Fix up node versions in GitHub Actions and add wasm-pack * fix build:lint target in sdk * exclude all worker.js from eslint for sdk --------- Co-authored-by: Mark Sinclair --- .github/workflows/audit.yml | 2 +- .github/workflows/build-ts-packages.yml | 8 +- .github/workflows/cd-dev.yml | 2 +- .github/workflows/cd-docs.yml | 2 +- .github/workflows/ci-dev.yml | 2 +- .github/workflows/ci-docs.yml | 2 +- .github/workflows/connect-desktop-ci.yml | 2 +- .github/workflows/network-explorer-lint.yml | 24 - .github/workflows/network-explorer.yml | 2 +- .github/workflows/nightly_build.yml | 2 +- .github/workflows/nightly_build_release.yml | 2 +- .github/workflows/nightly_build_release2.yml | 2 +- .../workflows/nym-connect-publish-macos.yml | 2 +- .../workflows/nym-connect-publish-ubuntu.yml | 2 +- .../nym-connect-publish-windows10.yml | 2 +- .../workflows/nym-wallet-publish-macos.yml | 2 +- .../workflows/nym-wallet-publish-ubuntu.yml | 2 +- .../nym-wallet-publish-windows10.yml | 2 +- .github/workflows/nym-wallet-storybook.yml | 12 +- .github/workflows/nym_wallet.yml | 2 +- .github/workflows/support-files/.nvmrc | 2 +- .github/workflows/typescript-lint.yml | 8 +- clients/validator/.nvmrc | 2 +- explorer/.nvmrc | 2 +- lerna.json | 10 +- nym-connect/desktop/.nvmrc | 2 +- nym-connect/mobile/.nvmrc | 2 +- nym-wallet/.nvmrc | 2 +- nym-wallet/package.json | 2 +- .../src/components/TestNode/Packets.tsx | 2 +- .../src/components/TestNode/PrintResults.tsx | 4 +- .../src/components/TestNode/Results.tsx | 3 +- .../node-settings/node-test/__mocks__.ts | 55 -- .../bonding/node-settings/node-test/index.tsx | 98 ++- .../bonding/node-settings/node-test/types.ts | 38 -- .../bonding/node-settings/node-test/worker.ts | 102 --- package.json | 10 +- .../build/yarn/wasm-placeholder/package.json | 5 + sdk/typescript/.eslintrc.js | 2 +- .../examples/node-tester/plain-html/.babelrc | 3 + .../examples/node-tester/plain-html/README.md | 14 + .../node-tester/plain-html/jest.config.js | 5 + .../node-tester/plain-html/package.json | 61 ++ .../node-tester/plain-html/src/index.html | 29 + .../node-tester/plain-html/src/index.ts | 116 ++++ .../node-tester/plain-html/tsconfig.json | 9 + .../node-tester/plain-html/tsconfig.prod.json | 10 + .../node-tester/plain-html/webpack.common.js | 30 + .../node-tester/plain-html/webpack.config.js | 67 ++ .../node-tester/plain-html/webpack.prod.js | 42 ++ .../examples/plain-html/tsconfig.prod.json | 16 +- sdk/typescript/packages/sdk/.gitignore | 1 + sdk/typescript/packages/sdk/package.json | 4 +- .../packages/sdk/rollup-cjs.config.mjs | 9 +- .../packages/sdk/rollup-esm.config.mjs | 9 +- .../sdk/rollup-node-tester-worker.config.mjs | 26 + sdk/typescript/packages/sdk/scripts/build.sh | 15 +- .../packages/sdk/src/mixnet/index.ts | 2 + .../sdk/src/mixnet/node-tester/constants.ts | 5 + .../sdk/src/mixnet/node-tester/index.ts | 50 ++ .../sdk/src/mixnet/node-tester/types.ts | 65 ++ .../sdk/src/mixnet/node-tester/worker.ts | 105 +++ .../src/mixnet/wasm/types-from-wasm-pack.ts | 336 ++++++++++ .../packages/sdk/src/mixnet/wasm/types.ts | 174 +---- .../packages/sdk/src/mixnet/wasm/worker.ts | 61 +- ts-packages/mock-nym-api/src/index.ts | 1 + .../src/App.tsx | 1 + yarn.lock | 627 +++++++++--------- 68 files changed, 1439 insertions(+), 883 deletions(-) delete mode 100644 .github/workflows/network-explorer-lint.yml delete mode 100644 nym-wallet/src/pages/bonding/node-settings/node-test/__mocks__.ts delete mode 100644 nym-wallet/src/pages/bonding/node-settings/node-test/types.ts delete mode 100644 nym-wallet/src/pages/bonding/node-settings/node-test/worker.ts create mode 100644 scripts/build/yarn/wasm-placeholder/package.json create mode 100644 sdk/typescript/examples/node-tester/plain-html/.babelrc create mode 100644 sdk/typescript/examples/node-tester/plain-html/README.md create mode 100644 sdk/typescript/examples/node-tester/plain-html/jest.config.js create mode 100644 sdk/typescript/examples/node-tester/plain-html/package.json create mode 100644 sdk/typescript/examples/node-tester/plain-html/src/index.html create mode 100644 sdk/typescript/examples/node-tester/plain-html/src/index.ts create mode 100644 sdk/typescript/examples/node-tester/plain-html/tsconfig.json create mode 100644 sdk/typescript/examples/node-tester/plain-html/tsconfig.prod.json create mode 100644 sdk/typescript/examples/node-tester/plain-html/webpack.common.js create mode 100644 sdk/typescript/examples/node-tester/plain-html/webpack.config.js create mode 100644 sdk/typescript/examples/node-tester/plain-html/webpack.prod.js create mode 100644 sdk/typescript/packages/sdk/rollup-node-tester-worker.config.mjs create mode 100644 sdk/typescript/packages/sdk/src/mixnet/node-tester/constants.ts create mode 100644 sdk/typescript/packages/sdk/src/mixnet/node-tester/index.ts create mode 100644 sdk/typescript/packages/sdk/src/mixnet/node-tester/types.ts create mode 100644 sdk/typescript/packages/sdk/src/mixnet/node-tester/worker.ts create mode 100644 sdk/typescript/packages/sdk/src/mixnet/wasm/types-from-wasm-pack.ts diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 9e42b31964..1a55fd34fa 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -38,7 +38,7 @@ jobs: - name: install npm uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - name: Matrix - Node Install run: npm install working-directory: .github/workflows/support-files diff --git a/.github/workflows/build-ts-packages.yml b/.github/workflows/build-ts-packages.yml index ba744b1a65..1fb210bd8e 100644 --- a/.github/workflows/build-ts-packages.yml +++ b/.github/workflows/build-ts-packages.yml @@ -16,9 +16,15 @@ jobs: - uses: rlespinasse/github-slug-action@v3.x - uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - name: Setup yarn run: npm install -g yarn + - name: Install Rust stable + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + - name: Install wasm-pack + run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - name: Build run: yarn && yarn build && yarn build:ci - name: Deploy branch to CI www (storybook) diff --git a/.github/workflows/cd-dev.yml b/.github/workflows/cd-dev.yml index ab5dd75f21..0ca463345f 100644 --- a/.github/workflows/cd-dev.yml +++ b/.github/workflows/cd-dev.yml @@ -16,7 +16,7 @@ jobs: - uses: rlespinasse/github-slug-action@v3.x - uses: actions/setup-node@v3 with: - node-version: "16" + node-version: 18 - name: Install Rust stable uses: actions-rs/toolchain@v1 with: diff --git a/.github/workflows/cd-docs.yml b/.github/workflows/cd-docs.yml index 6e7882785a..782a2c196d 100644 --- a/.github/workflows/cd-docs.yml +++ b/.github/workflows/cd-docs.yml @@ -16,7 +16,7 @@ jobs: - uses: rlespinasse/github-slug-action@v3.x - uses: actions/setup-node@v3 with: - node-version: "16" + node-version: 18 - name: Install Rust stable uses: actions-rs/toolchain@v1 with: diff --git a/.github/workflows/ci-dev.yml b/.github/workflows/ci-dev.yml index 39432c90e3..82068fce76 100644 --- a/.github/workflows/ci-dev.yml +++ b/.github/workflows/ci-dev.yml @@ -16,7 +16,7 @@ jobs: - uses: rlespinasse/github-slug-action@v3.x - uses: actions/setup-node@v3 with: - node-version: "16" + node-version: 18 - name: Install Rust stable uses: actions-rs/toolchain@v1 with: diff --git a/.github/workflows/ci-docs.yml b/.github/workflows/ci-docs.yml index e18370669d..2523013204 100644 --- a/.github/workflows/ci-docs.yml +++ b/.github/workflows/ci-docs.yml @@ -16,7 +16,7 @@ jobs: - uses: rlespinasse/github-slug-action@v3.x - uses: actions/setup-node@v3 with: - node-version: "16" + node-version: 18 - name: Install Rust stable uses: actions-rs/toolchain@v1 with: diff --git a/.github/workflows/connect-desktop-ci.yml b/.github/workflows/connect-desktop-ci.yml index 5846212222..569203cfff 100644 --- a/.github/workflows/connect-desktop-ci.yml +++ b/.github/workflows/connect-desktop-ci.yml @@ -20,7 +20,7 @@ jobs: - uses: rlespinasse/github-slug-action@v3.x - uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - name: Install Yarn run: npm install -g yarn - run: yarn diff --git a/.github/workflows/network-explorer-lint.yml b/.github/workflows/network-explorer-lint.yml deleted file mode 100644 index 35c07e654d..0000000000 --- a/.github/workflows/network-explorer-lint.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Linting for Network Explorer (eslint/prettier) - -on: - pull_request: - paths: - - 'explorer/**' - -defaults: - run: - working-directory: explorer - -jobs: - build: - runs-on: custom-runner-linux - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v3 - with: - node-version: 16 - - name: Setup yarn - run: npm install -g yarn - - name: Run ESLint - # GitHub should automatically annotate the PR - run: yarn && yarn lint \ No newline at end of file diff --git a/.github/workflows/network-explorer.yml b/.github/workflows/network-explorer.yml index 9f50548105..b4431b0ed4 100644 --- a/.github/workflows/network-explorer.yml +++ b/.github/workflows/network-explorer.yml @@ -21,7 +21,7 @@ jobs: - uses: rlespinasse/github-slug-action@v3.x - uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - name: Setup yarn run: npm install -g yarn continue-on-error: true diff --git a/.github/workflows/nightly_build.yml b/.github/workflows/nightly_build.yml index 64b95f6368..1ee391d6a7 100644 --- a/.github/workflows/nightly_build.yml +++ b/.github/workflows/nightly_build.yml @@ -152,7 +152,7 @@ jobs: uses: actions/setup-node@v3 if: env.WORKFLOW_CONCLUSION == 'failure' with: - node-version: 16 + node-version: 18 - name: Matrix - Node Install if: env.WORKFLOW_CONCLUSION == 'failure' run: npm install diff --git a/.github/workflows/nightly_build_release.yml b/.github/workflows/nightly_build_release.yml index 71b7df2bd7..fa1c465c97 100644 --- a/.github/workflows/nightly_build_release.yml +++ b/.github/workflows/nightly_build_release.yml @@ -167,7 +167,7 @@ jobs: uses: actions/setup-node@v3 if: env.WORKFLOW_CONCLUSION == 'failure' with: - node-version: 16 + node-version: 18 - name: Matrix - Node Install if: env.WORKFLOW_CONCLUSION == 'failure' run: npm install diff --git a/.github/workflows/nightly_build_release2.yml b/.github/workflows/nightly_build_release2.yml index ee85a1c978..3c3f962582 100644 --- a/.github/workflows/nightly_build_release2.yml +++ b/.github/workflows/nightly_build_release2.yml @@ -167,7 +167,7 @@ jobs: uses: actions/setup-node@v3 if: env.WORKFLOW_CONCLUSION == 'failure' with: - node-version: 16 + node-version: 18 - name: Matrix - Node Install if: env.WORKFLOW_CONCLUSION == 'failure' run: npm install diff --git a/.github/workflows/nym-connect-publish-macos.yml b/.github/workflows/nym-connect-publish-macos.yml index 0c9b33e416..379443d4dd 100644 --- a/.github/workflows/nym-connect-publish-macos.yml +++ b/.github/workflows/nym-connect-publish-macos.yml @@ -23,7 +23,7 @@ jobs: - name: Node v16 uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - name: Install Rust stable uses: actions-rs/toolchain@v1 with: diff --git a/.github/workflows/nym-connect-publish-ubuntu.yml b/.github/workflows/nym-connect-publish-ubuntu.yml index 473371c9e0..25d288581d 100644 --- a/.github/workflows/nym-connect-publish-ubuntu.yml +++ b/.github/workflows/nym-connect-publish-ubuntu.yml @@ -29,7 +29,7 @@ jobs: - name: Node v16 uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - name: Install Rust stable uses: actions-rs/toolchain@v1 diff --git a/.github/workflows/nym-connect-publish-windows10.yml b/.github/workflows/nym-connect-publish-windows10.yml index 7bd0ac1bc6..4a869caf3e 100644 --- a/.github/workflows/nym-connect-publish-windows10.yml +++ b/.github/workflows/nym-connect-publish-windows10.yml @@ -42,7 +42,7 @@ jobs: - name: Node v16 uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - name: Install Rust stable uses: actions-rs/toolchain@v1 diff --git a/.github/workflows/nym-wallet-publish-macos.yml b/.github/workflows/nym-wallet-publish-macos.yml index d3ef82759e..81c27a8338 100644 --- a/.github/workflows/nym-wallet-publish-macos.yml +++ b/.github/workflows/nym-wallet-publish-macos.yml @@ -23,7 +23,7 @@ jobs: - name: Node v16 uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - name: Install Rust stable uses: actions-rs/toolchain@v1 with: diff --git a/.github/workflows/nym-wallet-publish-ubuntu.yml b/.github/workflows/nym-wallet-publish-ubuntu.yml index 2b5a55c37a..1f2bb0330d 100644 --- a/.github/workflows/nym-wallet-publish-ubuntu.yml +++ b/.github/workflows/nym-wallet-publish-ubuntu.yml @@ -28,7 +28,7 @@ jobs: - name: Node v16 uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - name: Install Rust stable uses: actions-rs/toolchain@v1 diff --git a/.github/workflows/nym-wallet-publish-windows10.yml b/.github/workflows/nym-wallet-publish-windows10.yml index 53411b7571..044816953b 100644 --- a/.github/workflows/nym-wallet-publish-windows10.yml +++ b/.github/workflows/nym-wallet-publish-windows10.yml @@ -42,7 +42,7 @@ jobs: - name: Node v16 uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - name: Install Rust stable uses: actions-rs/toolchain@v1 diff --git a/.github/workflows/nym-wallet-storybook.yml b/.github/workflows/nym-wallet-storybook.yml index e98fe5e338..88f1230895 100644 --- a/.github/workflows/nym-wallet-storybook.yml +++ b/.github/workflows/nym-wallet-storybook.yml @@ -16,19 +16,9 @@ jobs: - uses: rlespinasse/github-slug-action@v3.x - uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - name: Setup yarn run: npm install -g yarn - - name: Install Rust stable - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - - name: Install wasm-pack - run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - working-directory: clients/webassembly - - name: Build WASM - run: wasm-pack build - working-directory: clients/webassembly - name: Build dependencies run: yarn && yarn build - name: Build storybook diff --git a/.github/workflows/nym_wallet.yml b/.github/workflows/nym_wallet.yml index 4b921ffb7a..d110314899 100644 --- a/.github/workflows/nym_wallet.yml +++ b/.github/workflows/nym_wallet.yml @@ -37,7 +37,7 @@ jobs: - name: Node v16 uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - name: Install yarn for building application run: yarn install diff --git a/.github/workflows/support-files/.nvmrc b/.github/workflows/support-files/.nvmrc index b6a7d89c68..3c032078a4 100644 --- a/.github/workflows/support-files/.nvmrc +++ b/.github/workflows/support-files/.nvmrc @@ -1 +1 @@ -16 +18 diff --git a/.github/workflows/typescript-lint.yml b/.github/workflows/typescript-lint.yml index 347d9ea0f0..b473107386 100644 --- a/.github/workflows/typescript-lint.yml +++ b/.github/workflows/typescript-lint.yml @@ -11,6 +11,7 @@ on: - 'nym-connect/mobile/package.json' - 'nym-wallet/src/**' - 'nym-wallet/package.json' + - 'explorer/**' pull_request: paths: - 'ts-packages/**' @@ -21,6 +22,7 @@ on: - 'nym-connect/mobile/package.json' - 'nym-wallet/src/**' - 'nym-wallet/package.json' + - 'explorer/**' jobs: build: @@ -33,7 +35,7 @@ jobs: - uses: rlespinasse/github-slug-action@v3.x - uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - name: Setup yarn run: npm install -g yarn - name: Install Rust stable @@ -42,10 +44,6 @@ jobs: toolchain: stable - name: Install wasm-pack run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - working-directory: clients/webassembly - - name: Build WASM - run: wasm-pack build - working-directory: clients/webassembly - name: Install run: yarn - name: Build packages diff --git a/clients/validator/.nvmrc b/clients/validator/.nvmrc index 19c7bdba7b..25bf17fc5a 100644 --- a/clients/validator/.nvmrc +++ b/clients/validator/.nvmrc @@ -1 +1 @@ -16 \ No newline at end of file +18 \ No newline at end of file diff --git a/explorer/.nvmrc b/explorer/.nvmrc index b6a7d89c68..3c032078a4 100644 --- a/explorer/.nvmrc +++ b/explorer/.nvmrc @@ -1 +1 @@ -16 +18 diff --git a/lerna.json b/lerna.json index 5d17094fd5..851bdf0b54 100644 --- a/lerna.json +++ b/lerna.json @@ -1,10 +1,4 @@ { - "packages": [ - "ts-packages/*", - "nym-wallet", - "nym-connect/**", - "sdk/typescript/examples/docs", - "sdk/typescript/packages/**" - ], - "version": "0.0.0" + "version": "0.0.0", + "useWorkspaces": true } diff --git a/nym-connect/desktop/.nvmrc b/nym-connect/desktop/.nvmrc index da2d3988d7..25bf17fc5a 100644 --- a/nym-connect/desktop/.nvmrc +++ b/nym-connect/desktop/.nvmrc @@ -1 +1 @@ -14 \ No newline at end of file +18 \ No newline at end of file diff --git a/nym-connect/mobile/.nvmrc b/nym-connect/mobile/.nvmrc index da2d3988d7..25bf17fc5a 100644 --- a/nym-connect/mobile/.nvmrc +++ b/nym-connect/mobile/.nvmrc @@ -1 +1 @@ -14 \ No newline at end of file +18 \ No newline at end of file diff --git a/nym-wallet/.nvmrc b/nym-wallet/.nvmrc index 19c7bdba7b..25bf17fc5a 100644 --- a/nym-wallet/.nvmrc +++ b/nym-wallet/.nvmrc @@ -1 +1 @@ -16 \ No newline at end of file +18 \ No newline at end of file diff --git a/nym-wallet/package.json b/nym-wallet/package.json index 4308313fe7..d6c7cdf442 100644 --- a/nym-wallet/package.json +++ b/nym-wallet/package.json @@ -31,6 +31,7 @@ "@nymproject/mui-theme": "^1.0.0", "@nymproject/react": "^1.0.0", "@nymproject/types": "^1.0.0", + "@nymproject/sdk": "1", "@storybook/react": "^6.5.15", "@tauri-apps/api": "^1.2.0", "@tauri-apps/tauri-forage": "^1.0.0-beta.2", @@ -41,7 +42,6 @@ "lodash": "^4.17.21", "notistack": "^2.0.3", "npm-run-all": "^4.1.5", - "nym-client-wasm": "1.1.1", "qrcode.react": "^1.0.1", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/nym-wallet/src/components/TestNode/Packets.tsx b/nym-wallet/src/components/TestNode/Packets.tsx index 46ee86bae1..dfbc4d7144 100644 --- a/nym-wallet/src/components/TestNode/Packets.tsx +++ b/nym-wallet/src/components/TestNode/Packets.tsx @@ -1,6 +1,6 @@ import React from 'react'; +import { TestStatus } from '@nymproject/sdk'; import { Divider, Typography } from '@mui/material'; -import { TestStatus } from 'src/pages/bonding/node-settings/node-test/types'; import { ResultsCard, ResultsCardDetail } from './ResultsCard'; export const Packets = ({ diff --git a/nym-wallet/src/components/TestNode/PrintResults.tsx b/nym-wallet/src/components/TestNode/PrintResults.tsx index 1395d2b575..c225d73708 100644 --- a/nym-wallet/src/components/TestNode/PrintResults.tsx +++ b/nym-wallet/src/components/TestNode/PrintResults.tsx @@ -1,8 +1,8 @@ import React, { useEffect } from 'react'; import { Card, CardContent, CardHeader, Dialog, Divider } from '@mui/material'; import { NymLogo } from '@nymproject/react/logo/NymLogo'; -import { ResultsCardDetail } from './ResultsCard'; import { sleep } from 'src/utils/sleep'; +import { ResultsCardDetail } from './ResultsCard'; export const PrintResults = ({ packetsSent, @@ -30,7 +30,7 @@ export const PrintResults = ({ asyncPrint(); window.addEventListener('afterprint', OnPrintRequestComplete); - () => window.removeEventListener('afterprint', OnPrintRequestComplete); + return () => window.removeEventListener('afterprint', OnPrintRequestComplete); }, []); return ( diff --git a/nym-wallet/src/components/TestNode/Results.tsx b/nym-wallet/src/components/TestNode/Results.tsx index 0ed14a814c..58856801b3 100644 --- a/nym-wallet/src/components/TestNode/Results.tsx +++ b/nym-wallet/src/components/TestNode/Results.tsx @@ -1,7 +1,6 @@ import React from 'react'; +import { TestStatus } from '@nymproject/sdk'; import { Grid } from '@mui/material'; - -import { TestStatus } from 'src/pages/bonding/node-settings/node-test/types'; import { Packets } from './Packets'; import { NodeScore } from './NodeScore'; import { Overview } from './Overview'; diff --git a/nym-wallet/src/pages/bonding/node-settings/node-test/__mocks__.ts b/nym-wallet/src/pages/bonding/node-settings/node-test/__mocks__.ts deleted file mode 100644 index c7a846d87a..0000000000 --- a/nym-wallet/src/pages/bonding/node-settings/node-test/__mocks__.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { WasmGateway, WasmMixNode, WasmNymTopology } from 'nym-client-wasm'; - -export const createDummyTopology = () => { - const l1Mixnode = new WasmMixNode( - 1, - 'n1fzv4jc7fanl9s0qj02ge2ezk3kts545kjtek47', - '178.79.143.65', - 1789, - '4Yr4qmEHd9sgsuQ83191FR2hD88RfsbMmB4tzhhZWriz', - '8ndjk5oZ6HxUZNScLJJ7hk39XtUqGexdKgW7hSX6kpWG', - 1, - '1.10.0', - ); - - const l2Mixnode = new WasmMixNode( - 2, - 'n1z93z44vf8ssvdhujjvxcj4rd5e3lz0l60wdk70', - '109.74.197.180', - 1789, - '7sVjiMrPYZrDWRujku9QLxgE8noT7NTgBAqizCsu7AoK', - 'GepXwRnKZDd8x2nBWAajGGBVvF3mrpVMQBkgfrGuqRCN', - 2, - '1.10.0', - ); - - const l3Mixnode = new WasmMixNode( - 3, - 'n1ptg680vnmef2cd8l0s9uyc4f0hgf3x8sed6w77', - '176.58.101.80', - 1789, - 'FoM5Mx9Pxk1g3zEqkS3APgtBeTtTo3M8k7Yu4bV6kK1R', - 'DeYjrDC2AcQRVFshiKnbUo6bRvPyZ33QGYR2DLeFJ9qD', - 3, - '1.10.0', - ); - - const gateway = new WasmGateway( - 'n16evnn8glr0sham3matj8rg2s24m6x56ayk87ts', - '85.159.212.96', - 1789, - 9000, - '336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9', - 'BtYjoWihiuFihGKQypmpSspbhmWDPxzqeTVSd8ciCpWL', - '1.10.1', - ); - - const mixnodes = new Map(); - mixnodes.set(1, [l1Mixnode]); - mixnodes.set(2, [l2Mixnode]); - mixnodes.set(3, [l3Mixnode]); - - const gateways = [gateway]; - - return new WasmNymTopology(mixnodes, gateways); -}; diff --git a/nym-wallet/src/pages/bonding/node-settings/node-test/index.tsx b/nym-wallet/src/pages/bonding/node-settings/node-test/index.tsx index e141d5f69c..7670fe1dcd 100644 --- a/nym-wallet/src/pages/bonding/node-settings/node-test/index.tsx +++ b/nym-wallet/src/pages/bonding/node-settings/node-test/index.tsx @@ -1,19 +1,20 @@ -import React, { useContext, useEffect, useRef, useState } from 'react'; +import React, { useCallback, useContext, useEffect, useRef, useState } from 'react'; import { Box, Button } from '@mui/material'; +import { Download } from '@mui/icons-material'; +import { NodeTestResultResponse, NodeTester, TestStatus, createNodeTesterClient } from '@nymproject/sdk'; +import { format } from 'date-fns'; import { AppContext, useBondingContext } from 'src/context'; import { LoadingModal } from 'src/components/Modals/LoadingModal'; import { Results } from 'src/components/TestNode/Results'; import { ErrorModal } from 'src/components/Modals/ErrorModal'; import { PrintResults } from 'src/components/TestNode/PrintResults'; -import { Download } from '@mui/icons-material'; -import { format } from 'date-fns'; -import { NodeTestEvent, NodeTestResult, TestStatus } from './types'; +import { MAINNET_VALIDATOR_URL, QA_VALIDATOR_URL } from 'src/constants'; export const NodeTestPage = () => { - const [nodeTestWorker, setNodeTestWorker] = useState(); + const [nodeTestClient, setNodeTestClient] = useState(); const [error, setError] = useState(); const [isLoading, setIsLoading] = useState(false); - const [results, setResults] = useState(); + const [results, setResults] = useState(); const [printResults, setPrintResults] = useState(false); const [testDate, setTestDate] = useState(); @@ -23,15 +24,6 @@ export const NodeTestPage = () => { const { network } = useContext(AppContext); const { bondedNode } = useBondingContext(); - const loadWorker = () => { - try { - const worker: Worker = new Worker(new URL('./worker.ts', import.meta.url)); - setNodeTestWorker(worker); - } catch (e) { - setError('Error loading worker'); - } - }; - const handleTestTimeout = () => { clearTimeout(timerRef.current); timerRef.current = setTimeout(() => { @@ -43,56 +35,52 @@ export const NodeTestPage = () => { }, 15000); }; - const handleWorkerMessages = (ev: MessageEvent) => { - const eventKind = ev.data.kind; - - if (eventKind === 'Error') { - setError(ev.data.args.message); - testStateRef.current = 'Stopped'; - } - if (eventKind === 'DisplayTesterResults') { - setResults(ev.data.args.result); - testStateRef.current = 'Complete'; - } - setIsLoading(false); - }; - const handleTestNode = async () => { - setError(undefined); - setResults(undefined); - setIsLoading(true); - setTestDate(format(new Date(), 'dd/MM/yyyy HH:mm')); - - if (nodeTestWorker) { + if (nodeTestClient && bondedNode) { + setResults(undefined); + setTestDate(format(new Date(), 'dd/MM/yyyy HH:mm')); + setIsLoading(true); + setError(undefined); testStateRef.current = 'Running'; - nodeTestWorker.postMessage({ - kind: 'TestPacket', - args: { - mixnodeIdentity: bondedNode?.identityKey, - network, - }, - } as NodeTestEvent); handleTestTimeout(); + try { + const result = await nodeTestClient.tester.startTest(bondedNode.identityKey); + setResults(result); + testStateRef.current = 'Complete'; + } catch (e) { + setError('Node test failed, please try again'); + testStateRef.current = 'Stopped'; + console.log(e); + } finally { + setIsLoading(false); + } } }; - useEffect(() => { - loadWorker(); - - return () => { - if (nodeTestWorker) { - nodeTestWorker.terminate(); - } - }; + const loadNodeTestClient = useCallback(async () => { + try { + const nodeTesterId = new Date().toISOString(); // make a new tester id for each session + const validator = network === 'MAINNET' ? MAINNET_VALIDATOR_URL : QA_VALIDATOR_URL; + const client = await createNodeTesterClient(); + await client.tester.init(validator, nodeTesterId); + setNodeTestClient(client); + } catch (e) { + console.log(e); + setError('Failed to load node tester client, please try again'); + } }, []); useEffect(() => { - if (nodeTestWorker) { - nodeTestWorker.addEventListener('message', (e) => handleWorkerMessages(e)); - } + loadNodeTestClient(); - return () => nodeTestWorker?.removeEventListener('message', handleWorkerMessages); - }, [nodeTestWorker]); + return () => { + clearTimeout(timerRef.current); + if (nodeTestClient) { + nodeTestClient.tester.disconnectFromGateway(); + nodeTestClient.terminate(); + } + }; + }, [loadNodeTestClient]); return ( diff --git a/nym-wallet/src/pages/bonding/node-settings/node-test/types.ts b/nym-wallet/src/pages/bonding/node-settings/node-test/types.ts deleted file mode 100644 index a15abf8620..0000000000 --- a/nym-wallet/src/pages/bonding/node-settings/node-test/types.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Network } from 'src/types'; - -export type NodeTestResult = { - score: number; - sentPackets: number; - receivedPackets: number; - receivedAcks: number; - duplicatePackets: number; - duplicateAcks: number; -}; - -type Error = { - kind: 'Error'; - args: { message: string }; -}; - -type WorkerLoaded = { - kind: 'WorkerLoaded'; -}; - -type DisplayTesterResults = { - kind: 'DisplayTesterResults'; - args: { - result: NodeTestResult; - }; -}; - -type TestPacket = { - kind: 'TestPacket'; - args: { - mixnodeIdentity: string; - network: Network; - }; -}; - -export type TestStatus = 'Stopped' | 'Running' | 'Complete'; - -export type NodeTestEvent = Error | DisplayTesterResults | TestPacket | WorkerLoaded; diff --git a/nym-wallet/src/pages/bonding/node-settings/node-test/worker.ts b/nym-wallet/src/pages/bonding/node-settings/node-test/worker.ts deleted file mode 100644 index 61c8b18bb9..0000000000 --- a/nym-wallet/src/pages/bonding/node-settings/node-test/worker.ts +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2020-2023 Nym Technologies SA -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* eslint-disable no-restricted-globals */ -import { NymNodeTester, set_panic_hook, current_network_topology, NodeTestResult } from 'nym-client-wasm'; -import { Network } from 'src/types'; -import { NodeTestEvent } from './types'; -import { MAINNET_VALIDATOR_URL, QA_VALIDATOR_URL } from 'src/constants'; - -console.log('Initializing worker'); - -const postMessage = (data: NodeTestEvent) => self.postMessage(data); - -postMessage({ - kind: 'WorkerLoaded', -}); - -const printAndDisplayTestResult = (result: NodeTestResult) => { - result.log_details(); - - postMessage({ - kind: 'DisplayTesterResults', - args: { - result: { - score: result.score(), - sentPackets: result.sent_packets, - receivedPackets: result.received_packets, - receivedAcks: result.received_acks, - duplicatePackets: result.duplicate_packets, - duplicateAcks: result.duplicate_acks, - }, - }, - }); -}; - -const buildTester = async (network: Network) => { - const validator = network === 'QA' ? QA_VALIDATOR_URL : MAINNET_VALIDATOR_URL; - const topology = await current_network_topology(validator); - const nodeTester = await new NymNodeTester(topology, network); - - return nodeTester; -}; - -async function testNode() { - self.onmessage = async (event: MessageEvent) => { - const eventKind = event.data.kind; - - switch (eventKind) { - case 'TestPacket': { - const { mixnodeIdentity, network } = event.data.args; - const nodeTester = await buildTester(network); - - try { - console.log(`Testing mixnode identity: ${mixnodeIdentity}, on network: ${network}.`); - const result = await nodeTester.test_node(mixnodeIdentity); - - printAndDisplayTestResult(result); - - await nodeTester.disconnect_from_gateway(); - console.log('Disconnected from gateway'); - } catch (e) { - const errorMessage = e instanceof Error ? e.message : 'Node test error'; - console.log(errorMessage); - - nodeTester.disconnect_from_gateway(); - - postMessage({ - kind: 'Error', - args: { message: errorMessage }, - }); - } - break; - } - default: - return undefined; - } - - return undefined; - }; -} - -async function main() { - // sets up better stack traces in case of in-rust panics - set_panic_hook(); - - // run test on simplified and dedicated tester: - await testNode(); -} - -// Let's get started! -main(); diff --git a/package.json b/package.json index 95b111b2f1..58d32165d3 100644 --- a/package.json +++ b/package.json @@ -10,14 +10,14 @@ "nym-connect/**", "explorer", "types", - "clients/validator", - "clients/webassembly/**" + "clients/validator" ], "scripts": { "clean": "lerna run clean", "build": "run-s build:types build:packages", "build:types": "lerna run --scope @nymproject/types build --stream", - "build:packages": "run-s build:packages:theme build:packages:react", + "build:packages": "run-s build:packages:theme build:packages:react build:packages:sdk", + "build:packages:sdk": "lerna run --scope @nymproject/sdk build:lint", "build:packages:theme": "lerna run --scope @nymproject/mui-theme build", "build:packages:react": "lerna run --scope @nymproject/react build", "build:react-example": "lerna run --scope @nymproject/react-webpack-with-theme-example build --stream", @@ -28,7 +28,9 @@ "lint:fix": "lerna run lint:fix --stream", "tsc": "lerna run tsc --stream", "types:lint:fix": "lerna run lint:fix --scope @nymproject/types --scope @nymproject/nym-wallet-app", - "audit:fix": "npm_config_yes=true npx yarn-audit-fix -- --dry-run" + "audit:fix": "npm_config_yes=true npx yarn-audit-fix -- --dry-run", + "preinstall": "yarn install:copy-placeholders", + "install:copy-placeholders": "cp scripts/build/yarn/wasm-placeholder/package.json sdk/typescript/packages/nym-client-wasm" }, "devDependencies": { "lerna": "^6.6.2", diff --git a/scripts/build/yarn/wasm-placeholder/package.json b/scripts/build/yarn/wasm-placeholder/package.json new file mode 100644 index 0000000000..50f57bc30d --- /dev/null +++ b/scripts/build/yarn/wasm-placeholder/package.json @@ -0,0 +1,5 @@ +{ + "name": "@nymproject/nym-client-wasm", + "version": "1.0.0", + "sideEffects": false +} diff --git a/sdk/typescript/.eslintrc.js b/sdk/typescript/.eslintrc.js index 040935b3bd..52bd4fe9a9 100644 --- a/sdk/typescript/.eslintrc.js +++ b/sdk/typescript/.eslintrc.js @@ -27,7 +27,7 @@ module.exports = { 'plugin:jest/recommended', 'plugin:jest/style', ], - ignorePatterns: ['dist/**/*', 'dist', 'node_modules', '**/wasm/worker.js'], + ignorePatterns: ['dist/**/*', 'dist', 'node_modules', '**/worker.js'], rules: { 'jest/prefer-strict-equal': 'error', 'jest/prefer-to-have-length': 'warn', diff --git a/sdk/typescript/examples/node-tester/plain-html/.babelrc b/sdk/typescript/examples/node-tester/plain-html/.babelrc new file mode 100644 index 0000000000..85e1f1ba26 --- /dev/null +++ b/sdk/typescript/examples/node-tester/plain-html/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["@babel/env", "@babel/react"] +} \ No newline at end of file diff --git a/sdk/typescript/examples/node-tester/plain-html/README.md b/sdk/typescript/examples/node-tester/plain-html/README.md new file mode 100644 index 0000000000..a255725316 --- /dev/null +++ b/sdk/typescript/examples/node-tester/plain-html/README.md @@ -0,0 +1,14 @@ +# HTML Nyn Node Test + +This is an example of using the Nym Mixnet node tester. + +You can use this example as a seed for a new project. + +## Running the example + +Try out the node tester app by running: + +``` +npm install +npm start +``` diff --git a/sdk/typescript/examples/node-tester/plain-html/jest.config.js b/sdk/typescript/examples/node-tester/plain-html/jest.config.js new file mode 100644 index 0000000000..e86e13bab9 --- /dev/null +++ b/sdk/typescript/examples/node-tester/plain-html/jest.config.js @@ -0,0 +1,5 @@ +/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', +}; diff --git a/sdk/typescript/examples/node-tester/plain-html/package.json b/sdk/typescript/examples/node-tester/plain-html/package.json new file mode 100644 index 0000000000..a3befe83ea --- /dev/null +++ b/sdk/typescript/examples/node-tester/plain-html/package.json @@ -0,0 +1,61 @@ +{ + "name": "@nymproject/sdk-example-node-tester-plain-html", + "description": "An example project that uses WASM node tester and plain HTML", + "version": "1.0.0", + "license": "Apache-2.0", + "devDependencies": { + "@babel/core": "^7.15.0", + "@babel/plugin-transform-async-to-generator": "^7.14.5", + "@babel/preset-env": "^7.15.0", + "@babel/preset-typescript": "^7.15.0", + "@types/jest": "^27.0.1", + "@types/node": "^16.7.13", + "@typescript-eslint/eslint-plugin": "^5.13.0", + "@typescript-eslint/parser": "^5.13.0", + "babel-loader": "^8.3.0", + "babel-plugin-root-import": "^5.1.0", + "clean-webpack-plugin": "^4.0.0", + "css-loader": "^6.7.3", + "css-minimizer-webpack-plugin": "^3.0.2", + "dotenv-webpack": "^7.0.3", + "eslint": "^8.10.0", + "eslint-config-airbnb": "^19.0.4", + "eslint-config-airbnb-typescript": "^16.1.0", + "eslint-config-prettier": "^8.5.0", + "eslint-import-resolver-root-import": "^1.0.4", + "eslint-plugin-import": "^2.25.4", + "eslint-plugin-jest": "^26.1.1", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-prettier": "^4.0.0", + "file-loader": "^6.2.0", + "fork-ts-checker-webpack-plugin": "^7.2.1", + "html-webpack-plugin": "^5.3.2", + "jest": "^27.1.0", + "mini-css-extract-plugin": "^2.2.2", + "npm-run-all": "^4.1.5", + "prettier": "^2.8.7", + "style-loader": "^3.3.1", + "thread-loader": "^3.0.4", + "ts-jest": "^27.0.5", + "ts-loader": "^9.4.2", + "tsconfig-paths-webpack-plugin": "^3.5.2", + "typescript": "^4.6.2", + "url-loader": "^4.1.1", + "webpack": "^5.75.0", + "webpack-cli": "^4.8.0", + "webpack-dev-server": "^4.5.0", + "webpack-merge": "^5.8.0" + }, + "scripts": { + "start": "webpack serve --progress --port 3000", + "build": "webpack build --progress --config webpack.prod.js", + "build:dev": "webpack build --progress", + "build:serve": "npx serve dist", + "test": "jest", + "test:watch": "jest --watch", + "tsc": "tsc", + "tsc:watch": "tsc --watch", + "lint": "eslint src", + "lint:fix": "eslint src --fix" + } +} diff --git a/sdk/typescript/examples/node-tester/plain-html/src/index.html b/sdk/typescript/examples/node-tester/plain-html/src/index.html new file mode 100644 index 0000000000..ccac6e2365 --- /dev/null +++ b/sdk/typescript/examples/node-tester/plain-html/src/index.html @@ -0,0 +1,29 @@ + + + + + + + Nym WebAssembly Demo + + + +

+ +

+

+ + + + +

+ +

Test a mixnode by entering the mixnode id above and click the Test button

+ +
+

+

+

+ + + diff --git a/sdk/typescript/examples/node-tester/plain-html/src/index.ts b/sdk/typescript/examples/node-tester/plain-html/src/index.ts new file mode 100644 index 0000000000..a2946ba079 --- /dev/null +++ b/sdk/typescript/examples/node-tester/plain-html/src/index.ts @@ -0,0 +1,116 @@ +import { createNodeTesterClient, NodeTester } from '@nymproject/sdk'; + +let nodeTester: NodeTester | null = null; + +/** + * Display messages that have been sent up the websocket. Colours them blue. + * + * @param {string} message + */ +function displayOutput(message: string, color?: string) { + const timestamp = new Date().toISOString().substr(11, 12); + + const sendDiv = document.createElement('div'); + const paragraph = document.createElement('p'); + paragraph.setAttribute('style', `color: ${color || 'blue'}`); + const paragraphContent = document.createTextNode(`${timestamp} >>> ${message}`); + paragraph.appendChild(paragraphContent); + + sendDiv.appendChild(paragraph); + document.getElementById('output')?.appendChild(sendDiv); +} + +/** + * The main entry point + */ +async function main() { + nodeTester = await createNodeTesterClient(); + + // add node tester to the Window globally, so that it can be used from the dev tools console + (window as any).nodeTester = nodeTester; + + if (!nodeTester) { + console.error('Oh no! Could not the node test'); + return; + } + + const nymApiUrl = 'https://validator.nymtech.net/api'; + const nodeTesterId = new Date().toISOString(); // make a new tester id for each session + await nodeTester.tester.init(nymApiUrl, nodeTesterId); + + const mixnodes = await (await fetch(`${nymApiUrl}/v1/mixnodes/active`)).json(); + + const exampleMixnodeIdentityKey = mixnodes[0].bond_information.mix_node.identity_key; + + const sendButton: HTMLButtonElement = document.querySelector('#send-button') as HTMLButtonElement; + const reconnectButton: HTMLButtonElement = document.querySelector('#reconnect-button') as HTMLButtonElement; + const disconnectButton: HTMLButtonElement = document.querySelector('#disconnect-button') as HTMLButtonElement; + const terminateButton: HTMLButtonElement = document.querySelector('#terminate-button') as HTMLButtonElement; + + const mixnodeIdInput = document.getElementById('mixnodeId') as HTMLFormElement; + + mixnodeIdInput.value = exampleMixnodeIdentityKey; + + reconnectButton.onclick = async function () { + try { + await nodeTester?.tester.reconnectToGateway(); + } catch (e: any) { + console.error('Error', e); + displayOutput(`ERROR: ${e.message}`, 'red'); + } + }; + + disconnectButton.onclick = async function () { + try { + await nodeTester?.tester.disconnectFromGateway(); + } catch (e: any) { + console.error('Error', e); + displayOutput(`ERROR: ${e.message}`, 'red'); + } + }; + + terminateButton.onclick = async function () { + try { + await nodeTester?.terminate(); + } catch (e: any) { + console.error('Error', e); + displayOutput(`ERROR: ${e.message}`, 'red'); + } + }; + + if (sendButton) { + sendButton.onclick = async function () { + const mixnodeId = mixnodeIdInput.value; + if (!nodeTester) { + displayOutput('ERROR: The node tester is not defined'); + console.error('The node tester is not defined'); + return; + } + if (!mixnodeId) { + displayOutput('ERROR: No mix id specified'); + console.error('No mix id specified'); + return; + } + + if (nodeTester && mixnodeId) { + displayOutput('Starting test...'); + try { + const response = await nodeTester.tester.startTest(mixnodeId); + displayOutput('Done!'); + if (response) { + displayOutput(JSON.stringify(response, null, 2), 'green'); + } + } catch (e: any) { + console.error('Error', e); + displayOutput(`ERROR: ${e.message}`, 'red'); + } + } + }; + } +} + +// wait for the html to load +window.addEventListener('DOMContentLoaded', () => { + // let's do this! + main(); +}); diff --git a/sdk/typescript/examples/node-tester/plain-html/tsconfig.json b/sdk/typescript/examples/node-tester/plain-html/tsconfig.json new file mode 100644 index 0000000000..86902367db --- /dev/null +++ b/sdk/typescript/examples/node-tester/plain-html/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "jsx": "react-jsx", + "outDir": "./dist" + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "build", "dist"] +} diff --git a/sdk/typescript/examples/node-tester/plain-html/tsconfig.prod.json b/sdk/typescript/examples/node-tester/plain-html/tsconfig.prod.json new file mode 100644 index 0000000000..cd04ae7aed --- /dev/null +++ b/sdk/typescript/examples/node-tester/plain-html/tsconfig.prod.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "jsx": "react-jsx", + "outDir": "./dist", + "declaration": false + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "build", "dist", "**/*.stories.*", "**/*.test.*", "**/*.spec.*"] +} diff --git a/sdk/typescript/examples/node-tester/plain-html/webpack.common.js b/sdk/typescript/examples/node-tester/plain-html/webpack.common.js new file mode 100644 index 0000000000..ae6ef6dc8e --- /dev/null +++ b/sdk/typescript/examples/node-tester/plain-html/webpack.common.js @@ -0,0 +1,30 @@ +const path = require('path'); +const { mergeWithRules } = require('webpack-merge'); +const { webpackCommon } = require('../../.webpack/webpack.base'); + +module.exports = mergeWithRules({ + module: { + rules: { + test: 'match', + use: 'replace', + }, + }, +})( + webpackCommon(__dirname, [ + { + inject: true, + filename: 'index.html', + template: path.resolve(__dirname, 'src/index.html'), + chunks: ['index'], + }, + ]), + { + entry: { + index: path.resolve(__dirname, 'src/index.ts'), + }, + output: { + path: path.resolve(__dirname, 'dist'), + publicPath: '/', + }, + }, +); diff --git a/sdk/typescript/examples/node-tester/plain-html/webpack.config.js b/sdk/typescript/examples/node-tester/plain-html/webpack.config.js new file mode 100644 index 0000000000..8c7288de81 --- /dev/null +++ b/sdk/typescript/examples/node-tester/plain-html/webpack.config.js @@ -0,0 +1,67 @@ +const { mergeWithRules } = require('webpack-merge'); +const webpack = require('webpack'); +const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); +const ReactRefreshTypeScript = require('react-refresh-typescript'); +const commonConfig = require('./webpack.common'); + +module.exports = mergeWithRules({ + module: { + rules: { + test: 'match', + use: 'replace', + }, + }, +})(commonConfig, { + mode: 'development', + devtool: 'inline-source-map', + module: { + rules: [ + { + test: /\.tsx?$/, + use: 'ts-loader', + exclude: /node_modules/, + options: { + getCustomTransformers: () => ({ + before: [ReactRefreshTypeScript()], + }), + // `ts-loader` does not work with HMR unless `transpileOnly` is used. + // If you need type checking, `ForkTsCheckerWebpackPlugin` is an alternative. + transpileOnly: true, + }, + }, + ], + }, + plugins: [ + new ReactRefreshWebpackPlugin(), + + // this can be included automatically by the dev server, however build mode fails if missing + new webpack.HotModuleReplacementPlugin(), + ], + + target: 'web', + + devServer: { + headers: { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization', + }, + historyApiFallback: true, + }, + + // recommended for faster rebuild + optimization: { + runtimeChunk: true, + removeAvailableModules: false, + removeEmptyChunks: false, + splitChunks: false, + }, + + cache: { + type: 'filesystem', + buildDependencies: { + // restart on config change + config: ['./webpack.config.js'], + }, + }, +}); diff --git a/sdk/typescript/examples/node-tester/plain-html/webpack.prod.js b/sdk/typescript/examples/node-tester/plain-html/webpack.prod.js new file mode 100644 index 0000000000..c92239179a --- /dev/null +++ b/sdk/typescript/examples/node-tester/plain-html/webpack.prod.js @@ -0,0 +1,42 @@ +const { mergeWithRules } = require('webpack-merge'); +const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const commonConfig = require('./webpack.common'); + +module.exports = mergeWithRules({ + module: { + rules: { + test: 'match', + use: 'replace', + }, + }, +})(commonConfig, { + mode: 'production', + + // TODO: no source maps, add back + devtool: false, + + module: { + rules: [ + { + test: /\.css$/, + use: [MiniCssExtractPlugin.loader, 'css-loader'], + }, + ], + }, + optimization: { + minimizer: ['...', new CssMinimizerPlugin()], + splitChunks: { + chunks: 'all', + }, + }, + plugins: [ + new MiniCssExtractPlugin({ + filename: '[name].[contenthash].css', + }), + ], + output: { + pathinfo: false, + filename: '[name].[contenthash].js', + }, +}); diff --git a/sdk/typescript/examples/plain-html/tsconfig.prod.json b/sdk/typescript/examples/plain-html/tsconfig.prod.json index ea260ca2f9..2e8a618c0f 100644 --- a/sdk/typescript/examples/plain-html/tsconfig.prod.json +++ b/sdk/typescript/examples/plain-html/tsconfig.prod.json @@ -1,20 +1,10 @@ { - "extends": "../tsconfig.json", + "extends": "../../tsconfig.json", "compilerOptions": { "jsx": "react-jsx", "outDir": "./dist", "declaration": false }, - "include": [ - "src/**/*.ts", - "src/**/*.tsx" - ], - "exclude": [ - "node_modules", - "build", - "dist", - "**/*.stories.*", - "**/*.test.*", - "**/*.spec.*" - ] + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "build", "dist", "**/*.stories.*", "**/*.test.*", "**/*.spec.*"] } diff --git a/sdk/typescript/packages/sdk/.gitignore b/sdk/typescript/packages/sdk/.gitignore index f2883f65bd..6166d37c02 100644 --- a/sdk/typescript/packages/sdk/.gitignore +++ b/sdk/typescript/packages/sdk/.gitignore @@ -1 +1,2 @@ src/mixnet/wasm/worker.js +src/mixnet/node-tester/worker.js \ No newline at end of file diff --git a/sdk/typescript/packages/sdk/package.json b/sdk/typescript/packages/sdk/package.json index 7b05d365af..7b2b512f37 100644 --- a/sdk/typescript/packages/sdk/package.json +++ b/sdk/typescript/packages/sdk/package.json @@ -26,10 +26,12 @@ "build:only-this": "scripts/build-prod.sh", "prebuild:dev": "yarn build:dependencies", "build:dev": "yarn build:dev:only-this", - "build:dev:only-this": "scripts/build.sh" + "build:dev:only-this": "scripts/build.sh", + "build:lint": "run-s build:dependencies:nym-client-wasm build:dev:only-this" }, "dependencies": { "@npmcli/node-gyp": "^3.0.0", + "@nymproject/nym-client-wasm": "1", "comlink": "^4.3.1", "lerna": "^6.6.2", "node-gyp": "^9.3.1" diff --git a/sdk/typescript/packages/sdk/rollup-cjs.config.mjs b/sdk/typescript/packages/sdk/rollup-cjs.config.mjs index fdd081ab49..9f6d102d3d 100644 --- a/sdk/typescript/packages/sdk/rollup-cjs.config.mjs +++ b/sdk/typescript/packages/sdk/rollup-cjs.config.mjs @@ -3,9 +3,7 @@ import resolve from '@rollup/plugin-node-resolve'; import { wasm } from '@rollup/plugin-wasm'; import webWorkerLoader from 'rollup-plugin-web-worker-loader'; -const extensions = [ - '.js', '.jsx', '.ts', '.tsx', -]; +const extensions = ['.js', '.jsx', '.ts', '.tsx']; export default { input: 'src/index.ts', @@ -17,6 +15,9 @@ export default { webWorkerLoader({ targetPlatform: 'browser', inline: true }), resolve({ extensions }), wasm({ maxFileSize: 10000000, targetEnv: 'browser' }), - typescript({ compilerOptions: { outDir: 'dist/cjs', target: 'es5' }, exclude: 'mixnet/wasm/worker.ts', }), + typescript({ + compilerOptions: { outDir: 'dist/cjs', target: 'es5' }, + exclude: ['mixnet/wasm/worker.ts', 'mixnet/node-tester/worker.ts'], + }), ], }; diff --git a/sdk/typescript/packages/sdk/rollup-esm.config.mjs b/sdk/typescript/packages/sdk/rollup-esm.config.mjs index 546188a9c3..3ad4c148fc 100644 --- a/sdk/typescript/packages/sdk/rollup-esm.config.mjs +++ b/sdk/typescript/packages/sdk/rollup-esm.config.mjs @@ -2,9 +2,7 @@ import typescript from '@rollup/plugin-typescript'; import resolve from '@rollup/plugin-node-resolve'; import webWorkerLoader from 'rollup-plugin-web-worker-loader'; -const extensions = [ - '.js', '.jsx', '.ts', '.tsx', -]; +const extensions = ['.js', '.jsx', '.ts', '.tsx']; export default { input: 'src/index.ts', @@ -15,6 +13,9 @@ export default { plugins: [ webWorkerLoader({ targetPlatform: 'browser', inline: true }), resolve({ extensions }), - typescript({ exclude: 'mixnet/wasm/worker.ts', compilerOptions: { outDir: 'dist/esm' } }), + typescript({ + exclude: ['mixnet/wasm/worker.ts', 'mixnet/node-tester/worker.ts'], + compilerOptions: { outDir: 'dist/esm' }, + }), ], }; diff --git a/sdk/typescript/packages/sdk/rollup-node-tester-worker.config.mjs b/sdk/typescript/packages/sdk/rollup-node-tester-worker.config.mjs new file mode 100644 index 0000000000..5f18e7ce33 --- /dev/null +++ b/sdk/typescript/packages/sdk/rollup-node-tester-worker.config.mjs @@ -0,0 +1,26 @@ +import typescript from '@rollup/plugin-typescript'; +import resolve from '@rollup/plugin-node-resolve'; +import { wasm } from '@rollup/plugin-wasm'; +import replace from '@rollup/plugin-replace'; + +const extensions = ['.js', '.jsx', '.ts', '.tsx']; + +export default { + input: 'src/mixnet/node-tester/worker.ts', + output: { + dir: 'dist', + format: 'cjs', + }, + plugins: [ + resolve({ extensions }), + // this is some nasty monkey patching that removes the WASM URL (because it is handled by the `wasm` plugin) + replace({ + values: { "input = new URL('nym_client_wasm_bg.wasm', import.meta.url);": 'input = undefined;' }, + delimiters: ['', ''], + preventAssignment: true, + }), + // force the wasm plugin to embed the wasm bundle - this means no downstream bundlers have to worry about handling it + wasm({ maxFileSize: 10000000, targetEnv: 'browser' }), + typescript({ compilerOptions: { declaration: false, target: 'es5' } }), + ], +}; diff --git a/sdk/typescript/packages/sdk/scripts/build.sh b/sdk/typescript/packages/sdk/scripts/build.sh index 8440a3adda..d2763969e7 100755 --- a/sdk/typescript/packages/sdk/scripts/build.sh +++ b/sdk/typescript/packages/sdk/scripts/build.sh @@ -7,7 +7,7 @@ set -o pipefail rm -rf dist || true #------------------------------------------------------- -# WEB WORKER +# WEB WORKER (WASM client) #------------------------------------------------------- # The web worker needs to be bundled because the WASM bundle needs to be loaded synchronously and all dependencies # must be included in the worker script (because it is not loaded as an ES Module) @@ -19,6 +19,19 @@ rollup -c rollup-worker.config.mjs rm -f src/mixnet/wasm/worker.js mv dist/worker.js src/mixnet/wasm/worker.js +#------------------------------------------------------- +# WEB WORKER (Node tester) +#------------------------------------------------------- +# The web worker needs to be bundled because the WASM bundle needs to be loaded synchronously and all dependencies +# must be included in the worker script (because it is not loaded as an ES Module) + +# build the worker +rollup -c rollup-node-tester-worker.config.mjs + +# move it next to the Typescript `mixnet/node-tester/index.ts` so it can be inlined by rollup +rm -f src/mixnet/node-tester/worker.js +mv dist/worker.js src/mixnet/node-tester/worker.js + #------------------------------------------------------- # ESM #------------------------------------------------------- diff --git a/sdk/typescript/packages/sdk/src/mixnet/index.ts b/sdk/typescript/packages/sdk/src/mixnet/index.ts index 3c4c661762..2fb66914e6 100644 --- a/sdk/typescript/packages/sdk/src/mixnet/index.ts +++ b/sdk/typescript/packages/sdk/src/mixnet/index.ts @@ -1,2 +1,4 @@ export * from './wasm'; export * from './wasm/types'; +export * from './node-tester'; +export * from './node-tester/types'; diff --git a/sdk/typescript/packages/sdk/src/mixnet/node-tester/constants.ts b/sdk/typescript/packages/sdk/src/mixnet/node-tester/constants.ts new file mode 100644 index 0000000000..55770cd39b --- /dev/null +++ b/sdk/typescript/packages/sdk/src/mixnet/node-tester/constants.ts @@ -0,0 +1,5 @@ +const QA_VALIDATOR_URL = 'https://qa-nym-api.qa.nymte.ch/api'; +const QWERTY_VALIDATOR_URL = 'https://qwerty-validator-api.qa.nymte.ch/api'; +const MAINNET_VALIDATOR_URL = 'https://validator.nymtech.net/api/'; + +export { QA_VALIDATOR_URL, QWERTY_VALIDATOR_URL, MAINNET_VALIDATOR_URL }; diff --git a/sdk/typescript/packages/sdk/src/mixnet/node-tester/index.ts b/sdk/typescript/packages/sdk/src/mixnet/node-tester/index.ts new file mode 100644 index 0000000000..04e52ee579 --- /dev/null +++ b/sdk/typescript/packages/sdk/src/mixnet/node-tester/index.ts @@ -0,0 +1,50 @@ +import InlineWasmWebWorker from 'web-worker:./worker'; +import * as Comlink from 'comlink'; +import { INodeTesterWorkerAsync, NodeTester, NodeTesterEventKinds } from './types'; + +/** + * Client for the Nym node tester. + */ +export const createNodeTesterClient = async (): Promise => { + // eslint-disable-next-line @typescript-eslint/no-use-before-define + const worker = await createWorker(); + + // let comlink handle interop with the web worker + const tester = Comlink.wrap(worker); + + // expose the method to terminate the worker + const terminate = async () => { + worker.terminate(); + }; + + return { tester, terminate }; +}; + +/** + * Async method to create a web worker that runs the Nym node tester client on another thread. It will only return once the worker + * has passed back a `Loaded` event to the calling thread. + * + * @return The instance of the web worker. + */ + +const createWorker = async () => + new Promise((resolve, reject) => { + // rollup will inline the built worker script, so that when the SDK is used in + // other projects, they will not need to mess around trying to bundle it + // however, it will make this SDK bundle bigger because of Base64 inline data + const worker = new InlineWasmWebWorker(); + + worker.addEventListener('error', reject); + worker.addEventListener( + 'message', + (msg) => { + worker.removeEventListener('error', reject); + if (msg.data?.kind === NodeTesterEventKinds.Loaded) { + resolve(worker); + } else { + reject(msg); + } + }, + { once: true }, + ); + }); diff --git a/sdk/typescript/packages/sdk/src/mixnet/node-tester/types.ts b/sdk/typescript/packages/sdk/src/mixnet/node-tester/types.ts new file mode 100644 index 0000000000..a556fec243 --- /dev/null +++ b/sdk/typescript/packages/sdk/src/mixnet/node-tester/types.ts @@ -0,0 +1,65 @@ +export interface INodeTesterWorkerAsync { + init: (validatorUrl: string, nodeTesterId?: string) => Promise; + reconnectToGateway: () => Promise; + disconnectFromGateway: () => Promise; + startTest: (mixnodeIdentityKey: string) => Promise; +} + +export interface INodeTesterWorkerDisposableAsync { + terminate: () => Promise; +} + +export interface NodeTester extends INodeTesterWorkerDisposableAsync { + tester: INodeTesterWorkerAsync; +} + +export enum NodeTesterEventKinds { + Loaded = 'Loaded', + Connected = 'Connected', +} + +export interface NodeTesterLoadedEvent { + kind: NodeTesterEventKinds.Loaded; + args: { + loaded: true; + }; +} + +export type Network = 'QA' | 'SANDBOX' | 'MAINNET'; + +export type NodeTestResultResponse = { + score: number; + sentPackets: number; + receivedPackets: number; + receivedAcks: number; + duplicatePackets: number; + duplicateAcks: number; +}; + +export type Error = { + kind: 'Error'; + args: { message: string }; +}; + +export type WorkerLoaded = { + kind: 'WorkerLoaded'; +}; + +export type DisplayTesterResults = { + kind: 'DisplayTesterResults'; + args: { + result: NodeTestResultResponse; + }; +}; + +export type TestPacket = { + kind: 'TestPacket'; + args: { + mixnodeIdentity: string; + network: Network; + }; +}; + +export type TestStatus = 'Stopped' | 'Running' | 'Complete'; + +export type NodeTestEvent = Error | DisplayTesterResults | TestPacket | WorkerLoaded; diff --git a/sdk/typescript/packages/sdk/src/mixnet/node-tester/worker.ts b/sdk/typescript/packages/sdk/src/mixnet/node-tester/worker.ts new file mode 100644 index 0000000000..ec51afd3ce --- /dev/null +++ b/sdk/typescript/packages/sdk/src/mixnet/node-tester/worker.ts @@ -0,0 +1,105 @@ +// Copyright 2020-2023 Nym Technologies SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import * as Comlink from 'comlink'; + +// +// Rollup will replace wasmBytes with a function that loads the WASM bundle from a base64 string embedded in the output. +// +// Doing it this way, saves having to support a large variety of bundlers and their quirks. +// +// @ts-ignore +// eslint-disable-next-line import/no-extraneous-dependencies +import wasmBytes from '@nymproject/nym-client-wasm/nym_client_wasm_bg.wasm'; + +/* eslint-disable no-restricted-globals */ +import init, { NymNodeTester, current_network_topology, NodeTestResult } from '@nymproject/nym-client-wasm'; +import type { INodeTesterWorkerAsync, NodeTesterLoadedEvent } from './types'; +import { NodeTesterEventKinds } from './types'; + +/** + * Helper method to send typed messages. + * @param event The strongly typed message to send back to the calling thread. + */ +// eslint-disable-next-line no-restricted-globals +const postMessageWithType = (event: E) => self.postMessage(event); + +console.log('[Nym WASM client] Starting Nym WASM web worker...'); + +const buildTester = async (validatorUrl: string, nodeTesterId?: string): Promise => { + const topology = await current_network_topology(validatorUrl); + return new NymNodeTester(topology, nodeTesterId); +}; + +async function main() { + const importResult = await init(wasmBytes()); + importResult.set_panic_hook(); + + let nodeTester: NymNodeTester | null = null; + + const webWorker: INodeTesterWorkerAsync = { + async init(validatorUrl: string, nodeTesterId?: string) { + nodeTester = await buildTester(validatorUrl, nodeTesterId); + }, + async reconnectToGateway() { + if (!nodeTester) { + throw Error('Please run init first'); + } + await nodeTester.reconnect_to_gateway(); + }, + async disconnectFromGateway() { + if (!nodeTester) { + throw Error('Please run init first'); + } + await nodeTester.disconnect_from_gateway(); + }, + async startTest(mixnodeIdentityKey: string) { + if (!nodeTester) { + throw Error('Please run init first'); + } + console.log(`Testing mixnode with identity key = ${mixnodeIdentityKey}`); + // TODO: fix typing in Rust code + const result = (await nodeTester.test_node(mixnodeIdentityKey)) as NodeTestResult | undefined; + + // return early if there was an error + if (!result) { + return result; + } + + // log the result in the worker so that the packet stats are visible somewhere and extract the score + result.log_details(); + + // eslint-disable-next-line @typescript-eslint/naming-convention + const { duplicate_acks, duplicate_packets, received_acks, received_packets, sent_packets } = result; + + // construct the response to avoid any weird proxy effects + return { + score: result.score(), + sentPackets: sent_packets, + receivedPackets: received_packets, + receivedAcks: received_acks, + duplicatePackets: duplicate_packets, + duplicateAcks: duplicate_acks, + }; + }, + }; + + // start comlink listening for messages and handle them above + Comlink.expose(webWorker); + + // notify any listeners that the web worker has loaded and is ready for testing + postMessageWithType({ kind: NodeTesterEventKinds.Loaded, args: { loaded: true } }); +} + +main(); diff --git a/sdk/typescript/packages/sdk/src/mixnet/wasm/types-from-wasm-pack.ts b/sdk/typescript/packages/sdk/src/mixnet/wasm/types-from-wasm-pack.ts new file mode 100644 index 0000000000..25fbba452c --- /dev/null +++ b/sdk/typescript/packages/sdk/src/mixnet/wasm/types-from-wasm-pack.ts @@ -0,0 +1,336 @@ +/** + */ +export interface TopologyWasm { + free(): void; + /** + * Specifies whether the client should not refresh the network topology after obtaining + * the first valid instance. + * Supersedes `topology_refresh_rate_ms`. + */ + disable_refreshing: boolean; + /** + * The uniform delay every which clients are querying the directory server + * to try to obtain a compatible network topology to send sphinx packets through. + */ + topology_refresh_rate_ms: bigint; + /** + * During topology refresh, test packets are sent through every single possible network + * path. This timeout determines waiting period until it is decided that the packet + * did not reach its destination. + */ + topology_resolution_timeout_ms: bigint; +} +/** + */ +export interface TrafficWasm { + free(): void; + /** + * The parameter of Poisson distribution determining how long, on average, + * sent packet is going to be delayed at any given mix node. + * So for a packet going through three mix nodes, on average, it will take three times this value + * until the packet reaches its destination. + */ + average_packet_delay_ms: bigint; + /** + * Controls whether the main packet stream constantly produces packets according to the predefined + * poisson distribution. + */ + disable_main_poisson_packet_distribution: boolean; + /** + * The parameter of Poisson distribution determining how long, on average, + * it is going to take another 'real traffic stream' message to be sent. + * If no real packets are available and cover traffic is enabled, + * a loop cover message is sent instead in order to preserve the rate. + */ + message_sending_average_delay_ms: bigint; + /** + * Controls whether the sent sphinx packet use the NON-DEFAULT bigger size. + */ + use_extended_packet_size: boolean; + /** + * Controls whether the sent packets should use outfox as opposed to the default sphinx. + */ + use_outfox: boolean; +} +/** + */ +export interface WasmGateway { + free(): void; + /** + */ + clients_port: number; + /** + */ + host: string; + /** + */ + identity_key: string; + /** + */ + mix_port: number; + /** + */ + owner: string; + /** + */ + sphinx_key: string; + /** + */ + version: string; +} + +/** + */ +export interface ReplySurbsWasm { + free(): void; + /** + * Defines the maximum number of reply surbs a remote party is allowed to request from this client at once. + */ + maximum_allowed_reply_surb_request_size: number; + /** + * Defines maximum amount of time given reply key is going to be valid for. + * This is going to be superseded by key rotation once implemented. + */ + maximum_reply_key_age_ms: bigint; + /** + * Defines maximum amount of time given reply surb is going to be valid for. + * This is going to be superseded by key rotation once implemented. + */ + maximum_reply_surb_age_ms: bigint; + /** + * Defines maximum amount of time the client is going to wait for reply surbs before + * deciding it's never going to get them and would drop all pending messages + */ + maximum_reply_surb_drop_waiting_period_ms: bigint; + /** + * Defines the maximum number of reply surbs the client would request. + */ + maximum_reply_surb_request_size: number; + /** + * Defines maximum amount of time the client is going to wait for reply surbs before explicitly asking + * for more even though in theory they wouldn't need to. + */ + maximum_reply_surb_rerequest_waiting_period_ms: bigint; + /** + * Defines the maximum number of reply surbs the client wants to keep in its storage at any times. + */ + maximum_reply_surb_storage_threshold: number; + /** + * Defines the minimum number of reply surbs the client would request. + */ + minimum_reply_surb_request_size: number; + /** + * Defines the minimum number of reply surbs the client wants to keep in its storage at all times. + * It can only allow to go below that value if its to request additional reply surbs. + */ + minimum_reply_surb_storage_threshold: number; +} + +/** + */ +export interface GatewayConnectionWasm { + free(): void; + /** + * How long we're willing to wait for a response to a message sent to the gateway, + * before giving up on it. + */ + gateway_response_timeout_ms: bigint; +} + +/** + */ +export interface AcknowledgementsWasm { + free(): void; + /** + * Value added to the expected round trip time of an acknowledgement packet before + * it is assumed it was lost and retransmission of the data packet happens. + * In an ideal network with 0 latency, this value would have been 0. + */ + ack_wait_addition_ms: bigint; + /** + * Value multiplied with the expected round trip time of an acknowledgement packet before + * it is assumed it was lost and retransmission of the data packet happens. + * In an ideal network with 0 latency, this value would have been 1. + */ + ack_wait_multiplier: number; + /** + * The parameter of Poisson distribution determining how long, on average, + * sent acknowledgement is going to be delayed at any given mix node. + * So for an ack going through three mix nodes, on average, it will take three times this value + * until the packet reaches its destination. + */ + average_ack_delay_ms: bigint; +} + +/** + */ +export interface CoverTrafficWasm { + free(): void; + /** + * Specifies the ratio of `primary_packet_size` to `secondary_packet_size` used in cover traffic. + * Only applicable if `secondary_packet_size` is enabled. + */ + cover_traffic_primary_size_ratio: number; + /** + * Controls whether the dedicated loop cover traffic stream should be enabled. + * (and sending packets, on average, every [Self::loop_cover_traffic_average_delay]) + */ + disable_loop_cover_traffic_stream: boolean; + /** + * The parameter of Poisson distribution determining how long, on average, + * it is going to take for another loop cover traffic message to be sent. + */ + loop_cover_traffic_average_delay_ms: bigint; +} + +export interface Config { + free(): void; +} + +export interface DebugWasm { + free(): void; + /** + * Defines all configuration options related to acknowledgements, such as delays or wait timeouts. + */ + acknowledgements: AcknowledgementsWasm; + /** + * Defines all configuration options related to cover traffic stream(s). + */ + cover_traffic: CoverTrafficWasm; + /** + * Defines all configuration options related to the gateway connection. + */ + gateway_connection: GatewayConnectionWasm; + /** + * Defines all configuration options related to reply SURBs. + */ + reply_surbs: ReplySurbsWasm; + /** + * Defines all configuration options related topology, such as refresh rates or timeouts. + */ + topology: TopologyWasm; + /** + * Defines all configuration options related to traffic streams. + */ + traffic: TrafficWasm; +} +/** + */ +export interface GatewayEndpointConfig { + free(): void; + /** + * gateway_id specifies ID of the gateway to which the client should send messages. + * If initially omitted, a random gateway will be chosen from the available topology. + */ + gateway_id: string; + /** + * Address of the gateway listener to which all client requests should be sent. + */ + gateway_listener: string; + /** + * Address of the gateway owner to which the client should send messages. + */ + gateway_owner: string; +} +/** + */ +export interface NymClient { + free(): void; + /** + * @returns {string} + */ + self_address(): string; + /** + * The simplest message variant where no additional information is attached. + * You're simply sending your `data` to specified `recipient` without any tagging. + * + * Ends up with `NymMessage::Plain` variant + * @param {Uint8Array} message + * @param {string} recipient + * @returns {Promise} + */ + send_regular_message(message: Uint8Array, recipient: string): Promise; + /** + * Creates a message used for a duplex anonymous communication where the recipient + * will never learn of our true identity. This is achieved by carefully sending `reply_surbs`. + * + * Note that if reply_surbs is set to zero then + * this variant requires the client having sent some reply_surbs in the past + * (and thus the recipient also knowing our sender tag). + * + * Ends up with `NymMessage::Repliable` variant + * @param {Uint8Array} message + * @param {string} recipient + * @param {number} reply_surbs + * @returns {Promise} + */ + send_anonymous_message(message: Uint8Array, recipient: string, reply_surbs: number): Promise; + /** + * Attempt to use our internally received and stored `ReplySurb` to send the message back + * to specified recipient whilst not knowing its full identity (or even gateway). + * + * Ends up with `NymMessage::Reply` variant + * @param {Uint8Array} message + * @param {string} recipient_tag + * @returns {Promise} + */ + send_reply(message: Uint8Array, recipient_tag: string): Promise; +} + +export interface Topology { + free(): void; + /** + * Specifies whether the client should not refresh the network topology after obtaining + * the first valid instance. + * Supersedes `topology_refresh_rate_ms`. + */ + disable_refreshing: boolean; + /** + * The uniform delay every which clients are querying the directory server + * to try to obtain a compatible network topology to send sphinx packets through. + */ + topology_refresh_rate_ms: bigint; + /** + * During topology refresh, test packets are sent through every single possible network + * path. This timeout determines waiting period until it is decided that the packet + * did not reach its destination. + */ + topology_resolution_timeout_ms: bigint; +} + +export interface Traffic { + free(): void; + /** + * The parameter of Poisson distribution determining how long, on average, + * sent packet is going to be delayed at any given mix node. + * So for a packet going through three mix nodes, on average, it will take three times this value + * until the packet reaches its destination. + */ + average_packet_delay_ms: bigint; + /** + * Controls whether the main packet stream constantly produces packets according to the predefined + * poisson distribution. + */ + disable_main_poisson_packet_distribution: boolean; + /** + * The parameter of Poisson distribution determining how long, on average, + * it is going to take another 'real traffic stream' message to be sent. + * If no real packets are available and cover traffic is enabled, + * a loop cover message is sent instead in order to preserve the rate. + */ + message_sending_average_delay_ms: bigint; + /** + * Controls whether the sent sphinx packet use the NON-DEFAULT bigger size. + */ + use_extended_packet_size: boolean; +} + +/** + */ +export interface NymClientBuilder { + free(): void; + /** + * @returns {Promise>} + */ + start_client(): Promise>; +} diff --git a/sdk/typescript/packages/sdk/src/mixnet/wasm/types.ts b/sdk/typescript/packages/sdk/src/mixnet/wasm/types.ts index 4927f10cfc..1f11384b1a 100644 --- a/sdk/typescript/packages/sdk/src/mixnet/wasm/types.ts +++ b/sdk/typescript/packages/sdk/src/mixnet/wasm/types.ts @@ -1,174 +1,6 @@ -export interface Acknowledgements { - free(): void; - /** - * Value added to the expected round trip time of an acknowledgement packet before - * it is assumed it was lost and retransmission of the data packet happens. - * In an ideal network with 0 latency, this value would have been 0. - */ - ack_wait_addition_ms: bigint; - /** - * Value multiplied with the expected round trip time of an acknowledgement packet before - * it is assumed it was lost and retransmission of the data packet happens. - * In an ideal network with 0 latency, this value would have been 1. - */ - ack_wait_multiplier: number; - /** - * The parameter of Poisson distribution determining how long, on average, - * sent acknowledgement is going to be delayed at any given mix node. - * So for an ack going through three mix nodes, on average, it will take three times this value - * until the packet reaches its destination. - */ - average_ack_delay_ms: bigint; -} +import type { DebugWasm } from './types-from-wasm-pack'; -export interface CoverTraffic { - free(): void; - /** - * Specifies the ratio of `primary_packet_size` to `secondary_packet_size` used in cover traffic. - * Only applicable if `secondary_packet_size` is enabled. - */ - cover_traffic_primary_size_ratio: number; - /** - * Controls whether the dedicated loop cover traffic stream should be enabled. - * (and sending packets, on average, every [Self::loop_cover_traffic_average_delay]) - */ - disable_loop_cover_traffic_stream: boolean; - /** - * The parameter of Poisson distribution determining how long, on average, - * it is going to take for another loop cover traffic message to be sent. - */ - loop_cover_traffic_average_delay_ms: bigint; -} - -export interface GatewayConnection { - free(): void; - /** - * How long we're willing to wait for a response to a message sent to the gateway, - * before giving up on it. - */ - gateway_response_timeout_ms: bigint; -} - -export interface ReplySurbs { - free(): void; - /** - * Defines the maximum number of reply surbs a remote party is allowed to request from this client at once. - */ - maximum_allowed_reply_surb_request_size: number; - /** - * Defines maximum amount of time given reply key is going to be valid for. - * This is going to be superseded by key rotation once implemented. - */ - maximum_reply_key_age_ms: bigint; - /** - * Defines maximum amount of time given reply surb is going to be valid for. - * This is going to be superseded by key rotation once implemented. - */ - maximum_reply_surb_age_ms: bigint; - /** - * Defines maximum amount of time the client is going to wait for reply surbs before - * deciding it's never going to get them and would drop all pending messages - */ - maximum_reply_surb_drop_waiting_period_ms: bigint; - /** - * Defines the maximum number of reply surbs the client would request. - */ - maximum_reply_surb_request_size: number; - /** - * Defines maximum amount of time the client is going to wait for reply surbs before explicitly asking - * for more even though in theory they wouldn't need to. - */ - maximum_reply_surb_rerequest_waiting_period_ms: bigint; - /** - * Defines the maximum number of reply surbs the client wants to keep in its storage at any times. - */ - maximum_reply_surb_storage_threshold: number; - /** - * Defines the minimum number of reply surbs the client would request. - */ - minimum_reply_surb_request_size: number; - /** - * Defines the minimum number of reply surbs the client wants to keep in its storage at all times. - * It can only allow to go below that value if its to request additional reply surbs. - */ - minimum_reply_surb_storage_threshold: number; -} - -export interface Debug { - free(): void; - /** - * Defines all configuration options related to acknowledgements, such as delays or wait timeouts. - */ - acknowledgements: Acknowledgements; - /** - * Defines all configuration options related to cover traffic stream(s). - */ - cover_traffic: CoverTraffic; - /** - * Defines all configuration options related to the gateway connection. - */ - gateway_connection: GatewayConnection; - /** - * Defines all configuration options related to reply SURBs. - */ - reply_surbs: ReplySurbs; - /** - * Defines all configuration options related topology, such as refresh rates or timeouts. - */ - topology: Topology; - /** - * Defines all configuration options related to traffic streams. - */ - traffic: Traffic; -} - -export interface Topology { - free(): void; - /** - * Specifies whether the client should not refresh the network topology after obtaining - * the first valid instance. - * Supersedes `topology_refresh_rate_ms`. - */ - disable_refreshing: boolean; - /** - * The uniform delay every which clients are querying the directory server - * to try to obtain a compatible network topology to send sphinx packets through. - */ - topology_refresh_rate_ms: bigint; - /** - * During topology refresh, test packets are sent through every single possible network - * path. This timeout determines waiting period until it is decided that the packet - * did not reach its destination. - */ - topology_resolution_timeout_ms: bigint; -} - -export interface Traffic { - free(): void; - /** - * The parameter of Poisson distribution determining how long, on average, - * sent packet is going to be delayed at any given mix node. - * So for a packet going through three mix nodes, on average, it will take three times this value - * until the packet reaches its destination. - */ - average_packet_delay_ms: bigint; - /** - * Controls whether the main packet stream constantly produces packets according to the predefined - * poisson distribution. - */ - disable_main_poisson_packet_distribution: boolean; - /** - * The parameter of Poisson distribution determining how long, on average, - * it is going to take another 'real traffic stream' message to be sent. - * If no real packets are available and cover traffic is enabled, - * a loop cover message is sent instead in order to preserve the rate. - */ - message_sending_average_delay_ms: bigint; - /** - * Controls whether the sent sphinx packet use the NON-DEFAULT bigger size. - */ - use_extended_packet_size: boolean; -} +export * from './types-from-wasm-pack'; /** * Some common mime types, however, you can always just specify the mime-type as a string @@ -221,7 +53,7 @@ export interface NymClientConfig { /** * Optional. Settings for the WASM client. */ - debug?: Debug; + debug?: DebugWasm; } export interface IWebWorker { diff --git a/sdk/typescript/packages/sdk/src/mixnet/wasm/worker.ts b/sdk/typescript/packages/sdk/src/mixnet/wasm/worker.ts index 4dbe9d5154..f1755b5d1f 100644 --- a/sdk/typescript/packages/sdk/src/mixnet/wasm/worker.ts +++ b/sdk/typescript/packages/sdk/src/mixnet/wasm/worker.ts @@ -168,43 +168,40 @@ init(wasmBytes()) if (config.gatewayListener) gatewayEndpoint.gateway_listener = config.gatewayListener; // create the client, passing handlers for events - wrapper.init( - new Config(config.clientId, config.nymApiUrl, gatewayEndpoint, config.debug || default_debug()), - async (message) => { - // fire an event with the raw message - postMessageWithType({ - kind: EventKinds.RawMessageReceived, - args: { payload: message }, - }); + wrapper.init(new Config(config.clientId, config.nymApiUrl, config.debug || default_debug()), async (message) => { + // fire an event with the raw message + postMessageWithType({ + kind: EventKinds.RawMessageReceived, + args: { payload: message }, + }); - try { - // try to decode the payload to extract the mime-type, headers and payload body - const decodedPayload = decode_payload(message); - const { payload, headers } = decodedPayload; - const mimeType = decodedPayload.mimeType as MimeTypes; + try { + // try to decode the payload to extract the mime-type, headers and payload body + const decodedPayload = decode_payload(message); + const { payload, headers } = decodedPayload; + const mimeType = decodedPayload.mimeType as MimeTypes; - if (wrapper.getTextMimeTypes().includes(mimeType)) { - const stringMessage = parse_utf8_string(payload); + if (wrapper.getTextMimeTypes().includes(mimeType)) { + const stringMessage = parse_utf8_string(payload); - // the payload is a string type (in the options at creation time, string mime-types are set, or fall back - // to defaults, such as `text/plain`, `application/json`, etc) - postMessageWithType({ - kind: EventKinds.StringMessageReceived, - args: { mimeType, payload: stringMessage, payloadRaw: payload, headers }, - }); - return; - } - - // the payload is a binary type - postMessageWithType({ - kind: EventKinds.BinaryMessageReceived, - args: { mimeType, payload, headers }, + // the payload is a string type (in the options at creation time, string mime-types are set, or fall back + // to defaults, such as `text/plain`, `application/json`, etc) + postMessageWithType({ + kind: EventKinds.StringMessageReceived, + args: { mimeType, payload: stringMessage, payloadRaw: payload, headers }, }); - } catch (e) { - console.error('Failed to parse binary message', e); + return; } - }, - ); + + // the payload is a binary type + postMessageWithType({ + kind: EventKinds.BinaryMessageReceived, + args: { mimeType, payload, headers }, + }); + } catch (e) { + console.error('Failed to parse binary message', e); + } + }); // start the client sending traffic await wrapper.start(); diff --git a/ts-packages/mock-nym-api/src/index.ts b/ts-packages/mock-nym-api/src/index.ts index 89ab9ad245..dc5848fd1a 100644 --- a/ts-packages/mock-nym-api/src/index.ts +++ b/ts-packages/mock-nym-api/src/index.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ import express from 'express'; import dotenv from 'dotenv'; import { createProxyMiddleware } from 'http-proxy-middleware'; diff --git a/ts-packages/react-webpack-with-theme-example/src/App.tsx b/ts-packages/react-webpack-with-theme-example/src/App.tsx index 6f70787807..35bca1929e 100644 --- a/ts-packages/react-webpack-with-theme-example/src/App.tsx +++ b/ts-packages/react-webpack-with-theme-example/src/App.tsx @@ -20,6 +20,7 @@ export const Content: FCWithChildren = () => { const isMounted = useIsMounted(); if (isMounted()) { + // eslint-disable-next-line no-console console.log('Content is mounted'); } diff --git a/yarn.lock b/yarn.lock index 34f8aaa416..197fe4355b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + "@adobe/css-tools@^4.0.1": version "4.2.0" resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.2.0.tgz#e1a84fca468f4b337816fcb7f0964beb620ba855" @@ -1203,7 +1208,7 @@ dependencies: regenerator-runtime "^0.13.2" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.9", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.9", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.5.tgz#8564dd588182ce0047d55d7a75e93921107b57ec" integrity sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA== @@ -1808,9 +1813,9 @@ integrity sha512-Bu+AMaXNjrpjh41znzHqaz3r2Nr8hHuHZT6V2LBKMhyMl0FgKA62PNYbqnfgmzOhoWZj70Zecisbo4H1rotP5g== "@floating-ui/dom@^1.0.0": - version "1.4.2" - resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.4.2.tgz#eb3a37f7506c4f95ef735967dc3496b5012e11cb" - integrity sha512-VKmvHVatWnewmGGy+7Mdy4cTJX71Pli6v/Wjb5RQBuq5wjUYx+Ef+kRThi8qggZqDgD8CogCpqhRoVp3+yQk+g== + version "1.4.3" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.4.3.tgz#0854a3297ea03894932381f3ea1403fab3a6e602" + integrity sha512-nB/68NyaQlcdY22L+Fgd1HERQ7UGv7XFN+tPxwrEfQL4nKtAP/jIZnZtpUlXbtV+VEGHh6W/63Gy2C5biWI3sA== dependencies: "@floating-ui/core" "^1.3.1" @@ -2390,6 +2395,20 @@ prop-types "^15.8.1" react-is "^18.2.0" +"@mui/base@5.0.0-beta.5": + version "5.0.0-beta.5" + resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.5.tgz#b566f3beb1eb2823139eabaf52014cf7be900015" + integrity sha512-vy3TWLQYdGNecTaufR4wDNQFV2WEg6wRPi6BVbx6q1vP3K1mbxIn1+XOqOzfYBXjFHvMx0gZAo2TgWbaqfgvAA== + dependencies: + "@babel/runtime" "^7.22.5" + "@emotion/is-prop-valid" "^1.2.1" + "@mui/types" "^7.2.4" + "@mui/utils" "^5.13.6" + "@popperjs/core" "^2.11.8" + clsx "^1.2.1" + prop-types "^15.8.1" + react-is "^18.2.0" + "@mui/core-downloads-tracker@^5.13.4": version "5.13.4" resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.13.4.tgz#7e4b491d8081b6d45ae51556d82cb16b31315a19" @@ -2417,16 +2436,16 @@ react-is "^18.2.0" "@mui/material@^5.0.1", "@mui/material@^5.2.2": - version "5.13.5" - resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.13.5.tgz#c14f14824f3a37ae0c5ebddbc0034956bc6fec30" - integrity sha512-eMay+Ue1OYXOFMQA5Aau7qbAa/kWHLAyi0McsbPTWssCbGehqkF6CIdPsfVGw6tlO+xPee1hUitphHJNL3xpOQ== + version "5.13.6" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.13.6.tgz#caaba1e071e394c415208404ce6964e6c14c16d6" + integrity sha512-/c2ZApeQm2sTYdQXjqEnldaBMBcUEiyu2VRS6bS39ZeNaAcCLBQbYocLR46R+f0S5dgpBzB0T4AsOABPOFYZ5Q== dependencies: - "@babel/runtime" "^7.21.0" - "@mui/base" "5.0.0-beta.4" + "@babel/runtime" "^7.22.5" + "@mui/base" "5.0.0-beta.5" "@mui/core-downloads-tracker" "^5.13.4" - "@mui/system" "^5.13.5" + "@mui/system" "^5.13.6" "@mui/types" "^7.2.4" - "@mui/utils" "^5.13.1" + "@mui/utils" "^5.13.6" "@types/react-transition-group" "^4.4.6" clsx "^1.2.1" csstype "^3.1.2" @@ -2476,16 +2495,16 @@ jss-plugin-vendor-prefixer "^10.10.0" prop-types "^15.8.1" -"@mui/system@>= 5", "@mui/system@^5.0.1", "@mui/system@^5.13.5": - version "5.13.5" - resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.13.5.tgz#9f67ea0c4f6974713f90b7b94c999fd3f40f8de3" - integrity sha512-n0gzUxoZ2ZHZgnExkh2Htvo9uW2oakofgPRQrDoa/GQOWyRD0NH9MDszBwOb6AAoXZb+OV5TE7I4LeZ/dzgHYA== +"@mui/system@>= 5", "@mui/system@^5.0.1", "@mui/system@^5.13.5", "@mui/system@^5.13.6": + version "5.13.6" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.13.6.tgz#5bf4f84fad0c9ed771458f821e384f61abfa33ca" + integrity sha512-G3Xr28uLqU3DyF6r2LQkHGw/ku4P0AHzlKVe7FGXOPl7X1u+hoe2xxj8Vdiq/69II/mh9OP21i38yBWgWb7WgQ== dependencies: - "@babel/runtime" "^7.21.0" + "@babel/runtime" "^7.22.5" "@mui/private-theming" "^5.13.1" "@mui/styled-engine" "^5.13.2" "@mui/types" "^7.2.4" - "@mui/utils" "^5.13.1" + "@mui/utils" "^5.13.6" clsx "^1.2.1" csstype "^3.1.2" prop-types "^15.8.1" @@ -2495,12 +2514,12 @@ resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.4.tgz#b6fade19323b754c5c6de679a38f068fd50b9328" integrity sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA== -"@mui/utils@^5.10.3", "@mui/utils@^5.13.1", "@mui/utils@^5.7.0": - version "5.13.1" - resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.13.1.tgz#86199e46014215f95da046a5ec803f4a39c96eee" - integrity sha512-6lXdWwmlUbEU2jUI8blw38Kt+3ly7xkmV9ljzY4Q20WhsJMWiNry9CX8M+TaP/HbtuyR8XKsdMgQW7h7MM3n3A== +"@mui/utils@^5.10.3", "@mui/utils@^5.13.1", "@mui/utils@^5.13.6", "@mui/utils@^5.7.0": + version "5.13.6" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.13.6.tgz#aa29d75de59577585b9f23891b03592d40459ed7" + integrity sha512-ggNlxl5NPSbp+kNcQLmSig6WVB0Id+4gOxhx644987v4fsji+CSXc+MFYLocFB/x4oHtzCUlSzbVHlJfP/fXoQ== dependencies: - "@babel/runtime" "^7.21.0" + "@babel/runtime" "^7.22.5" "@types/prop-types" "^15.7.5" "@types/react-is" "^18.2.0" prop-types "^15.8.1" @@ -2808,9 +2827,6 @@ dependencies: nx "15.9.4" -"@nymproject/nym-client-wasm@file:clients/webassembly/pkg": - version "1.1.1" - "@nymproject/nym-validator-client@^0.18.0": version "0.18.0" resolved "https://registry.yarnpkg.com/@nymproject/nym-validator-client/-/nym-validator-client-0.18.0.tgz#4dd72bafdf6c72b603242f32c0bb9a1f9e475b98" @@ -3036,10 +3052,10 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== -"@remix-run/router@1.6.3": - version "1.6.3" - resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.6.3.tgz#8205baf6e17ef93be35bf62c37d2d594e9be0dad" - integrity sha512-EXJysQ7J3veRECd0kZFQwYYd5sJMcq2O/m60zu1W2l3oVQ9xtub8jTOtYRE0+M2iomyG/W3Ps7+vp2kna0C27Q== +"@remix-run/router@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.7.0.tgz#550a8d5760b78efc5d60f62b5829b0f74c1fde81" + integrity sha512-Eu1V3kz3mV0wUpVTiFHuaT8UD1gj/0VnoFHQYX35xlslQUpe8CuYoKFn9d4WZFHm3yDywz6ALZuGdnUPKrNeAw== "@rollup/plugin-commonjs@^24.0.1": version "24.1.0" @@ -3107,9 +3123,9 @@ resolve "^1.22.1" "@rollup/plugin-typescript@^11.0.0": - version "11.1.1" - resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-11.1.1.tgz#258663a7aa6b51390dd39ae6e5502f2c4b2807cb" - integrity sha512-Ioir+x5Bejv72Lx2Zbz3/qGg7tvGbxQZALCLoJaGrkNXak/19+vKgKYJYM3i/fJxvsb23I9FuFQ8CUBEfsmBRg== + version "11.1.2" + resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-11.1.2.tgz#09eb5690a650bb0334bf84125bce9abd296442e4" + integrity sha512-0ghSOCMcA7fl1JM+0gYRf+Q/HWyg+zg7/gDSc+fRLmlJWcW5K1I+CLRzaRhXf4Y3DRyPnnDo4M2ktw+a6JcDEg== dependencies: "@rollup/pluginutils" "^5.0.1" resolve "^1.22.1" @@ -3142,79 +3158,79 @@ resolved "https://registry.yarnpkg.com/@sapphire/utilities/-/utilities-3.12.0.tgz#3ee8330338aa79a7e0cab04d4d0eec9ed69fc9bf" integrity sha512-y1JP4FdPBkZjJGJcb5Zx0ok64mtpGvz0TLOC49HTwYsfBQL8tsTct93yoYdEEMWSZFmOF1ZvV8L6jIJ1CW8bJw== -"@sentry-internal/tracing@7.56.0": - version "7.56.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.56.0.tgz#ba709258f2f0f3d8a36f9740403088b39212b843" - integrity sha512-OKI4Pz/O13gng8hT9rNc+gRV3+P7nnk1HnHlV8fgaQydS6DsRxoDL1sHa42tZGbh7K9jqNAP3TC6VjBOsr2tXA== +"@sentry-internal/tracing@7.57.0": + version "7.57.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.57.0.tgz#cb761931b635f8f24c84be0eecfacb8516b20551" + integrity sha512-tpViyDd8AhQGYYhI94xi2aaDopXOPfL2Apwrtb3qirWkomIQ2K86W1mPmkce+B0cFOnW2Dxv/ZTFKz6ghjK75A== dependencies: - "@sentry/core" "7.56.0" - "@sentry/types" "7.56.0" - "@sentry/utils" "7.56.0" - tslib "^1.9.3" + "@sentry/core" "7.57.0" + "@sentry/types" "7.57.0" + "@sentry/utils" "7.57.0" + tslib "^2.4.1 || ^1.9.3" -"@sentry/browser@7.56.0": - version "7.56.0" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.56.0.tgz#6bf3ff21bc2e9b66a72ea0c7dcc3572fdeb3bd8f" - integrity sha512-qpyyw+NM/psbNAYMlTCCdWwxHHcogppEQ+Q40jGE4sKP2VRIjjyteJkUcaEMoGpbJXx9puzTWbpzqlQ8r15Now== +"@sentry/browser@7.57.0": + version "7.57.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.57.0.tgz#6e724c9eac680dba99ced0fdf81be8d1e3b3bceb" + integrity sha512-E0HaYYlaqHFiIRZXxcvOO8Odvlt+TR1vFFXzqUWXPOvDRxURglTOCQ3EN/u6bxtAGJ6y/Zc2obgihTtypuel/w== dependencies: - "@sentry-internal/tracing" "7.56.0" - "@sentry/core" "7.56.0" - "@sentry/replay" "7.56.0" - "@sentry/types" "7.56.0" - "@sentry/utils" "7.56.0" - tslib "^1.9.3" + "@sentry-internal/tracing" "7.57.0" + "@sentry/core" "7.57.0" + "@sentry/replay" "7.57.0" + "@sentry/types" "7.57.0" + "@sentry/utils" "7.57.0" + tslib "^2.4.1 || ^1.9.3" -"@sentry/core@7.56.0": - version "7.56.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.56.0.tgz#f4253e0d61f55444180a63e5278b62e57303f7cf" - integrity sha512-Nuyyfh09Yz27kPo74fXHlrdmZeK6zrlJVtxQ6LkwuoaTBcNcesNXVaOtr6gjvUGUmsfriVPP3Jero5LXufV7GQ== +"@sentry/core@7.57.0": + version "7.57.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.57.0.tgz#65093d739c04f320a54395a21be955fcbe326acb" + integrity sha512-l014NudPH0vQlzybtXajPxYFfs9w762NoarjObC3gu76D1jzBBFzhdRelkGpDbSLNTIsKhEDDRpgAjBWJ9icfw== dependencies: - "@sentry/types" "7.56.0" - "@sentry/utils" "7.56.0" - tslib "^1.9.3" + "@sentry/types" "7.57.0" + "@sentry/utils" "7.57.0" + tslib "^2.4.1 || ^1.9.3" "@sentry/integrations@^7.54.0": - version "7.56.0" - resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.56.0.tgz#6fe812454fbccf00810f65667eb393b3bf298b92" - integrity sha512-0d/E/R3MW+5bQ9wcHPD0h/B2KFOpUt+wQgN1kNk7atY12auDzHKuGCjPP87D/xVyRoma3ErFqZCRqwtvCj1cfQ== + version "7.57.0" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.57.0.tgz#298085b3a2fe862cc70bc7f2143aa0fbc617322c" + integrity sha512-C3WZo5AGI2L0dj+mIjeZpdAwDEG2nDYvZbTzq5J9hVoHFdP3t7fOWBHSPkSFVtTdMaJrv+82aKnUefVCeAjxGg== dependencies: - "@sentry/types" "7.56.0" - "@sentry/utils" "7.56.0" + "@sentry/types" "7.57.0" + "@sentry/utils" "7.57.0" localforage "^1.8.1" - tslib "^1.9.3" + tslib "^2.4.1 || ^1.9.3" "@sentry/react@^7.54.0": - version "7.56.0" - resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.56.0.tgz#7e2e9363a76c7d67854bdb179142a2f7f910d476" - integrity sha512-dRnkZwspef5aEHV/eiLS/mhomFCXItylU8s78fzAn5QMTDGHmu5Pnhl5dxh/zbPUcdXqFA6GwJVucV4gzsNEJw== + version "7.57.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.57.0.tgz#cf91f0115bcd2a8306d6c8a39d8e8b53d4b21814" + integrity sha512-XGNTjIoCG3naSmCU8qObd+y+CqAB6NQkGWOp2yyBwp2inyKF2ehJvDh6bIQloBYq2TmOJDa4NfXdMrkilxaLFQ== dependencies: - "@sentry/browser" "7.56.0" - "@sentry/types" "7.56.0" - "@sentry/utils" "7.56.0" + "@sentry/browser" "7.57.0" + "@sentry/types" "7.57.0" + "@sentry/utils" "7.57.0" hoist-non-react-statics "^3.3.2" - tslib "^1.9.3" + tslib "^2.4.1 || ^1.9.3" -"@sentry/replay@7.56.0": - version "7.56.0" - resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.56.0.tgz#8a49dcb45e9ea83bf905cec0d9b42fed4b8085bd" - integrity sha512-bvjiJK1+SM/paLapuL+nEJ8CIF1bJqi0nnFyxUIi2L5L6yb2uMwfyT3IQ+kz0cXJsLdb3HN4WMphVjyiU9pFdg== +"@sentry/replay@7.57.0": + version "7.57.0" + resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.57.0.tgz#c8f7eae7b7edc9d32c3d2955b337f3b3c76dff39" + integrity sha512-pN4ryNS3J5EYbkXvR+O/+hseAJha7XDl8mPFtK0OGTHG10JzCi4tQJazblHQdpb5QBaMMPCeZ+isyfoQLDNXnw== dependencies: - "@sentry/core" "7.56.0" - "@sentry/types" "7.56.0" - "@sentry/utils" "7.56.0" + "@sentry/core" "7.57.0" + "@sentry/types" "7.57.0" + "@sentry/utils" "7.57.0" -"@sentry/types@7.56.0": - version "7.56.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.56.0.tgz#9042a099cf9e8816d081886d24b88082a5d9f87a" - integrity sha512-5WjhVOQm75ItOytOx2jTx+5yw8/qJ316+g1Di8dS9+kgIi1zniqdMcX00C2yYe3FMUgFB49PegCUYulm9Evapw== +"@sentry/types@7.57.0": + version "7.57.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.57.0.tgz#4fdb80cbd49ba034dd8d9be0c0005a016d5db3ce" + integrity sha512-D7ifoUfxuVCUyktIr5Gc+jXUbtcUMmfHdTtTbf1XCZHua5mJceK9wtl3YCg3eq/HK2Ppd52BKnTzEcS5ZKQM+w== -"@sentry/utils@7.56.0": - version "7.56.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.56.0.tgz#e60e4935d17b2197584abf6ce61b522ad055352c" - integrity sha512-wgeX7bufxc//TjjSIE+gCMm8hVId7Jzvc+f441bYrWnNZBuzPIDW2BummCcPrKzSYe5GeYZDTZGV8YZGMLGBjw== +"@sentry/utils@7.57.0": + version "7.57.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.57.0.tgz#8253c6fcf35138b4c424234b8da1596e11b98ad8" + integrity sha512-YXrkMCiNklqkXctn4mKYkrzNCf/dfVcRUQrkXjeBC+PHXbcpPyaJgInNvztR7Skl8lE3JPGPN4v5XhLxK1bUUg== dependencies: - "@sentry/types" "7.56.0" - tslib "^1.9.3" + "@sentry/types" "7.57.0" + tslib "^2.4.1 || ^1.9.3" "@sigstore/protobuf-specs@^0.1.0": version "0.1.0" @@ -3620,14 +3636,14 @@ qs "^6.10.0" telejson "^6.0.8" -"@storybook/channel-postmessage@7.0.23": - version "7.0.23" - resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-7.0.23.tgz#eff248def859a0106cb45d535eb13111b8abb2df" - integrity sha512-SfXTV55Z9U5rN1OuyR56s+PUpav3b4SgXtP67bnNsrv7dkKhBwr0DUUJogIRnjmY0Loy/hLvJ23kfmKXPWC4vQ== +"@storybook/channel-postmessage@7.0.24": + version "7.0.24" + resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-7.0.24.tgz#789bd121cf64e306737ec0f3b096ea0ac6f47bf5" + integrity sha512-QLtLXjEeTEwBN/7pB888mBaykmRU9Jy2BitvZuLJWyHHygTYm3vYZOaGR37DT+q/6Ob5GaZ0tURZmCSNDe8IIA== dependencies: - "@storybook/channels" "7.0.23" - "@storybook/client-logger" "7.0.23" - "@storybook/core-events" "7.0.23" + "@storybook/channels" "7.0.24" + "@storybook/client-logger" "7.0.24" + "@storybook/core-events" "7.0.24" "@storybook/global" "^5.0.0" qs "^6.10.0" telejson "^7.0.3" @@ -3652,10 +3668,10 @@ ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/channels@7.0.23": - version "7.0.23" - resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-7.0.23.tgz#4c57f5f43289ca21b6a713ff9c399c8abb6c868a" - integrity sha512-cCxR3Z84YQjsVMPgFTI+kDVNOlgXSDakwjkNFBznU+s2qhGW5eZt2g9YRDeVDQ6AjR4j4RrGhwddRq4lQZF2pg== +"@storybook/channels@7.0.24": + version "7.0.24" + resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-7.0.24.tgz#fcfe7a1a5599265506f07fe81d03b0585303fc15" + integrity sha512-NZVLwMhtzy6cZrNRjshFvMAD9mQTmJDNwhohodSkM/YFCDVFhmxQk9tgizVGh9MwY3CYGJ1SI96RUejGosb49Q== "@storybook/client-api@6.5.16": version "6.5.16" @@ -3691,10 +3707,10 @@ core-js "^3.8.2" global "^4.4.0" -"@storybook/client-logger@7.0.23", "@storybook/client-logger@^6.4.0 || >=6.5.0-0": - version "7.0.23" - resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-7.0.23.tgz#5db5d144d1948fd8c856195ee6a699c002046557" - integrity sha512-L287SRO8EaYOxTpryV7N/1WCL5I1IFs5Naiq3FpybhguUP7F3Si7KWvVdFmSW06K9jNj2IEQ/8zBRM8ra4ttyg== +"@storybook/client-logger@7.0.24", "@storybook/client-logger@^6.4.0 || >=6.5.0-0": + version "7.0.24" + resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-7.0.24.tgz#7be57ce1f90e65c6e9da7a88ed9ca7c5ce3c6536" + integrity sha512-4zRTb+QQ1hWaRqad/UufZNRfi2d/cf5a40My72Ct97VwjhJFE6aQ3K+hl1Xt6hh8dncDL2JK3cgziw6ElqjT0w== dependencies: "@storybook/global" "^5.0.0" @@ -3801,10 +3817,10 @@ dependencies: core-js "^3.8.2" -"@storybook/core-events@7.0.23": - version "7.0.23" - resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-7.0.23.tgz#99d36712dba8eae9e1585298dd9b97385ae13ad5" - integrity sha512-Hdt18p/qbgJc+1wY2dGcdjmlsuNXWsoLTaXrjInuvr1U0kmKmKs0VMaB0cFubnUgCmB3YQWTGnVr3q8iz9iB7g== +"@storybook/core-events@7.0.24": + version "7.0.24" + resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-7.0.24.tgz#3fa4b2b3af64a86525b4cf07f49a7410125ef810" + integrity sha512-xkf/rihCkhqMeh5EA8lVp90/mzbb2gcg6I3oeFWw2hognVcTnPXg6llhWdU4Spqd0cals7GEFmQugIILCmH8GA== "@storybook/core-server@6.5.16": version "6.5.16" @@ -3936,15 +3952,15 @@ global "^4.4.0" "@storybook/instrumenter@^6.4.0 || >=6.5.0-0": - version "7.0.23" - resolved "https://registry.yarnpkg.com/@storybook/instrumenter/-/instrumenter-7.0.23.tgz#0f7efd95cb2ec4698fc57cc012045cec42b7ef6b" - integrity sha512-CeV2se64XxccD4L6XFI3cFfEz3/Lcbrvb+T3bZZzGOXO18zH5tN3jXVfAONrz/mU69jL9mbo96hFl51UDtwcAg== + version "7.0.24" + resolved "https://registry.yarnpkg.com/@storybook/instrumenter/-/instrumenter-7.0.24.tgz#fbc81250f25b0d5f3da3a3aa9dad48cdc82642f9" + integrity sha512-XQ4Whq0rqW9eFMTtRpLxcl6bCf+KO3UZYcm+H63EDn9TstDyopmqv1fDg2tmJOpqLo143F8qLVC89rI7M/lO6w== dependencies: - "@storybook/channels" "7.0.23" - "@storybook/client-logger" "7.0.23" - "@storybook/core-events" "7.0.23" + "@storybook/channels" "7.0.24" + "@storybook/client-logger" "7.0.24" + "@storybook/core-events" "7.0.24" "@storybook/global" "^5.0.0" - "@storybook/preview-api" "7.0.23" + "@storybook/preview-api" "7.0.24" "@storybook/manager-webpack4@6.5.16": version "6.5.16" @@ -4060,18 +4076,18 @@ dependencies: core-js "^3.8.2" -"@storybook/preview-api@7.0.23": - version "7.0.23" - resolved "https://registry.yarnpkg.com/@storybook/preview-api/-/preview-api-7.0.23.tgz#6f4d98a54c7367341e086a1818866e2e1e97faea" - integrity sha512-kXhDX6gVjQu4Lx4SnCW5Yt5W/TbQofp9SL0paB1ywsJ15xSAPU5KVILe9OWAOba2YUnk7sHux/xDX/gH5RCpVw== +"@storybook/preview-api@7.0.24": + version "7.0.24" + resolved "https://registry.yarnpkg.com/@storybook/preview-api/-/preview-api-7.0.24.tgz#93634c060aa43bb10fb233f28ae83b7d74b98aad" + integrity sha512-psycU07tuB5nyJvfAJiDN/9e8cjOdJ+5lrCSYC3vPzH86LxADDIN0/8xFb1CaQWcXZsADEFJGpHKWbRhjym5ew== dependencies: - "@storybook/channel-postmessage" "7.0.23" - "@storybook/channels" "7.0.23" - "@storybook/client-logger" "7.0.23" - "@storybook/core-events" "7.0.23" + "@storybook/channel-postmessage" "7.0.24" + "@storybook/channels" "7.0.24" + "@storybook/client-logger" "7.0.24" + "@storybook/core-events" "7.0.24" "@storybook/csf" "^0.1.0" "@storybook/global" "^5.0.0" - "@storybook/types" "7.0.23" + "@storybook/types" "7.0.24" "@types/qs" "^6.9.5" dequal "^2.0.2" lodash "^4.17.21" @@ -4252,15 +4268,15 @@ memoizerific "^1.11.3" regenerator-runtime "^0.13.7" -"@storybook/types@7.0.23": - version "7.0.23" - resolved "https://registry.yarnpkg.com/@storybook/types/-/types-7.0.23.tgz#08ae3223e97ed1baa9aa715745a05ae83311425c" - integrity sha512-ziszL3OfhTT5PHE7kiQjWWx3Lw3qro8eLX+56dXDNgmft5LS66yEANcaA7OzxLnEgdyWSxJqgrVo6r0JwHp2Eg== +"@storybook/types@7.0.24": + version "7.0.24" + resolved "https://registry.yarnpkg.com/@storybook/types/-/types-7.0.24.tgz#22b2f6658f9a091ff584e1a0643ee1ea9a54ed39" + integrity sha512-SZh/XBHP1TT5bmEk0W52nT0v6fUnYwmZVls3da5noutdgOAiwL7TANtl41XrNjG+UDr8x0OE3PVVJi+LhwUaNA== dependencies: - "@storybook/channels" "7.0.23" + "@storybook/channels" "7.0.24" "@types/babel__core" "^7.0.0" "@types/express" "^4.7.0" - file-system-cache "^2.0.0" + file-system-cache "2.3.0" "@storybook/ui@6.5.16": version "6.5.16" @@ -5001,9 +5017,9 @@ form-data "^3.0.0" "@types/node@*", "@types/node@>=13.7.0": - version "20.3.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.3.1.tgz#e8a83f1aa8b649377bb1fb5d7bac5cb90e784dfe" - integrity sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg== + version "20.3.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.3.2.tgz#fa6a90f2600e052a03c18b8cb3fd83dd4e599898" + integrity sha512-vOBLVQeCQfIcF/2Y7eKFTqrMnizK5lRNQ7ykML/5RuwVXVWxYkgwS7xbt4B6fKCUPgbSL5FSsjHQpaGQP/dQmw== "@types/node@^13.7.0": version "13.13.52" @@ -5011,9 +5027,9 @@ integrity sha512-s3nugnZumCC//n4moGGe6tkNMyYEdaDBitVjwPxXmR5lnMG5dHePinH2EdxkG3Rh1ghFHHixAG4NJhpJW1rthQ== "@types/node@^14.0.10 || ^16.0.0", "@types/node@^14.14.20 || ^16.0.0", "@types/node@^16.7.13": - version "16.18.36" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.36.tgz#0db5d7efc4760d36d0d1d22c85d1a53accd5dc27" - integrity sha512-8egDX8dE50XyXWH6C6PRCNkTP106DuUrvdrednFouDSmCi7IOvrqr0frznfZaHifHH/3aq/7a7v9N4wdXMqhBQ== + version "16.18.37" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.37.tgz#a1f8728e4dc30163deb41e9b7aba65d0c2d4eda1" + integrity sha512-ql+4dw4PlPFBP495k8JzUX/oMNRI2Ei4PrMHgj8oT4VhGlYUzF4EYr0qk2fW+XBVGIrq8Zzk13m4cvyXZuv4pA== "@types/normalize-package-data@^2.4.0": version "2.4.1" @@ -5113,9 +5129,9 @@ "@types/react" "*" "@types/react@*", "@types/react@^18.0.26": - version "18.2.13" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.13.tgz#a98c09bde8b18f80021935b11d2d29ef5f4dcb2f" - integrity sha512-vJ+zElvi/Zn9cVXB5slX2xL8PZodPCwPRDpittQdw43JR2AJ5k3vKdgJJyneV/cYgIbLQUwXa9JVDvUZXGba+Q== + version "18.2.14" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.14.tgz#fa7a6fecf1ce35ca94e74874f70c56ce88f7a127" + integrity sha512-A0zjq+QN/O0Kpe30hA1GidzyFjatVvrpIvWLxD+xv67Vt91TWWgco9IvrJBkeyHm1trGaFS/FSGqPlhyeZRm0g== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -5300,14 +5316,14 @@ integrity sha512-3NoqvZC2W5gAC5DZbTpCeJ251vGQmgcWIHQJGq2J240HY6ErQ9aWKkwfoKJlHLx+A83WPNTZ9+3cd2ILxbvr1w== "@typescript-eslint/eslint-plugin@^5.13.0", "@typescript-eslint/eslint-plugin@^5.7.0": - version "5.60.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.60.0.tgz#2f4bea6a3718bed2ba52905358d0f45cd3620d31" - integrity sha512-78B+anHLF1TI8Jn/cD0Q00TBYdMgjdOn980JfAVa9yw5sop8nyTfVOQAv6LWywkOGLclDBtv5z3oxN4w7jxyNg== + version "5.60.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.60.1.tgz#81382d6ecb92b8dda70e91f9035611cb2fecd1c3" + integrity sha512-KSWsVvsJsLJv3c4e73y/Bzt7OpqMCADUO846bHcuWYSYM19bldbAeDv7dYyV0jwkbMfJ2XdlzwjhXtuD7OY6bw== dependencies: "@eslint-community/regexpp" "^4.4.0" - "@typescript-eslint/scope-manager" "5.60.0" - "@typescript-eslint/type-utils" "5.60.0" - "@typescript-eslint/utils" "5.60.0" + "@typescript-eslint/scope-manager" "5.60.1" + "@typescript-eslint/type-utils" "5.60.1" + "@typescript-eslint/utils" "5.60.1" debug "^4.3.4" grapheme-splitter "^1.0.4" ignore "^5.2.0" @@ -5316,78 +5332,78 @@ tsutils "^3.21.0" "@typescript-eslint/experimental-utils@^5.3.0": - version "5.60.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.60.0.tgz#48ffa47238592397c3d857fe1403eed3b1d5e604" - integrity sha512-ovid3u7CNBrr0Ct35LUPkNYH4e+z4Kc6dPfSG99oMmH9SfoEoefq09uSnJI4mUb/UM7a/peVM03G+MzLxrD16g== + version "5.60.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.60.1.tgz#d783bb63b9183541019a945eda6a9d96b096d985" + integrity sha512-TXUdLxv2t8181nh5yLXl/Gr/zKj1ZofQ7m+ZdmG2+El0TYOHCvlZfc35D4nturemC3RUnf3KmLuFp3bVBjkG5w== dependencies: - "@typescript-eslint/utils" "5.60.0" + "@typescript-eslint/utils" "5.60.1" "@typescript-eslint/parser@^5.13.0", "@typescript-eslint/parser@^5.7.0": - version "5.60.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.60.0.tgz#08f4daf5fc6548784513524f4f2f359cebb4068a" - integrity sha512-jBONcBsDJ9UoTWrARkRRCgDz6wUggmH5RpQVlt7BimSwaTkTjwypGzKORXbR4/2Hqjk9hgwlon2rVQAjWNpkyQ== + version "5.60.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.60.1.tgz#0f2f58209c0862a73e3d5a56099abfdfa21d0fd3" + integrity sha512-pHWlc3alg2oSMGwsU/Is8hbm3XFbcrb6P5wIxcQW9NsYBfnrubl/GhVVD/Jm/t8HXhA2WncoIRfBtnCgRGV96Q== dependencies: - "@typescript-eslint/scope-manager" "5.60.0" - "@typescript-eslint/types" "5.60.0" - "@typescript-eslint/typescript-estree" "5.60.0" + "@typescript-eslint/scope-manager" "5.60.1" + "@typescript-eslint/types" "5.60.1" + "@typescript-eslint/typescript-estree" "5.60.1" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.60.0": - version "5.60.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.60.0.tgz#ae511967b4bd84f1d5e179bb2c82857334941c1c" - integrity sha512-hakuzcxPwXi2ihf9WQu1BbRj1e/Pd8ZZwVTG9kfbxAMZstKz8/9OoexIwnmLzShtsdap5U/CoQGRCWlSuPbYxQ== +"@typescript-eslint/scope-manager@5.60.1": + version "5.60.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.60.1.tgz#35abdb47f500c68c08f2f2b4f22c7c79472854bb" + integrity sha512-Dn/LnN7fEoRD+KspEOV0xDMynEmR3iSHdgNsarlXNLGGtcUok8L4N71dxUgt3YvlO8si7E+BJ5Fe3wb5yUw7DQ== dependencies: - "@typescript-eslint/types" "5.60.0" - "@typescript-eslint/visitor-keys" "5.60.0" + "@typescript-eslint/types" "5.60.1" + "@typescript-eslint/visitor-keys" "5.60.1" -"@typescript-eslint/type-utils@5.60.0": - version "5.60.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.60.0.tgz#69b09087eb12d7513d5b07747e7d47f5533aa228" - integrity sha512-X7NsRQddORMYRFH7FWo6sA9Y/zbJ8s1x1RIAtnlj6YprbToTiQnM6vxcMu7iYhdunmoC0rUWlca13D5DVHkK2g== +"@typescript-eslint/type-utils@5.60.1": + version "5.60.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.60.1.tgz#17770540e98d65ab4730c7aac618003f702893f4" + integrity sha512-vN6UztYqIu05nu7JqwQGzQKUJctzs3/Hg7E2Yx8rz9J+4LgtIDFWjjl1gm3pycH0P3mHAcEUBd23LVgfrsTR8A== dependencies: - "@typescript-eslint/typescript-estree" "5.60.0" - "@typescript-eslint/utils" "5.60.0" + "@typescript-eslint/typescript-estree" "5.60.1" + "@typescript-eslint/utils" "5.60.1" debug "^4.3.4" tsutils "^3.21.0" -"@typescript-eslint/types@5.60.0": - version "5.60.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.60.0.tgz#3179962b28b4790de70e2344465ec97582ce2558" - integrity sha512-ascOuoCpNZBccFVNJRSC6rPq4EmJ2NkuoKnd6LDNyAQmdDnziAtxbCGWCbefG1CNzmDvd05zO36AmB7H8RzKPA== +"@typescript-eslint/types@5.60.1": + version "5.60.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.60.1.tgz#a17473910f6b8d388ea83c9d7051af89c4eb7561" + integrity sha512-zDcDx5fccU8BA0IDZc71bAtYIcG9PowaOwaD8rjYbqwK7dpe/UMQl3inJ4UtUK42nOCT41jTSCwg76E62JpMcg== -"@typescript-eslint/typescript-estree@5.60.0": - version "5.60.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.60.0.tgz#4ddf1a81d32a850de66642d9b3ad1e3254fb1600" - integrity sha512-R43thAuwarC99SnvrBmh26tc7F6sPa2B3evkXp/8q954kYL6Ro56AwASYWtEEi+4j09GbiNAHqYwNNZuNlARGQ== +"@typescript-eslint/typescript-estree@5.60.1": + version "5.60.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.60.1.tgz#8c71824b7165b64d5ebd7aa42968899525959834" + integrity sha512-hkX70J9+2M2ZT6fhti5Q2FoU9zb+GeZK2SLP1WZlvUDqdMbEKhexZODD1WodNRyO8eS+4nScvT0dts8IdaBzfw== dependencies: - "@typescript-eslint/types" "5.60.0" - "@typescript-eslint/visitor-keys" "5.60.0" + "@typescript-eslint/types" "5.60.1" + "@typescript-eslint/visitor-keys" "5.60.1" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@5.60.0", "@typescript-eslint/utils@^5.10.0": - version "5.60.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.60.0.tgz#4667c5aece82f9d4f24a667602f0f300864b554c" - integrity sha512-ba51uMqDtfLQ5+xHtwlO84vkdjrqNzOnqrnwbMHMRY8Tqeme8C2Q8Fc7LajfGR+e3/4LoYiWXUM6BpIIbHJ4hQ== +"@typescript-eslint/utils@5.60.1", "@typescript-eslint/utils@^5.10.0": + version "5.60.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.60.1.tgz#6861ebedbefba1ac85482d2bdef6f2ff1eb65b80" + integrity sha512-tiJ7FFdFQOWssFa3gqb94Ilexyw0JVxj6vBzaSpfN/8IhoKkDuSAenUKvsSHw2A/TMpJb26izIszTXaqygkvpQ== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@types/json-schema" "^7.0.9" "@types/semver" "^7.3.12" - "@typescript-eslint/scope-manager" "5.60.0" - "@typescript-eslint/types" "5.60.0" - "@typescript-eslint/typescript-estree" "5.60.0" + "@typescript-eslint/scope-manager" "5.60.1" + "@typescript-eslint/types" "5.60.1" + "@typescript-eslint/typescript-estree" "5.60.1" eslint-scope "^5.1.1" semver "^7.3.7" -"@typescript-eslint/visitor-keys@5.60.0": - version "5.60.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.60.0.tgz#b48b29da3f5f31dd1656281727004589d2722a66" - integrity sha512-wm9Uz71SbCyhUKgcaPRauBdTegUyY/ZWl8gLwD/i/ybJqscrrdVSFImpvUz16BLPChIeKBK5Fa9s6KDQjsjyWw== +"@typescript-eslint/visitor-keys@5.60.1": + version "5.60.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.60.1.tgz#19a877358bf96318ec35d90bfe6bd1445cce9434" + integrity sha512-xEYIxKcultP6E/RMKqube11pGjXH1DCo60mQoWhVYyKfLkwbIVVjYxmOenNMxILx0TjCujPTjjnTIVzm09TXIw== dependencies: - "@typescript-eslint/types" "5.60.0" + "@typescript-eslint/types" "5.60.1" eslint-visitor-keys "^3.3.0" "@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": @@ -5689,9 +5705,9 @@ integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== "@yarnpkg/parsers@^3.0.0-rc.18": - version "3.0.0-rc.46" - resolved "https://registry.yarnpkg.com/@yarnpkg/parsers/-/parsers-3.0.0-rc.46.tgz#03f8363111efc0ea670e53b0282cd3ef62de4e01" - integrity sha512-aiATs7pSutzda/rq8fnuPwTglyVwjM22bNnK2ZgjrpAjQHSSl3lztd2f9evst1W/qnC58DRz7T7QndUDumAR4Q== + version "3.0.0-rc.47" + resolved "https://registry.yarnpkg.com/@yarnpkg/parsers/-/parsers-3.0.0-rc.47.tgz#2b67a2f5098cafcd0a1ce7f2e9174794d639046e" + integrity sha512-ri/QnMiMobEgRUBF1fPcxH1ICa9jsG8y4tDNRAuk6zPdCPkSAzACKaXjmDiAZFiwKxK4hTVj0E8nklgWFeTLng== dependencies: js-yaml "^3.10.0" tslib "^2.4.0" @@ -6045,9 +6061,9 @@ aria-query@5.1.3: deep-equal "^2.0.5" aria-query@^5.0.0, aria-query@^5.1.3: - version "5.2.1" - resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.2.1.tgz#bc285d9d654d1df121bcd0c134880d415ca67c15" - integrity sha512-7uFg4b+lETFgdaJyETnILsXgnnzVnkHcgRbwbPwevm5x/LmUlt3MjczMRe1zg824iBgXZNRPTBftNYyRSKLp2g== + version "5.3.0" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e" + integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A== dependencies: dequal "^2.0.3" @@ -6099,7 +6115,7 @@ array-ify@^1.0.0: resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" integrity sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng== -array-includes@^3.0.3, array-includes@^3.1.5, array-includes@^3.1.6: +array-includes@^3.0.3, array-includes@^3.1.6: version "3.1.6" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== @@ -6122,11 +6138,6 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array-union@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-3.0.1.tgz#da52630d327f8b88cfbfb57728e2af5cd9b6b975" - integrity sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw== - array-uniq@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" @@ -7086,9 +7097,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001503: - version "1.0.30001507" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001507.tgz#fae53f6286e7564783eadea9b447819410a59534" - integrity sha512-SFpUDoSLCaE5XYL2jfqe9ova/pbQHEmbheDf5r4diNwbAgR3qxM9NQtfsiSscjqoya5K7kFcHPUQ+VsUkIJR4A== + version "1.0.30001509" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001509.tgz#2b7ad5265392d6d2de25cd8776d1ab3899570d14" + integrity sha512-2uDDk+TRiTX5hMcUYT/7CSyzMZxjfGu0vAUjS2g0LSD8UoXOv0LtpH4LxGMemsiPq6LCVIUjNwVM0erkOkGCDA== capture-exit@^2.0.0: version "2.0.0" @@ -7807,18 +7818,6 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== -copy-webpack-plugin@^10.2.4: - version "10.2.4" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-10.2.4.tgz#6c854be3fdaae22025da34b9112ccf81c63308fe" - integrity sha512-xFVltahqlsRcyyJqQbDY6EYTtyQZF9rf+JPjwHObLdPFMEISqkFkr7mFoVOC6BfYS/dNThyoQKvziugm+OnwBg== - dependencies: - fast-glob "^3.2.7" - glob-parent "^6.0.1" - globby "^12.0.2" - normalize-path "^3.0.0" - schema-utils "^4.0.0" - serialize-javascript "^6.0.0" - core-js-compat@^3.30.1, core-js-compat@^3.30.2, core-js-compat@^3.8.1: version "3.31.0" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.31.0.tgz#4030847c0766cc0e803dcdfb30055d7ef2064bf1" @@ -8913,9 +8912,9 @@ ejs@^3.1.7: jake "^10.8.5" electron-to-chromium@^1.4.431: - version "1.4.439" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.439.tgz#d0748e8128c18f92354d3412dfb2104c3fb90e8f" - integrity sha512-BHpErPSNhb9FB25+OwQP6mCAf3ZXfGbmuvc4LzBNVJwpCcXQJm++LerimocYRG9FRxUVRKZqaB7d0+pImSTPSg== + version "1.4.445" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.445.tgz#058d2c5f3a2981ab1a37440f5a5e42d15672aa6d" + integrity sha512-++DB+9VK8SBJwC+X1zlMfJ1tMA3F0ipi39GdEp+x3cV2TyBihqAgad8cNMWtLDEkbH39nlDQP7PfGrDr3Dr7HA== elliptic@^6.5.3, elliptic@^6.5.4: version "6.5.4" @@ -9018,9 +9017,9 @@ env-paths@^2.2.0: integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== envinfo@^7.7.3, envinfo@^7.7.4: - version "7.9.0" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.9.0.tgz#47594a13081be0d9be6e513534e8c58dbb26c7a1" - integrity sha512-RODB4txU+xImYDemN5DqaKC0CHk05XSVkOX4pq0hK26Qx+1LChkuOyUDlGEjYb3ACr0n9qBhFjg37hQuJvpkRQ== + version "7.10.0" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.10.0.tgz#55146e3909cc5fe63c22da63fb15b05aeac35b13" + integrity sha512-ZtUjZO6l5mwTHvc1L9+1q5p/R3wTopcfqMW8r5t8SJSKqeVI/LtajORwRFEKpEFuekjD0VBjwu1HMxL4UalIRw== err-code@^2.0.2: version "2.0.3" @@ -9854,7 +9853,7 @@ fast-glob@^2.2.6: merge2 "^1.2.3" micromatch "^3.1.10" -fast-glob@^3.2.7, fast-glob@^3.2.9: +fast-glob@^3.2.9: version "3.2.12" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== @@ -9972,6 +9971,14 @@ file-loader@^6.2.0: loader-utils "^2.0.0" schema-utils "^3.0.0" +file-system-cache@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/file-system-cache/-/file-system-cache-2.3.0.tgz#201feaf4c8cd97b9d0d608e96861bb6005f46fe6" + integrity sha512-l4DMNdsIPsVnKrgEXbJwDJsA5mB8rGwHYERMgqQx/xAUtChPJMre1bXBzDEqqVbWv9AIbFezXMxeEkZDSrXUOQ== + dependencies: + fs-extra "11.1.1" + ramda "0.29.0" + file-system-cache@^1.0.5: version "1.1.0" resolved "https://registry.yarnpkg.com/file-system-cache/-/file-system-cache-1.1.0.tgz#984de17b976b75a77a27e08d6828137c1aa80fa1" @@ -9980,14 +9987,6 @@ file-system-cache@^1.0.5: fs-extra "^10.1.0" ramda "^0.28.0" -file-system-cache@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/file-system-cache/-/file-system-cache-2.3.0.tgz#201feaf4c8cd97b9d0d608e96861bb6005f46fe6" - integrity sha512-l4DMNdsIPsVnKrgEXbJwDJsA5mB8rGwHYERMgqQx/xAUtChPJMre1bXBzDEqqVbWv9AIbFezXMxeEkZDSrXUOQ== - dependencies: - fs-extra "11.1.1" - ramda "0.29.0" - file-uri-to-path@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" @@ -10552,7 +10551,7 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" -glob-parent@^6.0.1, glob-parent@^6.0.2: +glob-parent@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== @@ -10601,15 +10600,15 @@ glob@7.2.0: path-is-absolute "^1.0.0" glob@^10.2.2: - version "10.3.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.0.tgz#763d02a894f3cdfc521b10bbbbc8e0309e750cce" - integrity sha512-AQ1/SB9HH0yCx1jXAT4vmCbTOPe5RQ+kCurjbel5xSCGhebumUv+GJZfa1rEqor3XIViqwSEmlkZCQD43RWrBg== + version "10.3.1" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.1.tgz#9789cb1b994515bedb811a6deca735b5c37d2bf4" + integrity sha512-9BKYcEeIs7QwlCYs+Y3GBvqAMISufUS0i2ELd11zpZjxI5V9iyRj0HgzB5/cLf2NY4vcYBTYzJ7GIui7j/4DOw== dependencies: foreground-child "^3.1.0" jackspeak "^2.0.3" minimatch "^9.0.1" minipass "^5.0.0 || ^6.0.2" - path-scurry "^1.7.0" + path-scurry "^1.10.0" glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.2.3" @@ -10683,18 +10682,6 @@ globby@11.1.0, globby@^11.0.1, globby@^11.0.2, globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" -globby@^12.0.2: - version "12.2.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-12.2.0.tgz#2ab8046b4fba4ff6eede835b29f678f90e3d3c22" - integrity sha512-wiSuFQLZ+urS9x2gGPl1H5drc5twabmm4m2gTR27XDFyjUHJUNsS8o/2aKyIF6IoBaR630atdher0XJ5g6OMmA== - dependencies: - array-union "^3.0.1" - dir-glob "^3.0.1" - fast-glob "^3.2.7" - ignore "^5.1.9" - merge2 "^1.4.1" - slash "^4.0.0" - globby@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" @@ -10974,11 +10961,6 @@ he@1.2.0, he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== -hello-wasm-pack@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/hello-wasm-pack/-/hello-wasm-pack-0.1.0.tgz#482a2e3371828056ac35f5b5fec76c0b99dcd530" - integrity sha512-3hx0GDkDLf/a9ThCMV2qG4mwza8N/MCtm8aeFFc/cdBCL2zMJ1kW1wjNl7xPqD1lz8Yl5+uhnc/cpui4dLwz/w== - hex-rgb@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/hex-rgb/-/hex-rgb-4.3.0.tgz#af5e974e83bb2fefe44d55182b004ec818c07776" @@ -11051,9 +11033,9 @@ html-encoding-sniffer@^2.0.1: whatwg-encoding "^1.0.5" html-entities@^2.1.0, html-entities@^2.3.2: - version "2.3.6" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.6.tgz#966391d58e5737c77bca4025e31721b496ab7454" - integrity sha512-9o0+dcpIw2/HxkNuYKxSJUF/MMRZQECK4GnF+oQOmJ83yCVHTWgCH5aOXxK5bozNRmM8wtgryjHD3uloPBDEGw== + version "2.4.0" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.4.0.tgz#edd0cee70402584c8c76cc2c0556db09d1f45061" + integrity sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ== html-escaper@^2.0.0: version "2.0.2" @@ -11303,7 +11285,7 @@ ignore@^4.0.3, ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.0.4, ignore@^5.1.9, ignore@^5.2.0: +ignore@^5.0.4, ignore@^5.2.0: version "5.2.4" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== @@ -12916,12 +12898,14 @@ jss@10.10.0, jss@^10.10.0: tiny-warning "^1.0.2" "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.3: - version "3.3.3" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz#76b3e6e6cece5c69d49a5792c3d01bd1a0cdc7ea" - integrity sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw== + version "3.3.4" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.4.tgz#b896535fed5b867650acce5a9bd4135ffc7b3bf9" + integrity sha512-fX2TVdCViod6HwKEtSWGHs57oFhVfCMwieb9PuRDgjDPh5XeqJiHFFFJCHxU5cnTc3Bu/GRL+kPiFmw8XWOfKw== dependencies: - array-includes "^3.1.5" - object.assign "^4.1.3" + array-includes "^3.1.6" + array.prototype.flat "^1.3.1" + object.assign "^4.1.4" + object.values "^1.1.6" junk@^3.1.0: version "3.1.0" @@ -13384,10 +13368,10 @@ lru-cache@^7.4.4, lru-cache@^7.5.1, lru-cache@^7.7.1: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== -lru-cache@^9.1.1: - version "9.1.2" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-9.1.2.tgz#255fdbc14b75589d6d0e73644ca167a8db506835" - integrity sha512-ERJq3FOzJTxBbFjZ7iDs+NiK4VI9Wz+RdrrAB8dio1oV+YvdPzUEE4QNiT2VD51DkIbCYRUUzCRkssXCHqSnKQ== +"lru-cache@^9.1.1 || ^10.0.0": + version "10.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.0.tgz#b9e2a6a72a129d81ab317202d93c7691df727e61" + integrity sha512-svTf/fzsKHffP42sujkO/Rjs37BCIsQVRCeNYIm9WN8rgT7ffoUnRtZCqU+6BqcSBdv8gwJeTz8knJpgACeQMw== lunr@^2.3.9: version "2.3.9" @@ -13724,9 +13708,9 @@ mem@^8.1.1: mimic-fn "^3.1.0" memfs@^3.1.2, memfs@^3.2.2, memfs@^3.4.1, memfs@^3.4.3: - version "3.5.3" - resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.5.3.tgz#d9b40fe4f8d5788c5f895bda804cd0d9eeee9f3b" - integrity sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw== + version "3.6.0" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.6.0.tgz#d7a2110f86f79dd950a8b6df6d57bc984aa185f6" + integrity sha512-EGowvkkgbMcIChjMTMkESFDbZeSh8xZ7kNSF0hAiAN4Jh6jgHCRS0Ga/+C8y6Au+oqpezRHCfPsmJ2+DwAgiwQ== dependencies: fs-monkey "^1.0.4" @@ -14248,9 +14232,9 @@ minimatch@^8.0.2: brace-expansion "^2.0.1" minimatch@^9.0.0, minimatch@^9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.1.tgz#8a555f541cf976c622daf078bb28f29fb927c253" - integrity sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w== + version "9.0.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.2.tgz#397e387fff22f6795844d00badc903a3d5de7057" + integrity sha512-PZOT9g5v2ojiTL7r1xF6plNHLtOeTpSlDI007As2NlA2aYBMfVom17yqa6QzhmDP8QOhn7LjHTg7DFCVSSa6yg== dependencies: brace-expansion "^2.0.1" @@ -15104,7 +15088,7 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" -object.assign@^4.1.2, object.assign@^4.1.3, object.assign@^4.1.4: +object.assign@^4.1.2, object.assign@^4.1.4: version "4.1.4" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== @@ -15233,16 +15217,16 @@ optionator@^0.8.1: word-wrap "~1.2.3" optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + version "0.9.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" - word-wrap "^1.2.3" ora@^5.4.1: version "5.4.1" @@ -15682,12 +15666,12 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.6.1, path-scurry@^1.7.0: - version "1.9.2" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.9.2.tgz#90f9d296ac5e37e608028e28a447b11d385b3f63" - integrity sha512-qSDLy2aGFPm8i4rsbHd4MNyTcrzHFsLQykrtbuGRknZZCBBVXSv2tSCDN2Cg6Rt/GFRw8GoW9y9Ecw5rIPG1sg== +path-scurry@^1.10.0, path-scurry@^1.6.1: + version "1.10.0" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.0.tgz#0ffbd4c1f7de9600f98a1405507d9f9acb438ab3" + integrity sha512-tZFEaRQbMLjwrsmidsGJ6wDMv0iazJWk6SfIKnY4Xru8auXgmJkOBa5DUbYFcFD2Rzk2+KDlIiF0GVXNCbgC7g== dependencies: - lru-cache "^9.1.1" + lru-cache "^9.1.1 || ^10.0.0" minipass "^5.0.0 || ^6.0.2" path-to-regexp@0.1.7: @@ -16659,9 +16643,9 @@ react-google-charts@^3.0.15: react-load-script "^0.0.6" react-hook-form@^7.14.2: - version "7.45.0" - resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.45.0.tgz#df2bbc8cee598855a63ba446e0bb06f7c8120ccf" - integrity sha512-AbHeZ4ad+0dEIknSW9dBgIwcvRDfZ1O97sgj75WaMdOX0eg8TBiUf9wxzVkIjZbk76BBIE9lmFOzyD4PN80ZQg== + version "7.45.1" + resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.45.1.tgz#e352c7f4dbc7540f0756abbb4dcfd1122fecc9bb" + integrity sha512-6dWoFJwycbuFfw/iKMcl+RdAOAOHDiF11KWYhNDRN/OkUt+Di5qsZHwA0OwsVnu9y135gkHpTw9DJA+WzCeR9w== react-identicons@^1.2.5: version "1.2.5" @@ -16751,19 +16735,19 @@ react-resize-detector@^8.0.4: lodash "^4.17.21" react-router-dom@6, react-router-dom@^6.7.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.13.0.tgz#6651f456bb2af42ef14f6880123b1f575539e81f" - integrity sha512-6Nqoqd7fgwxxVGdbiMHTpDHCYPq62d7Wk1Of7B82vH7ZPwwsRaIa22zRZKPPg413R5REVNiyuQPKDG1bubcOFA== + version "6.14.0" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.14.0.tgz#7ce6c3f73549e4d40216ba150253d3bf30812b33" + integrity sha512-YEwlApKwzMMMbGbhh+Q7MsloTldcwMgHxUY/1g0uA62+B1hZo2jsybCWIDCL8zvIDB1FA0pBKY9chHbZHt+2dQ== dependencies: - "@remix-run/router" "1.6.3" - react-router "6.13.0" + "@remix-run/router" "1.7.0" + react-router "6.14.0" -react-router@6.13.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.13.0.tgz#7e4427a271dae0cafbdb88c56ccbd9b1434ee93f" - integrity sha512-Si6KnfEnJw7gUQkNa70dlpI1bul46FuSxX5t5WwlUBxE25DAz2BjVkwaK8Y2s242bQrZPXCpmwLPtIO5pv4tXg== +react-router@6.14.0: + version "6.14.0" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.14.0.tgz#1c3e8e922d934d43a253fd862c72c82167c0a7f1" + integrity sha512-OD+vkrcGbvlwkspUFDgMzsu1RXwdjNh83YgG/28lBnDzgslhCgxIqoExLlxsfTpIygp7fc+Hd3esloNwzkm2xA== dependencies: - "@remix-run/router" "1.6.3" + "@remix-run/router" "1.7.0" react-simple-maps@^2.3.0: version "2.3.0" @@ -16784,9 +16768,9 @@ react-smooth@^2.0.2: react-transition-group "2.9.0" react-tooltip@*: - version "5.15.0" - resolved "https://registry.yarnpkg.com/react-tooltip/-/react-tooltip-5.15.0.tgz#54a1fdbd43b5ce90733c7495bc8b575e9c88f58e" - integrity sha512-OiH870zteP4T5B/J7cUGz37aY8C0Cny/i1qcLXevL+wZlW09mfjdcQ6FKP9OMMsRlszRwieOqAPT9l8rWz+BtA== + version "5.16.1" + resolved "https://registry.yarnpkg.com/react-tooltip/-/react-tooltip-5.16.1.tgz#dafb42170c50d93eaa06e26581ba8e6f7ceb2c48" + integrity sha512-z3IKJppX4llW8wQLQB3o5qUutVul79HVXI+Ncjf/5FMHbniCYPnxS1oCLpOhOEG9lV2QZRrQe9+l/pLEPOrrXA== dependencies: "@floating-ui/dom" "^1.0.0" classnames "^2.3.0" @@ -16965,9 +16949,9 @@ readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stre util-deprecate "^1.0.1" readable-stream@^4.1.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.4.0.tgz#55ce132d60a988c460d75c631e9ccf6a7229b468" - integrity sha512-kDMOq0qLtxV9f/SQv522h8cxZBqNZXuXNyjyezmfAAuribMyVXziljpQ/uQhfE1XLg2/TLTW2DsnoE4VAi/krg== + version "4.4.1" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.4.1.tgz#fa0f0878c3bc0c12b6a82e4e58c5dc160e1faaa2" + integrity sha512-llAHX9QC25bz5RPIoTeJxPaA/hgryaldValRhVZ2fK9bzbmFiscpz8fw6iBTvJfAk1w4FC1KXQme/nO7fbKyKg== dependencies: abort-controller "^3.0.0" buffer "^6.0.3" @@ -17416,9 +17400,9 @@ rollup-plugin-web-worker-loader@^1.6.1: integrity sha512-4QywQSz1NXFHKdyiou16mH3ijpcfLtLGOrAqvAqu1Gx+P8+zj+3gwC2BSL/VW1d+LW4nIHC8F7d7OXhs9UdR2A== rollup@^3.17.2, rollup@^3.2.1, rollup@^3.9.1: - version "3.25.1" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.25.1.tgz#9fff79d22ff1a904b2b595a2fb9bc3793cb987d8" - integrity sha512-tywOR+rwIt5m2ZAWSe5AIJcTat8vGlnPFAv15ycCrw33t6iFsXZ6mzHVFh2psSjxQPmI+xgzMZZizUAukBI4aQ== + version "3.25.3" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.25.3.tgz#f9a8986f0f244bcfde2208da91ba46b8fd252551" + integrity sha512-ZT279hx8gszBj9uy5FfhoG4bZx8c+0A1sbqtr7Q3KNWIizpTdDEPZbV2xcbvHsnFp4MavCQYZyzApJ+virB8Yw== optionalDependencies: fsevents "~2.3.2" @@ -17903,11 +17887,6 @@ slash@^2.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== -slash@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" - integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== - slice-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" @@ -18728,9 +18707,9 @@ terser@^4.1.2, terser@^4.6.3: source-map-support "~0.5.12" terser@^5.10.0, terser@^5.15.1, terser@^5.16.8, terser@^5.3.4: - version "5.18.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.18.1.tgz#6d8642508ae9fb7b48768e48f16d675c89a78460" - integrity sha512-j1n0Ao919h/Ai5r43VAnfV/7azUYW43GPxK7qSATzrsERfW7+y2QW9Cp9ufnRF5CQUWbnLSo7UJokSWCqg4tsQ== + version "5.18.2" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.18.2.tgz#ff3072a0faf21ffd38f99acc9a0ddf7b5f07b948" + integrity sha512-Ah19JS86ypbJzTzvUCX7KOsEIhDaRONungA4aYBjEP3JZRf4ocuDzTg4QWZnPn9DEMiMYGJPiSOy7aykoCc70w== dependencies: "@jridgewell/source-map" "^0.3.3" acorn "^8.8.2" @@ -18976,9 +18955,9 @@ ts-jest@^27.0.5: yargs-parser "20.x" ts-loader@^9.4.2: - version "9.4.3" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.4.3.tgz#55cfa7c28dd82a2de968ae45c3adb75fb888b27e" - integrity sha512-n3hBnm6ozJYzwiwt5YRiJZkzktftRpMiBApHaJPoWLA+qetQBAXkHqCLM6nwSdRDimqVtA5ocIkcTRLMTt7yzA== + version "9.4.4" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.4.4.tgz#6ceaf4d58dcc6979f84125335904920884b7cee4" + integrity sha512-MLukxDHBl8OJ5Dk3y69IsKVFRA/6MwzEqBgh+OXMPB/OD01KQuWPFd1WAQP8a5PeSCAxfnkhiuWqfmFJzJQt9w== dependencies: chalk "^4.1.0" enhanced-resolve "^5.0.0" @@ -19070,10 +19049,10 @@ tslib@^1.8.1, tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0: - version "2.5.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.3.tgz#24944ba2d990940e6e982c4bea147aba80209913" - integrity sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w== +tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0, "tslib@^2.4.1 || ^1.9.3": + version "2.6.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.0.tgz#b295854684dbda164e181d259a22cd779dcd7bc3" + integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA== tsutils@^3.21.0: version "3.21.0" @@ -19878,7 +19857,7 @@ webidl-conversions@^6.1.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== -webpack-cli@^4.8.0, webpack-cli@^4.9.2: +webpack-cli@^4.8.0: version "4.10.0" resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.10.0.tgz#37c1d69c8d85214c5a65e589378f53aec64dab31" integrity sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w== @@ -19930,7 +19909,7 @@ webpack-dev-middleware@^5.3.1: range-parser "^1.2.1" schema-utils "^4.0.0" -webpack-dev-server@^4.5.0, webpack-dev-server@^4.7.4: +webpack-dev-server@^4.5.0: version "4.15.1" resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz#8944b29c12760b3a45bdaa70799b17cb91b03df7" integrity sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA== @@ -20057,10 +20036,10 @@ webpack@4: watchpack "^1.7.4" webpack-sources "^1.4.1" -"webpack@>=4.43.0 <6.0.0", webpack@^5.70.0, webpack@^5.75.0, webpack@^5.9.0: - version "5.88.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.88.0.tgz#a07aa2f8e7a64a8f1cec0c6c2e180e3cb34440c8" - integrity sha512-O3jDhG5e44qIBSi/P6KpcCcH7HD+nYIHVBhdWFxcLOcIGN8zGo5nqF3BjyNCxIh4p1vFdNnreZv2h2KkoAw3lw== +"webpack@>=4.43.0 <6.0.0", webpack@^5.75.0, webpack@^5.9.0: + version "5.88.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.88.1.tgz#21eba01e81bd5edff1968aea726e2fbfd557d3f8" + integrity sha512-FROX3TxQnC/ox4N+3xQoWZzvGXSuscxR32rbzjpXgEzWudJFEJBpdlkkob2ylrv5yzzufD1zph1OoFsLtm6stQ== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^1.0.0" @@ -20203,7 +20182,7 @@ wildcard@^2.0.0: resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== -word-wrap@^1.2.3, word-wrap@~1.2.3: +word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== From c3d316453342cca88276d610d5e96a1df9d995f2 Mon Sep 17 00:00:00 2001 From: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com> Date: Mon, 3 Jul 2023 17:16:27 +0100 Subject: [PATCH 32/74] Update nym-wallet-storybook.yml --- .github/workflows/nym-wallet-storybook.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/nym-wallet-storybook.yml b/.github/workflows/nym-wallet-storybook.yml index 88f1230895..54f5804cbf 100644 --- a/.github/workflows/nym-wallet-storybook.yml +++ b/.github/workflows/nym-wallet-storybook.yml @@ -19,6 +19,12 @@ jobs: node-version: 18 - name: Setup yarn run: npm install -g yarn + - name: Install Rust stable + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + - name: Install wasm-pack + run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - name: Build dependencies run: yarn && yarn build - name: Build storybook From a0c6efafd25d9d697aeea055f6b491f6560918d8 Mon Sep 17 00:00:00 2001 From: Pierre Dommerc Date: Wed, 28 Jun 2023 12:20:29 +0200 Subject: [PATCH 33/74] feat(nc): monitoring update (#3609) --- nym-connect/desktop/src/pages/menu/index.tsx | 3 +- .../menu/settings/MonitoringSettings.tsx | 4 --- .../desktop/src/pages/menu/settings/index.tsx | 1 - nym-connect/desktop/src/routes/index.tsx | 2 +- nym-connect/desktop/src/sentry.ts | 2 ++ nym-connect/native/android/app/build.gradle | 2 +- .../src/main/java/net/nymtech/nyms5/App.kt | 29 +++++++++++++++++++ .../java/net/nymtech/nyms5/MainActivity.kt | 7 ++--- .../main/java/net/nymtech/nyms5/NymProxy.kt | 4 +++ .../java/net/nymtech/nyms5/ProxyWorker.kt | 4 +++ .../app/src/main/res/values/strings.xml | 4 +-- 11 files changed, 47 insertions(+), 15 deletions(-) diff --git a/nym-connect/desktop/src/pages/menu/index.tsx b/nym-connect/desktop/src/pages/menu/index.tsx index 67b3dc0131..da4f2be73d 100644 --- a/nym-connect/desktop/src/pages/menu/index.tsx +++ b/nym-connect/desktop/src/pages/menu/index.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Apps, HelpOutline, Settings } from '@mui/icons-material'; +import { Apps, HelpOutline, Settings, BugReport } from '@mui/icons-material'; import { Stack, Link, List, ListItem, ListItemButton, ListItemIcon, ListItemText } from '@mui/material'; import { Link as RouterLink } from 'react-router-dom'; import { AppVersion } from 'src/components/AppVersion'; @@ -7,6 +7,7 @@ import { AppVersion } from 'src/components/AppVersion'; const menuSchema = [ { title: 'Supported apps', icon: Apps, path: 'apps' }, { title: 'How to connect guide', icon: HelpOutline, path: 'guide' }, + { title: 'Please help us improve the app', icon: BugReport, path: 'monitoring' }, { title: 'Settings', icon: Settings, path: 'settings' }, ]; diff --git a/nym-connect/desktop/src/pages/menu/settings/MonitoringSettings.tsx b/nym-connect/desktop/src/pages/menu/settings/MonitoringSettings.tsx index 0bc23a55bd..92e15a155d 100644 --- a/nym-connect/desktop/src/pages/menu/settings/MonitoringSettings.tsx +++ b/nym-connect/desktop/src/pages/menu/settings/MonitoringSettings.tsx @@ -34,10 +34,6 @@ export const MonitoringSettings = () => { occur or if the app crashes, it will automatically send a report. Also it tracks various performance metrics. We use sentry.io service to handle this. - - Note: A report can include your external IP, this can be useful to catch issues related to IP location. - All recorded data is used by Nym developers and for app development purposes only. - diff --git a/nym-connect/desktop/src/pages/menu/settings/index.tsx b/nym-connect/desktop/src/pages/menu/settings/index.tsx index c6dbfc5998..bc58b69f1b 100644 --- a/nym-connect/desktop/src/pages/menu/settings/index.tsx +++ b/nym-connect/desktop/src/pages/menu/settings/index.tsx @@ -7,7 +7,6 @@ import { toggleLogViewer } from 'src/utils'; const menuSchema = [ { title: 'Select your gateway', path: 'gateway' }, { title: 'Select a service provider', path: 'service-provider' }, - { title: 'Help improve the app', path: 'monitoring' }, ]; export const SettingsMenu = () => ( diff --git a/nym-connect/desktop/src/routes/index.tsx b/nym-connect/desktop/src/routes/index.tsx index e490fec83a..8af5a703e3 100644 --- a/nym-connect/desktop/src/routes/index.tsx +++ b/nym-connect/desktop/src/routes/index.tsx @@ -25,11 +25,11 @@ export const AppRoutes = () => { } /> } /> } /> + } /> } /> } /> } /> - } /> diff --git a/nym-connect/desktop/src/sentry.ts b/nym-connect/desktop/src/sentry.ts index 835131c2ec..13f7529c30 100644 --- a/nym-connect/desktop/src/sentry.ts +++ b/nym-connect/desktop/src/sentry.ts @@ -43,6 +43,8 @@ async function initSentry() { getVersion().then((version) => { Sentry.setTag('app_version', version); }); + + Sentry.setUser({ id: 'nym', ip_address: undefined }); } export default initSentry; diff --git a/nym-connect/native/android/app/build.gradle b/nym-connect/native/android/app/build.gradle index 23d75605c4..5cd2701c53 100644 --- a/nym-connect/native/android/app/build.gradle +++ b/nym-connect/native/android/app/build.gradle @@ -99,7 +99,6 @@ android { } dependencies { - implementation 'androidx.core:core-ktx:1.10.1' implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1' implementation 'androidx.activity:activity-compose:1.7.2' @@ -124,4 +123,5 @@ dependencies { debugImplementation 'androidx.compose.ui:ui-tooling' debugImplementation 'androidx.compose.ui:ui-test-manifest' implementation 'com.github.kittinunf.fuel:fuel:3.0.0-alpha1' + implementation 'io.sentry:sentry-android:6.24.0' } diff --git a/nym-connect/native/android/app/src/main/java/net/nymtech/nyms5/App.kt b/nym-connect/native/android/app/src/main/java/net/nymtech/nyms5/App.kt index 8a59ada991..105270644c 100644 --- a/nym-connect/native/android/app/src/main/java/net/nymtech/nyms5/App.kt +++ b/nym-connect/native/android/app/src/main/java/net/nymtech/nyms5/App.kt @@ -2,6 +2,8 @@ package net.nymtech.nyms5 import android.app.Application import android.content.Context +import android.content.pm.PackageManager +import android.os.Build import android.util.Log import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences @@ -9,11 +11,15 @@ import androidx.datastore.preferences.core.booleanPreferencesKey import androidx.datastore.preferences.preferencesDataStore import androidx.work.Configuration import androidx.work.DelegatingWorkerFactory +import io.sentry.Scope +import io.sentry.Sentry import io.sentry.android.core.SentryAndroid +import io.sentry.protocol.User import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.coroutines.runBlocking + val Context.dataStore: DataStore by preferencesDataStore(name = "settings") val monitoringKey = booleanPreferencesKey("monitoring") @@ -40,11 +46,34 @@ class App : Application(), Configuration.Provider { options.dsn = "https://6872f5818bc147ef9c0fce114fcaac8a@o967446.ingest.sentry.io/4505306218102784" options.enableAllAutoBreadcrumbs(true) + options.isEnableUserInteractionTracing = true + options.isEnableUserInteractionBreadcrumbs = true // TODO should be adjusted in production env + options.sampleRate = 1.0 options.tracesSampleRate = 1.0 options.profilesSampleRate = 1.0 } + + Sentry.configureScope { scope: Scope -> + val packageManager = applicationContext.packageManager + val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + packageManager.getPackageInfo( + packageName, + PackageManager.PackageInfoFlags.of(0) + ) + } else { + packageManager.getPackageInfo(packageName, 0) + } + scope.setTag("app_version", packageInfo.versionName) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + scope.setTag("app_version_code", packageInfo.longVersionCode.toString()) + } + } + + val user = User() + user.id = "nym" + Sentry.setUser(user) } } } diff --git a/nym-connect/native/android/app/src/main/java/net/nymtech/nyms5/MainActivity.kt b/nym-connect/native/android/app/src/main/java/net/nymtech/nyms5/MainActivity.kt index 6e5a472be5..3530d6db81 100644 --- a/nym-connect/native/android/app/src/main/java/net/nymtech/nyms5/MainActivity.kt +++ b/nym-connect/native/android/app/src/main/java/net/nymtech/nyms5/MainActivity.kt @@ -50,6 +50,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString @@ -249,7 +250,7 @@ fun S5ClientSwitch( Spacer(modifier = modifier.width(14.dp)) Switch(checked = connected, enabled = !loading, onCheckedChange = { onSwitch(!connected) - }) + }, modifier = Modifier.testTag("switch_connect")) } if (connected && !loading) { Column(modifier = modifier.padding(16.dp)) { @@ -332,12 +333,10 @@ fun Monitoring( tint = Color.Yellow ) Spacer(modifier = modifier.width(16.dp)) - Text(stringResource(R.string.monitoring_desc_3), color = Color.Yellow) + Text(stringResource(R.string.monitoring_desc_2), color = Color.Yellow) } Spacer(modifier = modifier.height(18.dp)) Text(stringResource(R.string.monitoring_desc_1)) - Spacer(modifier = modifier.height(18.dp)) - Text(stringResource(R.string.monitoring_desc_2)) } } diff --git a/nym-connect/native/android/app/src/main/java/net/nymtech/nyms5/NymProxy.kt b/nym-connect/native/android/app/src/main/java/net/nymtech/nyms5/NymProxy.kt index 57d57454cf..8ff13e7c45 100644 --- a/nym-connect/native/android/app/src/main/java/net/nymtech/nyms5/NymProxy.kt +++ b/nym-connect/native/android/app/src/main/java/net/nymtech/nyms5/NymProxy.kt @@ -1,6 +1,7 @@ package net.nymtech.nyms5 import android.util.Log +import io.sentry.Sentry const val nymNativeLib = "nym_socks5_listener" @@ -27,6 +28,7 @@ class NymProxy { startClient(serviceProvider, onStartCbObj, onStopCbObj) } catch (e: Throwable) { Log.e(tag, "$nymNativeLib:startClient internal error: $e") + Sentry.captureException(e) } } @@ -36,6 +38,7 @@ class NymProxy { stopClient() } catch (e: Throwable) { Log.e(tag, "$nymNativeLib:stopClient internal error: $e") + Sentry.captureException(e) } } @@ -50,6 +53,7 @@ class NymProxy { } } catch (e: Throwable) { Log.e(tag, "$nymNativeLib:getClientState internal error: $e") + Sentry.captureException(e) } return State.UNINITIALIZED } diff --git a/nym-connect/native/android/app/src/main/java/net/nymtech/nyms5/ProxyWorker.kt b/nym-connect/native/android/app/src/main/java/net/nymtech/nyms5/ProxyWorker.kt index 779fbf9101..c2f71c3118 100644 --- a/nym-connect/native/android/app/src/main/java/net/nymtech/nyms5/ProxyWorker.kt +++ b/nym-connect/native/android/app/src/main/java/net/nymtech/nyms5/ProxyWorker.kt @@ -17,6 +17,7 @@ import androidx.work.WorkerParameters import androidx.work.workDataOf import fuel.Fuel import fuel.get +import io.sentry.Sentry import kotlinx.serialization.Serializable import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json @@ -100,6 +101,7 @@ class ProxyWorker( tag, "failed to make the work run in the context of a foreground service" ) + Sentry.captureException(e) } return try { @@ -127,6 +129,7 @@ class ProxyWorker( tag, "an error occurred while fetching the service providers list: $e" ) + Sentry.captureException(e) Log.w(tag, "using a default service provider $defaultSp") } @@ -139,6 +142,7 @@ class ProxyWorker( Result.success() } catch (e: Throwable) { Log.e(tag, "error: ${e.message}") + Sentry.captureException(e) Result.failure() } } diff --git a/nym-connect/native/android/app/src/main/res/values/strings.xml b/nym-connect/native/android/app/src/main/res/values/strings.xml index ee21a78dc9..ff0cb1857d 100644 --- a/nym-connect/native/android/app/src/main/res/values/strings.xml +++ b/nym-connect/native/android/app/src/main/res/values/strings.xml @@ -12,7 +12,5 @@ DpB3cHAchJiNBQi5FrZx2csXb1mrHkpYh9Wzf8Rjsuko.ANNWrvHqMYuertHGHUrZdBntQhpzfbWekB39qez9U2Vx@2BuMSfMW3zpeAjKXyKLhmY4QW1DXurrtSPEJ6CjX3SEh Connected to the mixnet Help Nym developers to fix errors, crashes and improve the application by enabling this option. If errors occur or if the app crashes, it will automatically send a report. Also it tracks various performance metrics. We use sentry.io service to handle this. - Note: A report can include your external IP, this can be useful to catch issues related to IP location. - All recorded data is used by Nym developers and for app development purposes only. - You must restart the application for the change to take effect. + You must restart the application for the change to take effect. \ No newline at end of file From 0fee189a89b0bec9a336b4d361e66df7f0d8320e Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 3 Jul 2023 17:29:29 +0000 Subject: [PATCH 34/74] moved image --- .../pic => images}/element_nym_keybind.png | Bin .../dev-portal/src/tutorials/matrix.md | 21 +++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) rename documentation/dev-portal/src/{tutorials/pic => images}/element_nym_keybind.png (100%) diff --git a/documentation/dev-portal/src/tutorials/pic/element_nym_keybind.png b/documentation/dev-portal/src/images/element_nym_keybind.png similarity index 100% rename from documentation/dev-portal/src/tutorials/pic/element_nym_keybind.png rename to documentation/dev-portal/src/images/element_nym_keybind.png diff --git a/documentation/dev-portal/src/tutorials/matrix.md b/documentation/dev-portal/src/tutorials/matrix.md index 2587707656..27a8bf744f 100644 --- a/documentation/dev-portal/src/tutorials/matrix.md +++ b/documentation/dev-portal/src/tutorials/matrix.md @@ -1,25 +1,24 @@ # Matrix NymConnect Integration -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. +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 a keyboard shortcut setting 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. +Make sure you have installed and started **[NymConnect](https://nymtech.net/developers/quickstart/nymconnect-gui.html)** on your desktop. -**Command-line** - -To start Matrix's Element client via Socks5 proxy connected to NymConnect open terminal and run: +To then start Matrix's Element client via a Socks5 proxy connected to NymConnect, open terminal and run: ```sh element-desktop --proxy-server=socks5://127.0.0.1:1080 ``` -**Keybinding** +## 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 @@ -31,5 +30,15 @@ An example can look like this. ![](pic/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): +```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. + +Now you can run Element throught the mixnet with a single-word command. From 73ca14aae22e6160c5b396aedc33844d8bce7215 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 3 Jul 2023 17:29:58 +0000 Subject: [PATCH 35/74] added alias info + some restructuring --- documentation/dev-portal/src/tutorials/matrix.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/dev-portal/src/tutorials/matrix.md b/documentation/dev-portal/src/tutorials/matrix.md index 27a8bf744f..39852fed05 100644 --- a/documentation/dev-portal/src/tutorials/matrix.md +++ b/documentation/dev-portal/src/tutorials/matrix.md @@ -28,7 +28,7 @@ Make sure your `Shortcut` isn't already taken by something else in the menu. An example can look like this. -![](pic/element_nym_keybind.png) +![](../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. From e0255646781fac4ca3a2692ae534129a12630294 Mon Sep 17 00:00:00 2001 From: farbanas Date: Tue, 4 Jul 2023 09:48:43 +0200 Subject: [PATCH 36/74] update changelog --- CHANGELOG.md | 6 +++++- nym-connect/desktop/CHANGELOG.md | 4 +++- nym-wallet/CHANGELOG.md | 4 +++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c12572b434..f938c81fe3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,16 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https:// ## [Unreleased] -## [1.1.23] (2023-06-27) +## [v1.1.23] (2023-07-04) - nym-cli: add client identity key signing support ([#3576]) +- Feature/node tester package ([#3634]) +- Add medium toggle to socks5 client ([#3615]) - Don't fully turn off background task when cover traffic is disabled ([#3596]) [#3576]: https://github.com/nymtech/nym/issues/3576 +[#3634]: https://github.com/nymtech/nym/pull/3634 +[#3615]: https://github.com/nymtech/nym/pull/3615 [#3596]: https://github.com/nymtech/nym/pull/3596 ## [v1.1.22] (2023-06-20) diff --git a/nym-connect/desktop/CHANGELOG.md b/nym-connect/desktop/CHANGELOG.md index 42d923e76a..174b5e938d 100644 --- a/nym-connect/desktop/CHANGELOG.md +++ b/nym-connect/desktop/CHANGELOG.md @@ -2,16 +2,18 @@ ## [Unreleased] -## [v1.1.14] (2023-06-27) +## [v1.1.14] (2023-07-04) - Nym connect fails to start when encountering an old config version ([#3588]) - NC desktop - apps section adjustments + add monero integration ([#2977]) +- nym-connect: use different service provider directory when medium toggle enabled ([#3617]) - Fix medium toggle in nym-connect ([#3590]) - [bugfix] NC: load old gateway configuration if we're not registering ([#3586]) - nym-connect: medium speed setting ([#3585]) [#3588]: https://github.com/nymtech/nym/issues/3588 [#2977]: https://github.com/nymtech/nym/issues/2977 +[#3617]: https://github.com/nymtech/nym/pull/3617 [#3590]: https://github.com/nymtech/nym/pull/3590 [#3586]: https://github.com/nymtech/nym/pull/3586 [#3585]: https://github.com/nymtech/nym/pull/3585 diff --git a/nym-wallet/CHANGELOG.md b/nym-wallet/CHANGELOG.md index acd33c1bb7..82a2dd9da7 100644 --- a/nym-wallet/CHANGELOG.md +++ b/nym-wallet/CHANGELOG.md @@ -2,11 +2,13 @@ ## [Unreleased] -## [v1.2.5] (2023-06-27) +## [v1.2.5] (2023-07-04) - Wallet - add "Test my node" in the Node Settings and show its results ([#2314]) +- Move client wasm to Wallet directory ([#3606]) [#2314]: https://github.com/nymtech/nym/issues/2314 +[#3606]: https://github.com/nymtech/nym/pull/3606 ## [v1.2.4] (2023-06-06) From a71e228a252c73a01ddf50a2cc0ef41205d0f4b0 Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Tue, 4 Jul 2023 09:34:35 +0100 Subject: [PATCH 37/74] Add wasm-pack install to GitHub Actions --- .github/workflows/nym-wallet-publish-macos.yml | 2 ++ .github/workflows/nym-wallet-publish-ubuntu.yml | 3 +++ .github/workflows/nym-wallet-publish-windows10.yml | 4 +++- .github/workflows/nym-wallet-storybook.yml | 6 ++++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/nym-wallet-publish-macos.yml b/.github/workflows/nym-wallet-publish-macos.yml index 81c27a8338..9df72181b6 100644 --- a/.github/workflows/nym-wallet-publish-macos.yml +++ b/.github/workflows/nym-wallet-publish-macos.yml @@ -28,6 +28,8 @@ jobs: uses: actions-rs/toolchain@v1 with: toolchain: stable + - name: Install wasm-pack + run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - name: Install the Apple developer certificate for code signing env: APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} diff --git a/.github/workflows/nym-wallet-publish-ubuntu.yml b/.github/workflows/nym-wallet-publish-ubuntu.yml index 1f2bb0330d..e9470ffcea 100644 --- a/.github/workflows/nym-wallet-publish-ubuntu.yml +++ b/.github/workflows/nym-wallet-publish-ubuntu.yml @@ -34,6 +34,9 @@ jobs: uses: actions-rs/toolchain@v1 with: toolchain: stable + - name: Install wasm-pack + run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + - name: Install app dependencies run: yarn - name: Create env file diff --git a/.github/workflows/nym-wallet-publish-windows10.yml b/.github/workflows/nym-wallet-publish-windows10.yml index 044816953b..b9934bd1ff 100644 --- a/.github/workflows/nym-wallet-publish-windows10.yml +++ b/.github/workflows/nym-wallet-publish-windows10.yml @@ -48,7 +48,9 @@ jobs: uses: actions-rs/toolchain@v1 with: toolchain: stable - + - name: Install wasm-pack + run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + - name: Create env file uses: timheuer/base64-to-file@v1.1 with: diff --git a/.github/workflows/nym-wallet-storybook.yml b/.github/workflows/nym-wallet-storybook.yml index 88f1230895..99eb4ce262 100644 --- a/.github/workflows/nym-wallet-storybook.yml +++ b/.github/workflows/nym-wallet-storybook.yml @@ -19,6 +19,12 @@ jobs: node-version: 18 - name: Setup yarn run: npm install -g yarn + - name: Install Rust stable + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + - name: Install wasm-pack + run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - name: Build dependencies run: yarn && yarn build - name: Build storybook From fc2236c3c80d279a34fd725fd1704473be1c25ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Tue, 4 Jul 2023 11:21:47 +0200 Subject: [PATCH 38/74] Strip comments from allow lists in network-requester (#3624) * service-provider: remove comments from standard allow list * Remove comments from the local allow list --- Cargo.lock | 11 ++-- .../network-requester/Cargo.toml | 1 + .../src/allowed_hosts/hosts.rs | 63 ++++++++++++++++++- .../src/allowed_hosts/standard_list.rs | 14 ++++- 4 files changed, 79 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3f87508d0b..1c4022ce0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4092,6 +4092,7 @@ dependencies = [ "pretty_env_logger", "publicsuffix", "rand 0.7.3", + "regex", "reqwest", "serde", "serde_json", @@ -5706,13 +5707,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.1" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.1", + "regex-syntax 0.7.2", ] [[package]] @@ -5732,9 +5733,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "reqwest" diff --git a/service-providers/network-requester/Cargo.toml b/service-providers/network-requester/Cargo.toml index 8226b7425a..5b80088b30 100644 --- a/service-providers/network-requester/Cargo.toml +++ b/service-providers/network-requester/Cargo.toml @@ -23,6 +23,7 @@ log = { workspace = true } pretty_env_logger = "0.4.0" publicsuffix = "1.5" # Can't update this until bip updates to support newer idna version rand = "0.7.3" +regex = "1.8.4" reqwest = { version = "0.11.11", features = ["json"] } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } diff --git a/service-providers/network-requester/src/allowed_hosts/hosts.rs b/service-providers/network-requester/src/allowed_hosts/hosts.rs index b68159d59e..5c48369d0d 100644 --- a/service-providers/network-requester/src/allowed_hosts/hosts.rs +++ b/service-providers/network-requester/src/allowed_hosts/hosts.rs @@ -128,10 +128,29 @@ impl HostsStore { log::trace!("Loading from storefile: {}", filename.as_ref().display()); let file = File::open(filename)?; let reader = BufReader::new(&file); - Ok(reader + let hosts = reader .lines() - .map(|line| Host::from(line.expect("failed to read input file line!"))) - .collect()) + .filter_map(|line| { + let line = line.expect("failed to read input file line!"); + trim_comment(&line) + }) + .map(Host::from) + .collect(); + dbg!(&hosts); + Ok(hosts) + } +} + +fn trim_comment(line: &str) -> Option { + if let Some(content) = line.split('#').next() { + let trim_content = content.trim().to_string(); + if trim_content.is_empty() { + None + } else { + Some(trim_content) + } + } else { + None } } @@ -145,4 +164,42 @@ mod constructor_tests { let store = HostsStore::new(temp_file); assert_eq!(store.data.domains.len(), 0); } + + #[test] + fn trim_comments() { + let entries = vec![ + "# keybase", + "keybaseapi.com", + "", + "gist.githubusercontent.com", + " ", + "# healthcheck # foo", + "nymtech.net", + "# blockstream green wallet", + "blockstream.info", + "greenaddress.it", + "91.108.56.0/22", + "2001:b28:f23d::/48", + "2001:67c:4e8::/48", + "# nym matrix server", + "# monero desktop - mainnet", + ]; + let filtered_entries: Vec<_> = entries + .iter() + .filter_map(|line| trim_comment(line)) + .collect(); + assert_eq!( + filtered_entries, + vec![ + "keybaseapi.com", + "gist.githubusercontent.com", + "nymtech.net", + "blockstream.info", + "greenaddress.it", + "91.108.56.0/22", + "2001:b28:f23d::/48", + "2001:67c:4e8::/48", + ] + ); + } } diff --git a/service-providers/network-requester/src/allowed_hosts/standard_list.rs b/service-providers/network-requester/src/allowed_hosts/standard_list.rs index 66f529f57f..3b873827e3 100644 --- a/service-providers/network-requester/src/allowed_hosts/standard_list.rs +++ b/service-providers/network-requester/src/allowed_hosts/standard_list.rs @@ -4,6 +4,7 @@ use crate::allowed_hosts::group::HostsGroup; use crate::allowed_hosts::host::Host; use nym_task::TaskClient; +use regex::Regex; use std::sync::Arc; use std::time::Duration; use tokio::sync::{RwLock, RwLockReadGuard}; @@ -11,11 +12,20 @@ use tokio::sync::{RwLock, RwLockReadGuard}; const STANDARD_LIST_URL: &str = "https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt"; +fn remove_comments(text: String) -> String { + if let Ok(regex) = Regex::new(r"#.*\n") { + regex.replace_all(&text, "").into_owned() + } else { + log::warn!("Failed to strip comments from standard allowed list"); + text + } +} + /// Fetch the standard allowed list from nymtech.net pub(crate) async fn fetch() -> Vec { log::info!("Refreshing standard allowed hosts"); - get_standard_allowed_list() - .await + let text = get_standard_allowed_list().await; + remove_comments(text) .split_whitespace() .map(Into::into) .collect() From 90a97b398e8cc95980b61866df7cfb6c13a64519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Tue, 4 Jul 2023 11:49:54 +0200 Subject: [PATCH 39/74] name-service contract: signature check when registering (#3572) * Add nonce state * Update name-service types and make it build * wip: convert tests * Fixed all tests in names.rs * Add TestName * Move TestSetup to integration tests * Tests in contract.rs done * Move error mod to common crate * All tests ported * Update other crates in workspace * rustfmt * clippy * Remove commented out code * Shortcut for name.name --- Cargo.lock | 4 + clients/webassembly/Cargo.lock | 4 + .../nyxd/traits/name_service_query_client.rs | 8 +- .../traits/name_service_signing_client.rs | 12 +- .../mixnet/operators/name/register.rs | 16 +- .../validator/mixnet/query/query_all_names.rs | 4 +- .../name-service/Cargo.toml | 4 + .../name-service/src/error.rs | 21 +- .../name-service/src/events.rs | 26 +- .../name-service/src/lib.rs | 2 + .../name-service/src/msg.rs | 18 +- .../name-service/src/response.rs | 43 +- .../name-service/src/signing_types.rs | 32 ++ .../name-service/src/types.rs | 55 ++- .../service-provider-directory/Cargo.toml | 4 +- contracts/Cargo.lock | 7 + contracts/name-service/Cargo.toml | 3 + contracts/name-service/src/constants.rs | 2 + contracts/name-service/src/contract.rs | 202 ++++++-- .../name-service/src/contract/execute.rs | 89 +++- contracts/name-service/src/contract/query.rs | 21 +- .../name-service/src/integration_tests.rs | 445 ------------------ .../src/integration_tests/delete.rs | 148 ++++++ .../name-service/src/integration_tests/mod.rs | 13 + .../src/integration_tests/name_id.rs | 70 +++ .../src/integration_tests/query.rs | 88 ++++ .../src/integration_tests/register.rs | 269 +++++++++++ .../src/integration_tests/test_name.rs | 75 +++ .../test_setup.rs | 74 ++- contracts/name-service/src/lib.rs | 5 +- contracts/name-service/src/state/admin.rs | 2 +- contracts/name-service/src/state/config.rs | 2 +- contracts/name-service/src/state/mod.rs | 2 + .../name-service/src/state/name_id_counter.rs | 85 ++-- contracts/name-service/src/state/names.rs | 381 +++++++-------- contracts/name-service/src/state/nonce.rs | 71 +++ .../name-service/src/test_helpers/assert.rs | 28 +- .../name-service/src/test_helpers/fixture.rs | 106 ++++- .../name-service/src/test_helpers/helpers.rs | 67 +-- .../name-service/src/test_helpers/mod.rs | 3 +- .../name-service/src/test_helpers/signing.rs | 39 ++ .../src/test_helpers/transactions.rs | 72 +++ nym-api/src/nym_contract_cache/cache/data.rs | 4 +- nym-api/src/nym_contract_cache/cache/mod.rs | 6 +- nym-connect/desktop/Cargo.lock | 4 + nym-wallet/Cargo.lock | 4 + 46 files changed, 1682 insertions(+), 958 deletions(-) rename {contracts => common/cosmwasm-smart-contracts}/name-service/src/error.rs (71%) create mode 100644 common/cosmwasm-smart-contracts/name-service/src/signing_types.rs delete mode 100644 contracts/name-service/src/integration_tests.rs create mode 100644 contracts/name-service/src/integration_tests/delete.rs create mode 100644 contracts/name-service/src/integration_tests/mod.rs create mode 100644 contracts/name-service/src/integration_tests/name_id.rs create mode 100644 contracts/name-service/src/integration_tests/query.rs create mode 100644 contracts/name-service/src/integration_tests/register.rs create mode 100644 contracts/name-service/src/integration_tests/test_name.rs rename contracts/name-service/src/{test_helpers => integration_tests}/test_setup.rs (64%) create mode 100644 contracts/name-service/src/state/nonce.rs create mode 100644 contracts/name-service/src/test_helpers/signing.rs create mode 100644 contracts/name-service/src/test_helpers/transactions.rs diff --git a/Cargo.lock b/Cargo.lock index 1c4022ce0d..6d8e1dadd7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4041,8 +4041,12 @@ name = "nym-name-service-common" version = "0.1.0" dependencies = [ "cosmwasm-std", + "cw-controllers", + "cw-utils", + "nym-contracts-common", "schemars", "serde", + "thiserror", ] [[package]] diff --git a/clients/webassembly/Cargo.lock b/clients/webassembly/Cargo.lock index d0ba9718c5..823fbbb252 100644 --- a/clients/webassembly/Cargo.lock +++ b/clients/webassembly/Cargo.lock @@ -2580,8 +2580,12 @@ name = "nym-name-service-common" version = "0.1.0" dependencies = [ "cosmwasm-std", + "cw-controllers", + "cw-utils", + "nym-contracts-common", "schemars", "serde", + "thiserror", ] [[package]] diff --git a/common/client-libs/validator-client/src/nyxd/traits/name_service_query_client.rs b/common/client-libs/validator-client/src/nyxd/traits/name_service_query_client.rs index 95f0a2517e..0823d97d6a 100644 --- a/common/client-libs/validator-client/src/nyxd/traits/name_service_query_client.rs +++ b/common/client-libs/validator-client/src/nyxd/traits/name_service_query_client.rs @@ -4,7 +4,7 @@ use nym_contracts_common::ContractBuildInformation; use nym_name_service_common::{ msg::QueryMsg as NameQueryMsg, response::{ConfigResponse, NamesListResponse, PagedNamesListResponse}, - Address, NameEntry, NameId, + Address, NameId, RegisteredName, }; use serde::Deserialize; @@ -21,7 +21,7 @@ pub trait NameServiceQueryClient { .await } - async fn get_name_entry(&self, name_id: NameId) -> Result { + async fn get_name_entry(&self, name_id: NameId) -> Result { self.query_name_service_contract(NameQueryMsg::NameId { name_id }) .await } @@ -54,14 +54,14 @@ pub trait NameServiceQueryClient { .await } - async fn get_all_names(&self) -> Result, NyxdError> { + async fn get_all_names(&self) -> Result, NyxdError> { let mut services = Vec::new(); let mut start_after = None; loop { let mut paged_response = self.get_names_paged(start_after.take(), None).await?; - let last_id = paged_response.names.last().map(|serv| serv.name_id); + let last_id = paged_response.names.last().map(|serv| serv.id); services.append(&mut paged_response.names); if let Some(start_after_res) = last_id { diff --git a/common/client-libs/validator-client/src/nyxd/traits/name_service_signing_client.rs b/common/client-libs/validator-client/src/nyxd/traits/name_service_signing_client.rs index 4e4e43ee77..1235043094 100644 --- a/common/client-libs/validator-client/src/nyxd/traits/name_service_signing_client.rs +++ b/common/client-libs/validator-client/src/nyxd/traits/name_service_signing_client.rs @@ -2,7 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 use async_trait::async_trait; -use nym_name_service_common::{msg::ExecuteMsg as NameExecuteMsg, Address, NameId, NymName}; +use nym_contracts_common::signing::MessageSignature; +use nym_name_service_common::{msg::ExecuteMsg as NameExecuteMsg, NameDetails, NameId, NymName}; use crate::nyxd::{ coin::Coin, cosmwasm_client::types::ExecuteResult, error::NyxdError, Fee, NyxdClient, @@ -20,14 +21,17 @@ pub trait NameServiceSigningClient { async fn register_name( &self, - name: NymName, - address: Address, + name: NameDetails, + owner_signature: MessageSignature, deposit: Coin, fee: Option, ) -> Result { self.execute_name_service_contract( fee, - NameExecuteMsg::Register { name, address }, + NameExecuteMsg::Register { + name, + owner_signature, + }, vec![deposit], ) .await diff --git a/common/commands/src/validator/mixnet/operators/name/register.rs b/common/commands/src/validator/mixnet/operators/name/register.rs index 6458faf8a6..e246e4241a 100644 --- a/common/commands/src/validator/mixnet/operators/name/register.rs +++ b/common/commands/src/validator/mixnet/operators/name/register.rs @@ -1,6 +1,7 @@ use clap::Parser; use log::{error, info}; -use nym_name_service_common::{Address, Coin, NymName}; +use nym_contracts_common::signing::MessageSignature; +use nym_name_service_common::{Address, Coin, NameDetails, NymName}; use nym_validator_client::nyxd::{error::NyxdError, traits::NameServiceSigningClient}; use tap::TapFallible; @@ -16,9 +17,15 @@ pub struct Args { #[clap(long)] pub nym_address: String, + #[clap(long)] + pub signature: MessageSignature, + /// Deposit to be made to the service provider directory, in curent DENOMINATION (e.g. 'unym') #[clap(long)] pub deposit: u128, + + #[clap(long)] + pub identity_key: String, } pub async fn register(args: Args, client: SigningClient) -> Result<(), NyxdError> { @@ -29,12 +36,17 @@ pub async fn register(args: Args, client: SigningClient) -> Result<(), NyxdError let name = NymName::new(&args.name).expect("invalid name"); let address = Address::new(&args.nym_address); + let name = NameDetails { + name, + address, + identity_key: args.identity_key, + }; let denom = client.current_chain_details().mix_denom.base.as_str(); let deposit = Coin::new(args.deposit, denom); let res = client - .register_name(name, address, deposit.into(), None) + .register_name(name, args.signature, deposit.into(), None) .await .tap_err(|err| error!("Failed to register name: {err:#?}"))?; diff --git a/common/commands/src/validator/mixnet/query/query_all_names.rs b/common/commands/src/validator/mixnet/query/query_all_names.rs index e3bb24ebae..5a17cad30d 100644 --- a/common/commands/src/validator/mixnet/query/query_all_names.rs +++ b/common/commands/src/validator/mixnet/query/query_all_names.rs @@ -34,8 +34,8 @@ pub async fn query(args: Args, client: &QueryClientWithNyxd) { table.set_header(vec!["Name Id", "Owner", "Nym Address", "Name"]); for name_entry in res.names { table.add_row(vec![ - name_entry.name_id.to_string(), - name_entry.name.owner.to_string(), + name_entry.id.to_string(), + name_entry.owner.to_string(), name_entry.name.address.to_string(), name_entry.name.name.to_string(), ]); diff --git a/common/cosmwasm-smart-contracts/name-service/Cargo.toml b/common/cosmwasm-smart-contracts/name-service/Cargo.toml index 46b767a3df..23fb221e23 100644 --- a/common/cosmwasm-smart-contracts/name-service/Cargo.toml +++ b/common/cosmwasm-smart-contracts/name-service/Cargo.toml @@ -7,5 +7,9 @@ edition = "2021" [dependencies] cosmwasm-std = { workspace = true } +cw-controllers = { workspace = true } +cw-utils = { workspace = true } +nym-contracts-common = { path = "../contracts-common", version = "0.5.0" } schemars = "0.8" serde = { workspace = true, features = ["derive"] } +thiserror = { workspace = true } diff --git a/contracts/name-service/src/error.rs b/common/cosmwasm-smart-contracts/name-service/src/error.rs similarity index 71% rename from contracts/name-service/src/error.rs rename to common/cosmwasm-smart-contracts/name-service/src/error.rs index 66ca6485dd..8c31308b66 100644 --- a/contracts/name-service/src/error.rs +++ b/common/cosmwasm-smart-contracts/name-service/src/error.rs @@ -1,8 +1,10 @@ use cosmwasm_std::{Addr, StdError}; use cw_controllers::AdminError; -use nym_name_service_common::{Address, NameId, NymName}; +use nym_contracts_common::signing::verifier::ApiVerifierError; use thiserror::Error; +use crate::{Address, NameId, NymName}; + #[derive(Error, Debug, PartialEq)] pub enum NameServiceError { #[error("{0}")] @@ -47,6 +49,21 @@ pub enum NameServiceError { error_message: String, }, + #[error("Failed to recover ed25519 public key from its base58 representation - {0}")] + MalformedEd25519IdentityKey(String), + + #[error("Failed to recover ed25519 signature from its base58 representation - {0}")] + MalformedEd25519Signature(String), + + #[error("Provided ed25519 signature did not verify correctly")] + InvalidEd25519Signature, + + #[error("failed to verify message signature: {source}")] + SignatureVerificationFailure { + #[from] + source: ApiVerifierError, + }, + #[error("duplicate entries detected for name: {name}")] DuplicateNames { name: NymName }, @@ -54,4 +71,4 @@ pub enum NameServiceError { NameAlreadyRegistered { name: NymName }, } -pub(crate) type Result = std::result::Result; +pub type Result = std::result::Result; diff --git a/common/cosmwasm-smart-contracts/name-service/src/events.rs b/common/cosmwasm-smart-contracts/name-service/src/events.rs index 0454a8fb28..5bf65e606d 100644 --- a/common/cosmwasm-smart-contracts/name-service/src/events.rs +++ b/common/cosmwasm-smart-contracts/name-service/src/events.rs @@ -1,6 +1,6 @@ use cosmwasm_std::{Coin, Event}; -use crate::{NameId, RegisteredName}; +use crate::RegisteredName; pub enum NameEventType { Register, @@ -34,29 +34,29 @@ pub const OWNER: &str = "owner"; pub const DEPOSIT_REQUIRED: &str = "deposit_required"; -pub fn new_register_event(name_id: NameId, name: RegisteredName) -> Event { +pub fn new_register_event(name: RegisteredName) -> Event { Event::new(NameEventType::Register) .add_attribute(ACTION, NameEventType::Register) - .add_attribute(NAME_ID, name_id.to_string()) - .add_attribute(NAME, name.name.to_string()) - .add_attribute(name.address.event_tag(), name.address.to_string()) + .add_attribute(NAME_ID, name.id.to_string()) + .add_attribute(NAME, name.name.name.to_string()) + .add_attribute(name.name.address.event_tag(), name.name.address.to_string()) .add_attribute(OWNER, name.owner.to_string()) } -pub fn new_delete_id_event(name_id: NameId, name: RegisteredName) -> Event { +pub fn new_delete_id_event(name: RegisteredName) -> Event { Event::new(NameEventType::DeleteId) .add_attribute(ACTION, NameEventType::DeleteId) - .add_attribute(NAME_ID, name_id.to_string()) - .add_attribute(NAME, name.name.to_string()) - .add_attribute(name.address.event_tag(), name.address.to_string()) + .add_attribute(NAME_ID, name.id.to_string()) + .add_attribute(NAME, name.name.name.to_string()) + .add_attribute(name.name.address.event_tag(), name.name.address.to_string()) } -pub fn new_delete_name_event(name_id: NameId, name: RegisteredName) -> Event { +pub fn new_delete_name_event(name: RegisteredName) -> Event { Event::new(NameEventType::DeleteId) .add_attribute(ACTION, NameEventType::DeleteName) - .add_attribute(NAME_ID, name_id.to_string()) - .add_attribute(NAME, name.name.to_string()) - .add_attribute(name.address.event_tag(), name.address.to_string()) + .add_attribute(NAME_ID, name.id.to_string()) + .add_attribute(NAME, name.name.name.to_string()) + .add_attribute(name.name.address.event_tag(), name.name.address.to_string()) } pub fn new_update_deposit_required_event(deposit_required: Coin) -> Event { diff --git a/common/cosmwasm-smart-contracts/name-service/src/lib.rs b/common/cosmwasm-smart-contracts/name-service/src/lib.rs index 4609473c60..71a702b7c1 100644 --- a/common/cosmwasm-smart-contracts/name-service/src/lib.rs +++ b/common/cosmwasm-smart-contracts/name-service/src/lib.rs @@ -1,6 +1,8 @@ +pub mod error; pub mod events; pub mod msg; pub mod response; +pub mod signing_types; pub mod types; // Re-export all types at the top-level diff --git a/common/cosmwasm-smart-contracts/name-service/src/msg.rs b/common/cosmwasm-smart-contracts/name-service/src/msg.rs index 6a6698f34d..9a8e2b8ecf 100644 --- a/common/cosmwasm-smart-contracts/name-service/src/msg.rs +++ b/common/cosmwasm-smart-contracts/name-service/src/msg.rs @@ -1,5 +1,6 @@ -use crate::{Address, NameId, NymName}; +use crate::{Address, NameDetails, NameId, NymName}; use cosmwasm_std::Coin; +use nym_contracts_common::signing::MessageSignature; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] @@ -22,7 +23,10 @@ pub struct MigrateMsg {} #[serde(rename_all = "snake_case")] pub enum ExecuteMsg { /// Announcing a name pointing to a nym-address - Register { name: NymName, address: Address }, + Register { + name: NameDetails, + owner_signature: MessageSignature, + }, /// Delete a name entry by id DeleteId { name_id: NameId }, /// Delete a name entry by name @@ -38,8 +42,11 @@ impl ExecuteMsg { pub fn default_memo(&self) -> String { match self { - ExecuteMsg::Register { name, address } => { - format!("registering {address} as name: {name}") + ExecuteMsg::Register { + name, + owner_signature: _, + } => { + format!("registering {} as name: {}", name.address, name.name) } ExecuteMsg::DeleteId { name_id } => { format!("deleting name with id {name_id}") @@ -75,6 +82,9 @@ pub enum QueryMsg { limit: Option, start_after: Option, }, + SigningNonce { + address: String, + }, Config {}, GetContractVersion {}, #[serde(rename = "get_cw2_contract_version")] diff --git a/common/cosmwasm-smart-contracts/name-service/src/response.rs b/common/cosmwasm-smart-contracts/name-service/src/response.rs index 5daa630d01..8087195eee 100644 --- a/common/cosmwasm-smart-contracts/name-service/src/response.rs +++ b/common/cosmwasm-smart-contracts/name-service/src/response.rs @@ -1,36 +1,22 @@ -use crate::{msg::ExecuteMsg, NameEntry, NameId, RegisteredName}; +use crate::{NameId, RegisteredName}; use cosmwasm_std::Coin; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -/// Like [`NameEntry`] but since it's a response type the name is an option depending on if -/// the name exists or not. -#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] -#[serde(rename_all = "snake_case")] -pub struct NameEntryResponse { - pub name_id: NameId, - pub name: Option, -} - #[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct NamesListResponse { - pub names: Vec, + pub names: Vec, } impl NamesListResponse { - pub fn new(names: Vec<(NameId, RegisteredName)>) -> NamesListResponse { - NamesListResponse { - names: names - .into_iter() - .map(|(name_id, name)| NameEntry::new(name_id, name)) - .collect(), - } + pub fn new(names: Vec) -> NamesListResponse { + NamesListResponse { names } } } -impl From<&[NameEntry]> for NamesListResponse { - fn from(names: &[NameEntry]) -> Self { +impl From<&[RegisteredName]> for NamesListResponse { + fn from(names: &[RegisteredName]) -> Self { NamesListResponse { names: names.to_vec(), } @@ -40,21 +26,17 @@ impl From<&[NameEntry]> for NamesListResponse { #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] #[serde(rename_all = "snake_case")] pub struct PagedNamesListResponse { - pub names: Vec, + pub names: Vec, pub per_page: usize, pub start_next_after: Option, } impl PagedNamesListResponse { pub fn new( - names: Vec<(NameId, RegisteredName)>, + names: Vec, per_page: usize, start_next_after: Option, ) -> PagedNamesListResponse { - let names = names - .into_iter() - .map(|(name_id, name)| NameEntry::new(name_id, name)) - .collect(); PagedNamesListResponse { names, per_page, @@ -68,12 +50,3 @@ impl PagedNamesListResponse { pub struct ConfigResponse { pub deposit_required: Coin, } - -impl From for ExecuteMsg { - fn from(name: RegisteredName) -> Self { - ExecuteMsg::Register { - name: name.name, - address: name.address, - } - } -} diff --git a/common/cosmwasm-smart-contracts/name-service/src/signing_types.rs b/common/cosmwasm-smart-contracts/name-service/src/signing_types.rs new file mode 100644 index 0000000000..80a19a7e3d --- /dev/null +++ b/common/cosmwasm-smart-contracts/name-service/src/signing_types.rs @@ -0,0 +1,32 @@ +use cosmwasm_std::{Addr, Coin}; +use nym_contracts_common::signing::{ + ContractMessageContent, MessageType, Nonce, SignableMessage, SigningPurpose, +}; +use serde::Serialize; + +use crate::NameDetails; + +pub type SignableNameRegisterMsg = SignableMessage>; + +#[derive(Serialize)] +pub struct NameRegister { + name: NameDetails, +} + +impl SigningPurpose for NameRegister { + fn message_type() -> MessageType { + MessageType::new("name-register") + } +} + +pub fn construct_name_register_sign_payload( + nonce: Nonce, + sender: Addr, + deposit: Coin, + name: NameDetails, +) -> SignableNameRegisterMsg { + let payload = NameRegister { name }; + let proxy = None; + let content = ContractMessageContent::new(sender, proxy, vec![deposit], payload); + SignableMessage::new(nonce, content) +} diff --git a/common/cosmwasm-smart-contracts/name-service/src/types.rs b/common/cosmwasm-smart-contracts/name-service/src/types.rs index 166e095a2f..dd44340815 100644 --- a/common/cosmwasm-smart-contracts/name-service/src/types.rs +++ b/common/cosmwasm-smart-contracts/name-service/src/types.rs @@ -1,24 +1,48 @@ use std::fmt::{Display, Formatter}; use cosmwasm_std::{Addr, Coin}; +use nym_contracts_common::IdentityKey; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -/// The directory of services are indexed by [`ServiceId`]. +/// The directory of names are indexed by [`NameId`]. pub type NameId = u32; #[derive(Serialize, Deserialize, Clone, PartialEq, Debug, JsonSchema)] pub struct RegisteredName { + /// Unique id assigned to the registerd name. + pub id: NameId, + + /// The registerd name details. + pub name: NameDetails, + + /// name owner. + pub owner: Addr, + + /// Block height at which the name was added. + pub block_height: u64, + + /// The deposit used to announce the name. + pub deposit: Coin, +} + +impl RegisteredName { + // Shortcut for getting the actual name + pub fn entry(&self) -> &NymName { + &self.name.name + } +} + +#[derive(Serialize, Deserialize, Clone, PartialEq, Debug, JsonSchema)] +pub struct NameDetails { /// The name pointing to the nym address pub name: NymName, - /// The address of the service. + + /// The address of the name alias. pub address: Address, - /// Service owner. - pub owner: Addr, - /// Block height at which the service was added. - pub block_height: u64, - /// The deposit used to announce the service. - pub deposit: Coin, + + /// The identity key of the registered name. + pub identity_key: IdentityKey, } /// String representation of a nym address, which is of the form @@ -68,6 +92,7 @@ pub enum NymNameError { InvalidName, } +/// Defines what names are allowed fn is_valid_name_char(c: char) -> bool { // Normal lowercase letters (c.is_alphabetic() && c.is_lowercase()) @@ -98,20 +123,6 @@ impl Display for NymName { } } -/// [`RegisterdName`] together with the assigned [`NameId`]. -#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)] -#[serde(rename_all = "snake_case")] -pub struct NameEntry { - pub name_id: NameId, - pub name: RegisteredName, -} - -impl NameEntry { - pub fn new(name_id: NameId, name: RegisteredName) -> Self { - Self { name_id, name } - } -} - #[cfg(test)] mod tests { use super::NymName; diff --git a/common/cosmwasm-smart-contracts/service-provider-directory/Cargo.toml b/common/cosmwasm-smart-contracts/service-provider-directory/Cargo.toml index 67185a593c..3965734b2d 100644 --- a/common/cosmwasm-smart-contracts/service-provider-directory/Cargo.toml +++ b/common/cosmwasm-smart-contracts/service-provider-directory/Cargo.toml @@ -7,9 +7,9 @@ edition = "2021" [dependencies] cosmwasm-std = { workspace = true } +cw-controllers = { workspace = true } +cw-utils = { workspace = true } nym-contracts-common = { path = "../contracts-common", version = "0.5.0" } schemars = "0.8" serde = { workspace = true, features = ["derive"] } thiserror = { workspace = true } -cw-utils = { workspace = true } -cw-controllers = { workspace = true } diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock index 456b9e013c..1db4c0bd8a 100644 --- a/contracts/Cargo.lock +++ b/contracts/Cargo.lock @@ -1411,6 +1411,7 @@ name = "nym-name-service" version = "0.1.0" dependencies = [ "anyhow", + "bs58", "cosmwasm-std", "cw-controllers", "cw-multi-test", @@ -1418,8 +1419,10 @@ dependencies = [ "cw-utils", "cw2", "nym-contracts-common", + "nym-crypto", "nym-name-service-common", "rand 0.8.5", + "rand_chacha 0.2.2", "rstest", "semver", "serde", @@ -1432,8 +1435,12 @@ name = "nym-name-service-common" version = "0.1.0" dependencies = [ "cosmwasm-std", + "cw-controllers", + "cw-utils", + "nym-contracts-common", "schemars", "serde", + "thiserror", ] [[package]] diff --git a/contracts/name-service/Cargo.toml b/contracts/name-service/Cargo.toml index 7ddb660d56..56fe0145cf 100644 --- a/contracts/name-service/Cargo.toml +++ b/contracts/name-service/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" crate-type = ["cdylib", "rlib"] [dependencies] +bs58 = "0.4.0" cosmwasm-std = { workspace = true } cw-controllers = { workspace = true } cw-storage-plus = { workspace = true } @@ -24,5 +25,7 @@ vergen = { version = "=7.4.3", default-features = false, features = ["build", "g [dev-dependencies] anyhow = "1.0.40" cw-multi-test = { workspace = true } +nym-crypto = { path = "../../common/crypto", features = ["asymmetric", "rand"] } rand = "0.8.5" +rand_chacha = "0.2" rstest = "0.17.0" diff --git a/contracts/name-service/src/constants.rs b/contracts/name-service/src/constants.rs index 6ac0998ae0..0b87f40264 100644 --- a/contracts/name-service/src/constants.rs +++ b/contracts/name-service/src/constants.rs @@ -14,3 +14,5 @@ pub const NAMES_PK_NAMESPACE: &str = "nanames"; pub const NAMES_OWNER_IDX_NAMESPACE: &str = "naowner"; pub const NAMES_ADDRESS_IDX_NAMESPACE: &str = "naaddress"; pub const NAMES_NAME_IDX_NAMESPACE: &str = "naname"; + +pub const SIGNING_NONCES_NAMESPACE: &str = "nasn"; diff --git a/contracts/name-service/src/contract.rs b/contracts/name-service/src/contract.rs index a88d831dc8..f3347c4d6a 100644 --- a/contracts/name-service/src/contract.rs +++ b/contracts/name-service/src/contract.rs @@ -1,6 +1,6 @@ use crate::{ - error::{NameServiceError, Result}, state::{self, Config}, + NameServiceError, Result, }; use cosmwasm_std::{to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response}; use nym_name_service_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; @@ -72,7 +72,10 @@ pub fn execute( msg: ExecuteMsg, ) -> Result { match msg { - ExecuteMsg::Register { name, address } => execute::register(deps, env, info, name, address), + ExecuteMsg::Register { + name, + owner_signature, + } => execute::register(deps, env, info, name, owner_signature), ExecuteMsg::DeleteId { name_id } => execute::delete_id(deps, info, name_id), ExecuteMsg::DeleteName { name } => execute::delete_name(deps, info, name), ExecuteMsg::UpdateDepositRequired { deposit_required } => { @@ -90,6 +93,9 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result { QueryMsg::All { limit, start_after } => { to_binary(&query::query_all_paged(deps, limit, start_after)?) } + QueryMsg::SigningNonce { address } => { + to_binary(&query::query_current_signing_nonce(deps, address)?) + } QueryMsg::Config {} => to_binary(&query::query_config(deps)?), QueryMsg::GetContractVersion {} => to_binary(&query::query_contract_version()), QueryMsg::GetCW2ContractVersion {} => to_binary(&cw2::get_contract_version(deps.storage)?), @@ -102,16 +108,19 @@ mod tests { use super::*; use crate::test_helpers::{ - assert::{assert_config, assert_empty, assert_name, assert_names, assert_not_found}, - fixture::name_fixture, - helpers::{get_attribute, nyms}, + assert::{ + assert_config, assert_current_nonce, assert_empty, assert_name, assert_names, + assert_not_found, + }, + fixture::new_name_details_with_sign, + helpers::{get_attribute, nyms, test_rng}, }; use cosmwasm_std::{ testing::{mock_dependencies, mock_env, mock_info}, Addr, Coin, }; - use nym_name_service_common::{msg::ExecuteMsg, NameEntry, NameId}; + use nym_name_service_common::{msg::ExecuteMsg, NameId, RegisteredName}; const DENOM: &str = "unym"; @@ -135,23 +144,28 @@ mod tests { } #[test] - fn register_fails_incorrect_deposit() { + fn register_fails_deposit_too_small() { + let mut rng = test_rng(); let mut deps = mock_dependencies(); let msg = InstantiateMsg::new(nyms(100)); let info = mock_info("creator", &[]); - let admin = info.sender.clone(); let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap(); assert_eq!(res.messages.len(), 0); - // Register - let msg: ExecuteMsg = name_fixture().into(); - let owner = name_fixture().owner.to_string(); + let deposit = nyms(99); + let owner = "steve"; + let (name, owner_signature) = + new_name_details_with_sign(deps.as_mut(), &mut rng, "foo", "address", owner, deposit); + let msg = ExecuteMsg::Register { + name, + owner_signature, + }; assert_eq!( execute( deps.as_mut(), mock_env(), - mock_info(&owner, &[nyms(99)]), + mock_info(owner, &[nyms(99)]), msg.clone() ) .unwrap_err(), @@ -161,34 +175,135 @@ mod tests { } ); + // Since we signed for 99unym deposit. assert_eq!( execute( deps.as_mut(), mock_env(), - mock_info(&owner, &[nyms(101)]), + mock_info(owner, &[nyms(100)]), msg ) .unwrap_err(), + NameServiceError::InvalidEd25519Signature, + ); + } + + #[test] + fn register_fails_deposit_too_large() { + let mut rng = test_rng(); + let mut deps = mock_dependencies(); + let msg = InstantiateMsg::new(nyms(100)); + let info = mock_info("creator", &[]); + let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap(); + assert_eq!(res.messages.len(), 0); + + let deposit = nyms(101); + let owner = "steve"; + let (name, owner_signature) = + new_name_details_with_sign(deps.as_mut(), &mut rng, "foo", "address", owner, deposit); + let msg = ExecuteMsg::Register { + name, + owner_signature, + }; + + assert_eq!( + execute( + deps.as_mut(), + mock_env(), + mock_info(owner, &[nyms(101)]), + msg.clone() + ) + .unwrap_err(), NameServiceError::TooLargeDeposit { funds: 101u128.into(), deposit_required: 100u128.into(), } ); - assert_config(deps.as_ref(), &admin, Coin::new(100, DENOM)); - assert_empty(deps.as_ref()); + // Since we signed for 101unym deposit. + assert_eq!( + execute( + deps.as_mut(), + mock_env(), + mock_info(owner, &[nyms(100)]), + msg + ) + .unwrap_err(), + NameServiceError::InvalidEd25519Signature, + ); } #[test] - fn register_success() { + fn register_fails_owner_mismatch() { + let mut rng = test_rng(); let mut deps = mock_dependencies(); let msg = InstantiateMsg::new(nyms(100)); let info = mock_info("creator", &[]); let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap(); assert_eq!(res.messages.len(), 0); + // Setup + let deposit = nyms(100); + let owner = "steve"; + let (name, owner_signature) = new_name_details_with_sign( + deps.as_mut(), + &mut rng, + "my-name", + "my-address", + owner, + deposit, + ); + // Register - let msg: ExecuteMsg = name_fixture().into(); + let msg = ExecuteMsg::Register { + name, + owner_signature, + }; + assert_eq!( + execute( + deps.as_mut(), + mock_env(), + mock_info("timmy", &[nyms(100)]), + msg.clone(), + ) + .unwrap_err(), + NameServiceError::InvalidEd25519Signature, + ); + assert!(execute( + deps.as_mut(), + mock_env(), + mock_info("steve", &[nyms(100)]), + msg + ) + .is_ok()); + } + + #[test] + fn register_success() { + let mut rng = test_rng(); + let mut deps = mock_dependencies(); + let msg = InstantiateMsg::new(nyms(100)); + let info = mock_info("creator", &[]); + let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap(); + assert_eq!(res.messages.len(), 0); + + // Setup + let deposit = nyms(100); + let owner = "steve"; + let (name, owner_signature) = new_name_details_with_sign( + deps.as_mut(), + &mut rng, + "my-name", + "my-address", + owner, + deposit.clone(), + ); + + // Register + let msg = ExecuteMsg::Register { + name: name.clone(), + owner_signature, + }; let info = mock_info("steve", &[nyms(100)]); let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap(); @@ -198,17 +313,24 @@ mod tests { assert_eq!(id, expected_id); assert_eq!( get_attribute(&res, "register", "name"), - "my-service".to_string() + "my-name".to_string() ); assert_eq!( get_attribute(&res, "register", "nym_address"), - "client_id.client_key@gateway_id".to_string() + "my-address".to_string() ); + // Check that the nonce has been incremented, but only for the owner + assert_current_nonce(deps.as_ref(), &Addr::unchecked("steve"), 1); + assert_current_nonce(deps.as_ref(), &Addr::unchecked("timmy"), 0); + // The expected registered name - let expected_name = NameEntry { - name_id: expected_id, - name: name_fixture(), + let expected_name = RegisteredName { + id: expected_id, + name, + owner: Addr::unchecked(owner), + block_height: 12345, + deposit, }; assert_names(deps.as_ref(), &[expected_name.clone()]); assert_name(deps.as_ref(), &expected_name); @@ -216,6 +338,7 @@ mod tests { #[test] fn delete() { + let mut rng = test_rng(); let mut deps = mock_dependencies(); let msg = InstantiateMsg::new(Coin::new(100, "unym")); let info = mock_info("creator", &[]); @@ -223,16 +346,31 @@ mod tests { assert_eq!(res.messages.len(), 0); // Register - let msg: ExecuteMsg = name_fixture().into(); + let deposit = nyms(100); + let steve = "steve"; + let (name, owner_signature) = new_name_details_with_sign( + deps.as_mut(), + &mut rng, + "my-name", + "my-address", + steve, + deposit.clone(), + ); + let msg = ExecuteMsg::Register { + name: name.clone(), + owner_signature, + }; let info_steve = mock_info("steve", &[nyms(100)]); - assert_eq!(info_steve.sender, name_fixture().owner); - execute(deps.as_mut(), mock_env(), info_steve, msg).unwrap(); + execute(deps.as_mut(), mock_env(), info_steve.clone(), msg).unwrap(); // The expected registerd name let expected_id = 1; - let expected_name = NameEntry { - name_id: expected_id, - name: name_fixture(), + let expected_name = RegisteredName { + id: expected_id, + name, + owner: Addr::unchecked(steve), + block_height: 12345, + deposit, }; assert_names(deps.as_ref(), &[expected_name]); @@ -248,12 +386,8 @@ mod tests { // Removing an non-existent name will fail let msg = ExecuteMsg::delete_id(expected_id + 1); - let info_owner = MessageInfo { - sender: name_fixture().owner, - funds: vec![], - }; assert_eq!( - execute(deps.as_mut(), mock_env(), info_owner.clone(), msg).unwrap_err(), + execute(deps.as_mut(), mock_env(), info_steve.clone(), msg).unwrap_err(), NameServiceError::NotFound { name_id: expected_id + 1 } @@ -261,7 +395,7 @@ mod tests { // Remove as correct owner succeeds let msg = ExecuteMsg::delete_id(expected_id); - let res = execute(deps.as_mut(), mock_env(), info_owner, msg).unwrap(); + let res = execute(deps.as_mut(), mock_env(), info_steve, msg).unwrap(); assert_eq!( get_attribute(&res, "delete_id", "name_id"), expected_id.to_string() diff --git a/contracts/name-service/src/contract/execute.rs b/contracts/name-service/src/contract/execute.rs index a7396c1229..e41e57d7f4 100644 --- a/contracts/name-service/src/contract/execute.rs +++ b/contracts/name-service/src/contract/execute.rs @@ -1,15 +1,19 @@ use crate::{ constants::{MAX_NUMBER_OF_NAMES_FOR_ADDRESS, MAX_NUMBER_OF_NAMES_PER_OWNER}, - error::{NameServiceError, Result}, - state, + state, NameServiceError, Result, }; use cosmwasm_std::{Addr, BankMsg, Coin, Deps, DepsMut, Env, MessageInfo, Response, Uint128}; +use nym_contracts_common::{ + signing::{MessageSignature, Verifier}, + IdentityKey, +}; use nym_name_service_common::{ events::{ new_delete_id_event, new_delete_name_event, new_register_event, new_update_deposit_required_event, }, - Address, NameId, NymName, RegisteredName, + signing_types::construct_name_register_sign_payload, + Address, NameDetails, NameId, NymName, RegisteredName, }; use super::query; @@ -86,17 +90,54 @@ fn return_deposit(name_to_delete: &RegisteredName) -> BankMsg { } } +fn verify_register_signature( + deps: Deps<'_>, + sender: Addr, + deposit: Coin, + name: NameDetails, + signature: MessageSignature, +) -> Result<()> { + // recover the public key + let public_key = decode_ed25519_identity_key(&name.identity_key)?; + + // reconstruct the payload + let nonce = state::get_signing_nonce(deps.storage, sender.clone())?; + + let msg = construct_name_register_sign_payload(nonce, sender, deposit, name); + + if deps.api.verify_message(msg, signature, &public_key)? { + Ok(()) + } else { + Err(NameServiceError::InvalidEd25519Signature) + } +} + +fn decode_ed25519_identity_key(encoded: &IdentityKey) -> Result<[u8; 32]> { + let mut public_key = [0u8; 32]; + let used = bs58::decode(encoded) + .into(&mut public_key) + .map_err(|err| NameServiceError::MalformedEd25519IdentityKey(err.to_string()))?; + + if used != 32 { + return Err(NameServiceError::MalformedEd25519IdentityKey( + "Too few bytes provided for the public key".into(), + )); + } + + Ok(public_key) +} + /// Register a new name. It will be assigned a new name id. pub fn register( deps: DepsMut, env: Env, info: MessageInfo, - name: NymName, - address: Address, + name: NameDetails, + owner_signature: MessageSignature, ) -> Result { - ensure_name_not_exists(deps.as_ref(), &name)?; + ensure_name_not_exists(deps.as_ref(), &name.name)?; ensure_max_names_per_owner(deps.as_ref(), info.sender.clone())?; - ensure_max_names_per_address(deps.as_ref(), address.clone())?; + ensure_max_names_per_address(deps.as_ref(), name.address.clone())?; let deposit_required = state::deposit_required(deps.storage)?; let denom = deposit_required.denom.clone(); @@ -104,16 +145,29 @@ pub fn register( .map_err(|err| NameServiceError::DepositRequired { source: err })?; ensure_correct_deposit(will_deposit, deposit_required.amount)?; + let deposit = Coin::new(will_deposit.u128(), denom); + + verify_register_signature( + deps.as_ref(), + info.sender.clone(), + deposit.clone(), + name.clone(), + owner_signature, + )?; + + state::increment_signing_nonce(deps.storage, info.sender.clone())?; + + let id = state::next_name_id_counter(deps.storage)?; let new_name = RegisteredName { - address, + id, name, owner: info.sender, block_height: env.block.height, - deposit: Coin::new(will_deposit.u128(), denom), + deposit, }; - let name_id = state::names::save(deps.storage, &new_name)?; + state::names::save(deps.storage, &new_name)?; - Ok(Response::new().add_event(new_register_event(name_id, new_name))) + Ok(Response::new().add_event(new_register_event(new_name))) } /// Delete an exsisting name. @@ -127,23 +181,20 @@ pub fn delete_id(deps: DepsMut, info: MessageInfo, name_id: NameId) -> Result Result { let name_to_delete = query::query_name(deps.as_ref(), name)?; - ensure_sender_authorized(info, &name_to_delete.name)?; + ensure_sender_authorized(info, &name_to_delete)?; - state::names::remove_id(deps.storage, name_to_delete.name_id)?; - let return_deposit_msg = return_deposit(&name_to_delete.name); + state::names::remove_id(deps.storage, name_to_delete.id)?; + let return_deposit_msg = return_deposit(&name_to_delete); Ok(Response::new() .add_message(return_deposit_msg) - .add_event(new_delete_name_event( - name_to_delete.name_id, - name_to_delete.name, - ))) + .add_event(new_delete_name_event(name_to_delete))) } /// Update the deposit required to register new names diff --git a/contracts/name-service/src/contract/query.rs b/contracts/name-service/src/contract/query.rs index 0ba8355e96..29b7b4b057 100644 --- a/contracts/name-service/src/contract/query.rs +++ b/contracts/name-service/src/contract/query.rs @@ -1,18 +1,17 @@ use cosmwasm_std::Deps; -use nym_contracts_common::ContractBuildInformation; +use nym_contracts_common::{signing::Nonce, ContractBuildInformation}; use nym_name_service_common::{ response::{ConfigResponse, NamesListResponse, PagedNamesListResponse}, - Address, NameEntry, NameId, NymName, + Address, NameId, NymName, RegisteredName, }; use crate::{ - error::Result, state::{self, names::PagedLoad}, + Result, }; -pub fn query_id(deps: Deps, name_id: NameId) -> Result { - let name = state::names::load_id(deps.storage, name_id)?; - Ok(NameEntry { name_id, name }) +pub fn query_id(deps: Deps, name_id: NameId) -> Result { + state::names::load_id(deps.storage, name_id) } pub fn query_owner(deps: Deps, owner: String) -> Result { @@ -26,9 +25,8 @@ pub fn query_address(deps: Deps, address: Address) -> Result Ok(NamesListResponse::new(names)) } -pub fn query_name(deps: Deps, name: NymName) -> Result { - state::names::load_name_entry(deps.storage, &name) - .map(|(name_id, name)| NameEntry::new(name_id, name)) +pub fn query_name(deps: Deps, name: NymName) -> Result { + state::names::load_name(deps.storage, &name) } pub fn query_all_paged( @@ -44,6 +42,11 @@ pub fn query_all_paged( Ok(PagedNamesListResponse::new(names, limit, start_next_after)) } +pub fn query_current_signing_nonce(deps: Deps<'_>, address: String) -> Result { + let address = deps.api.addr_validate(&address)?; + state::get_signing_nonce(deps.storage, address) +} + pub fn query_config(deps: Deps) -> Result { let config = state::load_config(deps.storage)?; Ok(config.into()) diff --git a/contracts/name-service/src/integration_tests.rs b/contracts/name-service/src/integration_tests.rs deleted file mode 100644 index b7e68ffdc8..0000000000 --- a/contracts/name-service/src/integration_tests.rs +++ /dev/null @@ -1,445 +0,0 @@ -//! Integration tests using cw-multi-test. - -use cosmwasm_std::Addr; -use nym_name_service_common::{ - response::{ConfigResponse, PagedNamesListResponse}, - Address, NameEntry, NymName, RegisteredName, -}; - -use crate::{ - constants::NAME_DEFAULT_RETRIEVAL_LIMIT, - error::NameServiceError, - test_helpers::{fixture::name_entry, helpers::nyms, test_setup::TestSetup}, -}; - -#[test] -fn instantiate_contract() { - TestSetup::new(); -} - -#[test] -fn query_config() { - assert_eq!( - TestSetup::new().query_config(), - ConfigResponse { - deposit_required: nyms(100), - } - ); -} - -#[test] -fn register_and_query_name() { - let mut setup = TestSetup::new(); - assert_eq!( - setup.query_all(), - PagedNamesListResponse { - names: vec![], - per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, - start_next_after: None, - } - ); - - // Register a first name - let owner = Addr::unchecked("owner"); - let name = NymName::new("steves-server").unwrap(); - let nym_address = Address::new("nym-address"); - assert_eq!(setup.contract_balance(), nyms(0)); - assert_eq!(setup.balance(&owner), nyms(250)); - setup.register(name.clone(), nym_address.clone(), owner.clone()); - - // Deposit is deposited to contract and deducted from owners's balance - assert_eq!(setup.contract_balance(), nyms(100)); - assert_eq!(setup.balance(&owner), nyms(150)); - - // We can query the full name list - assert_eq!( - setup.query_all(), - PagedNamesListResponse { - names: vec![NameEntry { - name_id: 1, - name: RegisteredName { - address: nym_address.clone(), - name: name.clone(), - owner: owner.clone(), - block_height: 12345, - deposit: nyms(100), - }, - }], - per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, - start_next_after: Some(1), - } - ); - - // ... and we can query by id - assert_eq!( - setup.query_id(1), - NameEntry { - name_id: 1, - name: RegisteredName { - address: nym_address.clone(), - name: name.clone(), - owner: owner.clone(), - block_height: 12345, - deposit: nyms(100), - }, - } - ); - - // Register a second name - let owner2 = Addr::unchecked("owner2"); - let name2 = NymName::new("another_server").unwrap(); - let nym_address2 = Address::new("nymAddress2"); - setup.register(name2.clone(), nym_address2.clone(), owner2.clone()); - - assert_eq!(setup.contract_balance(), nyms(200)); - assert_eq!( - setup.query_all(), - PagedNamesListResponse { - names: vec![ - name_entry(1, name, nym_address, owner), - name_entry(2, name2, nym_address2, owner2) - ], - per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, - start_next_after: Some(2), - } - ); -} - -#[test] -fn cant_register_a_name_without_funds() { - let mut setup = TestSetup::new(); - assert_eq!(setup.contract_balance(), nyms(0)); - assert_eq!(setup.balance("owner"), nyms(250)); - setup.register( - NymName::new("my_name").unwrap(), - Address::new("nymAddress"), - Addr::unchecked("owner"), - ); - assert_eq!(setup.contract_balance(), nyms(100)); - assert_eq!(setup.balance("owner"), nyms(150)); - setup.register( - NymName::new("my_name2").unwrap(), - Address::new("nymAddress"), - Addr::unchecked("owner"), - ); - assert_eq!(setup.contract_balance(), nyms(200)); - assert_eq!(setup.balance("owner"), nyms(50)); - let res = setup - .try_register( - NymName::new("my_name3").unwrap(), - Address::new("nymAddress"), - Addr::unchecked("owner"), - ) - .unwrap_err(); - assert_eq!( - res.downcast::().unwrap(), - cosmwasm_std::StdError::Overflow { - source: cosmwasm_std::OverflowError::new( - cosmwasm_std::OverflowOperation::Sub, - "50", - "100" - ) - } - ); -} - -#[test] -fn delete_name() { - let mut setup = TestSetup::new(); - setup.register( - NymName::new("my_name").unwrap(), - Address::new("nymAddress"), - Addr::unchecked("owner"), - ); - assert_eq!(setup.contract_balance(), nyms(100)); - assert_eq!(setup.balance("owner"), nyms(150)); - assert!(!setup.query_all().names.is_empty()); - setup.delete(1, Addr::unchecked("owner")); - - // Deleting the name returns the deposit to the owner - assert_eq!(setup.contract_balance(), nyms(0)); - assert_eq!(setup.balance("owner"), nyms(250)); - assert!(setup.query_all().names.is_empty()); -} - -#[test] -fn only_owner_can_delete_name() { - let mut setup = TestSetup::new(); - assert_eq!(setup.contract_balance(), nyms(0)); - setup.register( - NymName::new("name").unwrap(), - Address::new("nymAddress"), - Addr::unchecked("owner"), - ); - assert_eq!(setup.contract_balance(), nyms(100)); - assert!(!setup.query_all().names.is_empty()); - - let delete_resp = setup - .try_delete(1, Addr::unchecked("not_owner")) - .unwrap_err(); - - assert_eq!(setup.contract_balance(), nyms(100)); - assert_eq!( - delete_resp.downcast::().unwrap(), - NameServiceError::Unauthorized { - sender: Addr::unchecked("not_owner") - } - ); -} - -#[test] -fn cant_delete_name_that_does_not_exist() { - let mut setup = TestSetup::new(); - setup.register( - NymName::new("foo").unwrap(), - Address::new("nymAddress"), - Addr::unchecked("owner"), - ); - assert_eq!(setup.contract_balance(), nyms(100)); - assert!(!setup.query_all().names.is_empty()); - - let delete_resp = setup.try_delete(0, Addr::unchecked("owner")).unwrap_err(); - assert_eq!(setup.contract_balance(), nyms(100)); - assert_eq!( - delete_resp.downcast::().unwrap(), - NameServiceError::NotFound { name_id: 0 } - ); - - let delete_resp = setup.try_delete(2, Addr::unchecked("owner")).unwrap_err(); - assert_eq!(setup.contract_balance(), nyms(100)); - assert_eq!( - delete_resp.downcast::().unwrap(), - NameServiceError::NotFound { name_id: 2 } - ); - - assert!(!setup.query_all().names.is_empty()); - setup.delete(1, Addr::unchecked("owner")); - assert_eq!(setup.contract_balance(), nyms(0)); - assert!(setup.query_all().names.is_empty()); -} - -#[test] -fn cant_register_the_same_name_multiple_times() { - let mut setup = TestSetup::new(); - - setup.register( - NymName::new("name").unwrap(), - Address::new("nymAddress"), - Addr::unchecked("owner"), - ); - let resp = setup - .try_register( - NymName::new("name").unwrap(), - Address::new("nymAddress"), - Addr::unchecked("owner"), - ) - .unwrap_err(); - - assert_eq!( - resp.downcast::().unwrap(), - NameServiceError::NameAlreadyRegistered { - name: NymName::new("name").unwrap() - } - ); -} - -#[test] -fn can_register_multiple_names_for_the_same_nym_address() { - let mut setup = TestSetup::new(); - let name1 = NymName::new("name1").unwrap(); - let name2 = NymName::new("name2").unwrap(); - let address = Address::new("nymaddress"); - let owner = Addr::unchecked("owner"); - - setup.register(name1.clone(), address.clone(), owner.clone()); - setup.register(name2.clone(), address.clone(), owner.clone()); - - assert_eq!( - setup.query_all().names, - vec![ - name_entry(1, name1, address.clone(), owner.clone()), - name_entry(2, name2, address, owner) - ], - ); -} - -#[test] -fn register_multiple_names_and_deleting_by_name() { - let mut setup = TestSetup::new(); - let owner1 = Addr::unchecked("wealthy_owner_1"); - let owner2 = Addr::unchecked("wealthy_owner_2"); - let nym_address1 = Address::new("nymaddress1"); - let nym_address2 = Address::new("nymaddress2"); - let name1 = NymName::new("name1").unwrap(); - let name2 = NymName::new("name2").unwrap(); - let name3 = NymName::new("name3").unwrap(); - let name4 = NymName::new("name4").unwrap(); - let name5 = NymName::new("name5").unwrap(); - - // We register the same address three times, but with different owners - assert_eq!(setup.contract_balance(), nyms(0)); - assert_eq!(setup.balance(&owner1), nyms(1000)); - setup.register(name1.clone(), nym_address1.clone(), owner1.clone()); - setup.register(name2.clone(), nym_address1.clone(), owner1.clone()); - setup.register(name3.clone(), nym_address2.clone(), owner1.clone()); - setup.register(name4.clone(), nym_address1.clone(), owner2.clone()); - setup.register(name5.clone(), nym_address2.clone(), owner2.clone()); - - assert_eq!(setup.contract_balance(), nyms(500)); - assert_eq!(setup.balance(&owner1), nyms(700)); - assert_eq!( - setup.query_all(), - PagedNamesListResponse { - names: vec![ - name_entry(1, name1.clone(), nym_address1.clone(), owner1.clone()), - name_entry(2, name2.clone(), nym_address1.clone(), owner1.clone()), - name_entry(3, name3.clone(), nym_address2.clone(), owner1.clone()), - name_entry(4, name4.clone(), nym_address1.clone(), owner2.clone()), - name_entry(5, name5.clone(), nym_address2.clone(), owner2.clone()), - ], - per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, - start_next_after: Some(5), - } - ); - - setup.delete_name(name1, owner1.clone()); - - assert_eq!(setup.contract_balance(), nyms(400)); - assert_eq!(setup.balance(&owner1), nyms(800)); - assert_eq!( - setup.query_all(), - PagedNamesListResponse { - names: vec![ - name_entry(2, name2, nym_address1.clone(), owner1.clone()), - name_entry(3, name3, nym_address2.clone(), owner1), - name_entry(4, name4, nym_address1, owner2.clone()), - name_entry(5, name5, nym_address2, owner2), - ], - per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, - start_next_after: Some(5), - } - ); -} - -#[test] -fn check_paging() { - let mut setup = TestSetup::new(); - let owner1 = Addr::unchecked("wealthy_owner_1"); - let owner2 = Addr::unchecked("wealthy_owner_2"); - let nym_address1 = Address::new("nymAddress1"); - let nym_address2 = Address::new("nymAddress2"); - let name1 = NymName::new("name1").unwrap(); - let name2 = NymName::new("name2").unwrap(); - let name3 = NymName::new("name3").unwrap(); - let name4 = NymName::new("name4").unwrap(); - let name5 = NymName::new("name5").unwrap(); - - // We register the same address three times, but with different owners - assert_eq!(setup.contract_balance(), nyms(0)); - assert_eq!(setup.balance(&owner1), nyms(1000)); - setup.register(name1.clone(), nym_address1.clone(), owner1.clone()); - setup.register(name2.clone(), nym_address1.clone(), owner1.clone()); - setup.register(name3.clone(), nym_address2.clone(), owner1.clone()); - setup.register(name4.clone(), nym_address1.clone(), owner2.clone()); - setup.register(name5.clone(), nym_address2.clone(), owner2.clone()); - - assert_eq!(setup.contract_balance(), nyms(500)); - assert_eq!(setup.balance(&owner1), nyms(700)); - assert_eq!( - setup.query_all(), - PagedNamesListResponse { - names: vec![ - name_entry(1, name1.clone(), nym_address1.clone(), owner1.clone()), - name_entry(2, name2.clone(), nym_address1.clone(), owner1.clone()), - name_entry(3, name3.clone(), nym_address2.clone(), owner1.clone()), - name_entry(4, name4.clone(), nym_address1.clone(), owner2.clone()), - name_entry(5, name5, nym_address2.clone(), owner2.clone()), - ], - per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, - start_next_after: Some(5), - } - ); - - setup.delete_name(name1, owner1.clone()); - - assert_eq!( - setup.query_all_with_limit(Some(2), None), - PagedNamesListResponse { - names: vec![ - name_entry(2, name2, nym_address1.clone(), owner1.clone()), - name_entry(3, name3.clone(), nym_address2.clone(), owner1.clone()), - ], - per_page: 2, - start_next_after: Some(3), - } - ); - - assert_eq!( - setup.query_all_with_limit(Some(2), Some(2)), - PagedNamesListResponse { - names: vec![ - name_entry(3, name3, nym_address2, owner1), - name_entry(4, name4, nym_address1, owner2), - ], - per_page: 2, - start_next_after: Some(4), - } - ); -} - -#[test] -fn name_id_is_not_resused_when_deleting_and_then_adding_a_new_names() { - let mut setup = TestSetup::new(); - setup.register( - NymName::new("myname1").unwrap(), - Address::new("nymAddress1"), - Addr::unchecked("owner1"), - ); - setup.register( - NymName::new("myname2").unwrap(), - Address::new("nymAddress2"), - Addr::unchecked("owner2"), - ); - setup.register( - NymName::new("myname3").unwrap(), - Address::new("nymAddress3"), - Addr::unchecked("owner3"), - ); - - setup.delete(1, Addr::unchecked("owner1")); - setup.delete(3, Addr::unchecked("owner3")); - - assert_eq!( - setup.query_all().names, - vec![name_entry( - 2, - NymName::new("myname2").unwrap(), - Address::new("nymAddress2"), - Addr::unchecked("owner2") - )] - ); - - setup.register( - NymName::new("myname4").unwrap(), - Address::new("nymAddress4"), - Addr::unchecked("owner4"), - ); - - assert_eq!( - setup.query_all().names, - vec![ - name_entry( - 2, - NymName::new("myname2").unwrap(), - Address::new("nymAddress2"), - Addr::unchecked("owner2") - ), - name_entry( - 4, - NymName::new("myname4").unwrap(), - Address::new("nymAddress4"), - Addr::unchecked("owner4") - ) - ] - ); -} diff --git a/contracts/name-service/src/integration_tests/delete.rs b/contracts/name-service/src/integration_tests/delete.rs new file mode 100644 index 0000000000..feede51739 --- /dev/null +++ b/contracts/name-service/src/integration_tests/delete.rs @@ -0,0 +1,148 @@ +use cosmwasm_std::Addr; +use nym_name_service_common::{response::PagedNamesListResponse, Address, NymName}; +use rstest::rstest; + +use crate::{ + constants::NAME_DEFAULT_RETRIEVAL_LIMIT, + test_helpers::{fixture::new_name, helpers::nyms}, + NameServiceError, +}; + +use super::test_setup::TestSetup; + +#[rstest::fixture] +fn setup() -> TestSetup { + TestSetup::new() +} + +#[rstest] +fn delete_name(mut setup: TestSetup) { + setup.sign_and_register( + &NymName::new("my_name").unwrap(), + &Address::new("address"), + &Addr::unchecked("owner"), + &nyms(100), + ); + assert_eq!(setup.contract_balance(), nyms(100)); + assert_eq!(setup.balance("owner"), nyms(150)); + assert!(!setup.query_all().names.is_empty()); + setup.delete(1, Addr::unchecked("owner")); + + // Deleting the name returns the deposit to the owner + assert_eq!(setup.contract_balance(), nyms(0)); + assert_eq!(setup.balance("owner"), nyms(250)); + assert!(setup.query_all().names.is_empty()); +} + +#[rstest] +fn only_owner_can_delete_name(mut setup: TestSetup) { + assert_eq!(setup.contract_balance(), nyms(0)); + setup.sign_and_register( + &NymName::new("name").unwrap(), + &Address::new("nymAddress"), + &Addr::unchecked("owner"), + &nyms(100), + ); + assert_eq!(setup.contract_balance(), nyms(100)); + assert!(!setup.query_all().names.is_empty()); + + let delete_resp = setup + .try_delete(1, Addr::unchecked("not_owner")) + .unwrap_err(); + + assert_eq!(setup.contract_balance(), nyms(100)); + assert_eq!( + delete_resp.downcast::().unwrap(), + NameServiceError::Unauthorized { + sender: Addr::unchecked("not_owner") + } + ); +} + +#[rstest] +fn cant_delete_name_that_does_not_exist(mut setup: TestSetup) { + setup.sign_and_register( + &NymName::new("foo").unwrap(), + &Address::new("nymAddress"), + &Addr::unchecked("owner"), + &nyms(100), + ); + assert_eq!(setup.contract_balance(), nyms(100)); + assert!(!setup.query_all().names.is_empty()); + + let delete_resp = setup.try_delete(0, Addr::unchecked("owner")).unwrap_err(); + assert_eq!(setup.contract_balance(), nyms(100)); + assert_eq!( + delete_resp.downcast::().unwrap(), + NameServiceError::NotFound { name_id: 0 } + ); + + let delete_resp = setup.try_delete(2, Addr::unchecked("owner")).unwrap_err(); + assert_eq!(setup.contract_balance(), nyms(100)); + assert_eq!( + delete_resp.downcast::().unwrap(), + NameServiceError::NotFound { name_id: 2 } + ); + + assert!(!setup.query_all().names.is_empty()); + setup.delete(1, Addr::unchecked("owner")); + assert_eq!(setup.contract_balance(), nyms(0)); + assert!(setup.query_all().names.is_empty()); +} + +#[rstest] +fn register_multiple_names_and_deleting_by_name(mut setup: TestSetup) { + let owner1 = Addr::unchecked("wealthy_owner_1"); + let owner2 = Addr::unchecked("wealthy_owner_2"); + let address1 = Address::new("address1"); + let address2 = Address::new("address2"); + let name1 = NymName::new("name1").unwrap(); + let name2 = NymName::new("name2").unwrap(); + let name3 = NymName::new("name3").unwrap(); + let name4 = NymName::new("name4").unwrap(); + let name5 = NymName::new("name5").unwrap(); + + // We register the same address three times, but with different owners + assert_eq!(setup.contract_balance(), nyms(0)); + assert_eq!(setup.balance(&owner1), nyms(1000)); + let s1 = setup.sign_and_register(&name1, &address1, &owner1, &nyms(100)); + let s2 = setup.sign_and_register(&name2, &address1, &owner1, &nyms(100)); + let s3 = setup.sign_and_register(&name3, &address2, &owner1, &nyms(100)); + let s4 = setup.sign_and_register(&name4, &address1, &owner2, &nyms(100)); + let s5 = setup.sign_and_register(&name5, &address2, &owner2, &nyms(100)); + + assert_eq!(setup.contract_balance(), nyms(500)); + assert_eq!(setup.balance(&owner1), nyms(700)); + assert_eq!( + setup.query_all(), + PagedNamesListResponse { + names: vec![ + new_name(1, &name1, &address1, &owner1, s1.identity_key()), + new_name(2, &name2, &address1, &owner1, s2.identity_key()), + new_name(3, &name3, &address2, &owner1, s3.identity_key()), + new_name(4, &name4, &address1, &owner2, s4.identity_key()), + new_name(5, &name5, &address2, &owner2, s5.identity_key()), + ], + per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, + start_next_after: Some(5), + } + ); + + setup.delete_name(name1, owner1.clone()); + + assert_eq!(setup.contract_balance(), nyms(400)); + assert_eq!(setup.balance(&owner1), nyms(800)); + assert_eq!( + setup.query_all(), + PagedNamesListResponse { + names: vec![ + new_name(2, &name2, &address1, &owner1, s2.identity_key()), + new_name(3, &name3, &address2, &owner1, s3.identity_key()), + new_name(4, &name4, &address1, &owner2, s4.identity_key()), + new_name(5, &name5, &address2, &owner2, s5.identity_key()), + ], + per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, + start_next_after: Some(5), + } + ); +} diff --git a/contracts/name-service/src/integration_tests/mod.rs b/contracts/name-service/src/integration_tests/mod.rs new file mode 100644 index 0000000000..28905d63c4 --- /dev/null +++ b/contracts/name-service/src/integration_tests/mod.rs @@ -0,0 +1,13 @@ +//! Integration tests using cw-multi-test. + +mod delete; +mod name_id; +mod query; +mod register; +mod test_name; +mod test_setup; + +#[test] +fn instantiate_contract() { + test_setup::TestSetup::new(); +} diff --git a/contracts/name-service/src/integration_tests/name_id.rs b/contracts/name-service/src/integration_tests/name_id.rs new file mode 100644 index 0000000000..39f5a993cf --- /dev/null +++ b/contracts/name-service/src/integration_tests/name_id.rs @@ -0,0 +1,70 @@ +use cosmwasm_std::Addr; +use nym_name_service_common::{Address, NymName}; + +use crate::test_helpers::{fixture::new_name, helpers::nyms}; + +use super::test_setup::TestSetup; + +#[test] +fn name_id_is_not_resused_when_deleting_and_then_adding_a_new_names() { + let mut setup = TestSetup::new(); + setup.sign_and_register( + &NymName::new("myname1").unwrap(), + &Address::new("nymAddress1"), + &Addr::unchecked("owner1"), + &nyms(100), + ); + let s2 = setup.sign_and_register( + &NymName::new("myname2").unwrap(), + &Address::new("nymAddress2"), + &Addr::unchecked("owner2"), + &nyms(100), + ); + setup.sign_and_register( + &NymName::new("myname3").unwrap(), + &Address::new("nymAddress3"), + &Addr::unchecked("owner3"), + &nyms(100), + ); + + setup.delete(1, Addr::unchecked("owner1")); + setup.delete(3, Addr::unchecked("owner3")); + + assert_eq!( + setup.query_all().names, + vec![new_name( + 2, + &NymName::new("myname2").unwrap(), + &Address::new("nymAddress2"), + &Addr::unchecked("owner2"), + s2.identity_key(), + )] + ); + + let s4 = setup.sign_and_register( + &NymName::new("myname4").unwrap(), + &Address::new("nymAddress4"), + &Addr::unchecked("owner4"), + &nyms(100), + ); + + assert_eq!( + setup.query_all().names, + vec![ + new_name( + 2, + &NymName::new("myname2").unwrap(), + &Address::new("nymAddress2"), + &Addr::unchecked("owner2"), + s2.identity_key(), + ), + new_name( + 4, + &NymName::new("myname4").unwrap(), + &Address::new("nymAddress4"), + &Addr::unchecked("owner4"), + s4.identity_key(), + ) + ] + ); +} diff --git a/contracts/name-service/src/integration_tests/query.rs b/contracts/name-service/src/integration_tests/query.rs new file mode 100644 index 0000000000..67069a0a1d --- /dev/null +++ b/contracts/name-service/src/integration_tests/query.rs @@ -0,0 +1,88 @@ +use cosmwasm_std::Addr; +use nym_name_service_common::{ + response::{ConfigResponse, PagedNamesListResponse}, + Address, NymName, +}; + +use crate::{ + constants::NAME_DEFAULT_RETRIEVAL_LIMIT, + test_helpers::{fixture::new_name, helpers::nyms}, +}; + +use super::test_setup::TestSetup; + +#[test] +fn query_config() { + assert_eq!( + TestSetup::new().query_config(), + ConfigResponse { + deposit_required: nyms(100), + } + ); +} + +#[test] +fn check_paging() { + let mut setup = TestSetup::new(); + let owner1 = Addr::unchecked("wealthy_owner_1"); + let owner2 = Addr::unchecked("wealthy_owner_2"); + let address1 = Address::new("nymAddress1"); + let address2 = Address::new("nymAddress2"); + let name1 = NymName::new("name1").unwrap(); + let name2 = NymName::new("name2").unwrap(); + let name3 = NymName::new("name3").unwrap(); + let name4 = NymName::new("name4").unwrap(); + let name5 = NymName::new("name5").unwrap(); + + // We register the same address three times, but with different owners + assert_eq!(setup.contract_balance(), nyms(0)); + assert_eq!(setup.balance(&owner1), nyms(1000)); + let s1 = setup.sign_and_register(&name1, &address1, &owner1, &nyms(100)); + let s2 = setup.sign_and_register(&name2, &address1, &owner1, &nyms(100)); + let s3 = setup.sign_and_register(&name3, &address2, &owner1, &nyms(100)); + let s4 = setup.sign_and_register(&name4, &address1, &owner2, &nyms(100)); + let s5 = setup.sign_and_register(&name5, &address2, &owner2, &nyms(100)); + + assert_eq!(setup.contract_balance(), nyms(500)); + assert_eq!(setup.balance(&owner1), nyms(700)); + assert_eq!( + setup.query_all(), + PagedNamesListResponse { + names: vec![ + new_name(1, &name1, &address1, &owner1, s1.identity_key()), + new_name(2, &name2, &address1, &owner1, s2.identity_key()), + new_name(3, &name3, &address2, &owner1, s3.identity_key()), + new_name(4, &name4, &address1, &owner2, s4.identity_key()), + new_name(5, &name5, &address2, &owner2, s5.identity_key()), + ], + per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, + start_next_after: Some(5), + } + ); + + setup.delete_name(name1, owner1.clone()); + + assert_eq!( + setup.query_all_with_limit(Some(2), None), + PagedNamesListResponse { + names: vec![ + new_name(2, &name2, &address1, &owner1, s2.identity_key()), + new_name(3, &name3, &address2, &owner1, s3.identity_key()), + ], + per_page: 2, + start_next_after: Some(3), + } + ); + + assert_eq!( + setup.query_all_with_limit(Some(2), Some(2)), + PagedNamesListResponse { + names: vec![ + new_name(3, &name3, &address2, &owner1, s3.identity_key()), + new_name(4, &name4, &address1, &owner2, s4.identity_key()), + ], + per_page: 2, + start_next_after: Some(4), + } + ); +} diff --git a/contracts/name-service/src/integration_tests/register.rs b/contracts/name-service/src/integration_tests/register.rs new file mode 100644 index 0000000000..9d6d339dbc --- /dev/null +++ b/contracts/name-service/src/integration_tests/register.rs @@ -0,0 +1,269 @@ +use cosmwasm_std::Addr; +use nym_name_service_common::{ + error::NameServiceError, response::PagedNamesListResponse, Address, NameDetails, NymName, + RegisteredName, +}; +use rstest::rstest; + +use crate::{ + constants::NAME_DEFAULT_RETRIEVAL_LIMIT, + test_helpers::{fixture::new_name, helpers::nyms}, +}; + +use super::test_setup::TestSetup; + +#[rstest::fixture] +fn setup() -> TestSetup { + TestSetup::new() +} + +#[rstest] +fn basic_register(mut setup: TestSetup) { + assert_eq!( + setup.query_all(), + PagedNamesListResponse { + names: vec![], + per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, + start_next_after: None, + } + ); + + // Register a first name + let owner = Addr::unchecked("owner"); + let name = NymName::new("steves-server").unwrap(); + let nym_address = Address::new("nym-address"); + assert_eq!(setup.contract_balance(), nyms(0)); + assert_eq!(setup.balance(&owner), nyms(250)); + assert_eq!(setup.query_signing_nonce(owner.to_string()), 0); + + let reg_name = setup.new_name(&name, &nym_address); + let payload = setup.payload_to_sign(&owner, &nyms(100), ®_name.name); + let reg_name = reg_name.sign(payload); + setup.register(®_name, &owner); + + // Deposit is deposited to contract and deducted from owners's balance + assert_eq!(setup.contract_balance(), nyms(100)); + assert_eq!(setup.balance(&owner), nyms(150)); + + // The signing nonce has been incremented + assert_eq!(setup.query_signing_nonce(owner.to_string()), 1); + + // We can query the full name list + assert_eq!( + setup.query_all(), + PagedNamesListResponse { + names: vec![RegisteredName { + id: 1, + name: NameDetails { + name: name.clone(), + address: nym_address.clone(), + identity_key: reg_name.identity_key().to_string(), + }, + owner: owner.clone(), + block_height: 12345, + deposit: nyms(100), + }], + per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, + start_next_after: Some(1), + } + ); + + // ... and we can query by id + assert_eq!( + setup.query_id(1), + RegisteredName { + id: 1, + name: reg_name.details().clone(), + owner: owner.clone(), + block_height: 12345, + deposit: nyms(100), + } + ); + + // Register a second name + let owner2 = Addr::unchecked("owner2"); + let name2 = NymName::new("another_server").unwrap(); + let nym_address2 = Address::new("nymAddress2"); + let reg_name2 = setup.new_signed_name(&name2, &nym_address2, &owner2, &nyms(100)); + setup.register(®_name2, &owner2); + + assert_eq!(setup.contract_balance(), nyms(200)); + assert_eq!( + setup.query_all(), + PagedNamesListResponse { + names: vec![ + new_name(1, &name, &nym_address, &owner, reg_name.identity_key()), + new_name(2, &name2, &nym_address2, &owner2, reg_name2.identity_key()), + ], + per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, + start_next_after: Some(2), + } + ); +} + +#[rstest] +fn register_fails_when_owner_mismatch(mut setup: TestSetup) { + let owner = Addr::unchecked("owner"); + let name = NymName::new("steves-server").unwrap(); + let nym_address = Address::new("nym-address"); + let reg_name = setup.new_signed_name(&name, &nym_address, &owner, &nyms(100)); + let res = setup + .try_register(®_name, &Addr::unchecked("owner2")) + .unwrap_err(); + assert_eq!( + res.downcast::().unwrap(), + NameServiceError::InvalidEd25519Signature + ); +} + +#[rstest] +fn signing_nonce_is_increased_when_registering(mut setup: TestSetup) { + let owner1 = Addr::unchecked("owner1"); + let owner2 = Addr::unchecked("owner2"); + + assert_eq!(setup.query_signing_nonce(owner1.to_string()), 0); + assert_eq!(setup.query_signing_nonce(owner2.to_string()), 0); + + setup.sign_and_register( + &NymName::new("myname1").unwrap(), + &Address::new("address1"), + &owner1, + &nyms(100), + ); + + assert_eq!(setup.query_signing_nonce(owner1.to_string()), 1); + assert_eq!(setup.query_signing_nonce(owner2.to_string()), 0); + + setup.sign_and_register( + &NymName::new("myname2").unwrap(), + &Address::new("address2"), + &owner2, + &nyms(100), + ); + + assert_eq!(setup.query_signing_nonce(owner1.to_string()), 1); + assert_eq!(setup.query_signing_nonce(owner2.to_string()), 1); + + setup.sign_and_register( + &NymName::new("myname3").unwrap(), + &Address::new("address3"), + &owner2, + &nyms(100), + ); + + assert_eq!(setup.query_signing_nonce(owner1.to_string()), 1); + assert_eq!(setup.query_signing_nonce(owner2.to_string()), 2); +} + +#[rstest] +fn creating_two_names_in_a_row_without_announcing_fails(mut setup: TestSetup) { + let owner = Addr::unchecked("wealthy_owner_1"); + let name1 = NymName::new("steves-server1").unwrap(); + let name2 = NymName::new("steves-server2").unwrap(); + let address1 = Address::new("nymAddress1"); + let address2 = Address::new("nymAddress2"); + let deposit = nyms(100); + + let s1 = setup.new_signed_name(&name1, &address1, &owner, &deposit); + + // This second name will be signed with the same nonce + let s2 = setup.new_signed_name(&name2, &address2, &owner, &deposit); + + // Announce the first service works, and this increments the nonce + setup.register(&s1, &owner); + + // Now the nonce has been incremented, and the signature will not match + let resp: NameServiceError = setup + .try_register(&s2, &owner) + .unwrap_err() + .downcast() + .unwrap(); + assert_eq!(resp, NameServiceError::InvalidEd25519Signature,); +} + +#[rstest] +fn cant_register_a_name_without_funds(mut setup: TestSetup) { + assert_eq!(setup.contract_balance(), nyms(0)); + assert_eq!(setup.balance("owner"), nyms(250)); + let name1 = setup.new_signed_name( + &NymName::new("my_name").unwrap(), + &Address::new("nymAddress"), + &Addr::unchecked("owner"), + &nyms(100), + ); + setup.register(&name1, &Addr::unchecked("owner")); + assert_eq!(setup.contract_balance(), nyms(100)); + assert_eq!(setup.balance("owner"), nyms(150)); + + let name2 = setup.new_signed_name( + &NymName::new("my_name2").unwrap(), + &Address::new("nymAddress"), + &Addr::unchecked("owner"), + &nyms(100), + ); + setup.register(&name2, &Addr::unchecked("owner")); + assert_eq!(setup.contract_balance(), nyms(200)); + assert_eq!(setup.balance("owner"), nyms(50)); + let name3 = setup.new_signed_name( + &NymName::new("my_name3").unwrap(), + &Address::new("nymAddress"), + &Addr::unchecked("owner"), + &nyms(100), + ); + let res = setup + .try_register(&name3, &Addr::unchecked("owner")) + .unwrap_err(); + assert_eq!( + res.downcast::().unwrap(), + cosmwasm_std::StdError::Overflow { + source: cosmwasm_std::OverflowError::new( + cosmwasm_std::OverflowOperation::Sub, + "50", + "100" + ) + } + ); +} + +#[rstest] +fn cant_register_the_same_name_multiple_times(mut setup: TestSetup) { + let name1 = setup.new_signed_name( + &NymName::new("name").unwrap(), + &Address::new("nymAddress"), + &Addr::unchecked("owner"), + &nyms(100), + ); + setup.register(&name1, &Addr::unchecked("owner")); + let resp = setup + .try_register(&name1, &Addr::unchecked("owner")) + .unwrap_err(); + + assert_eq!( + resp.downcast::().unwrap(), + NameServiceError::NameAlreadyRegistered { + name: NymName::new("name").unwrap() + } + ); +} + +#[rstest] +fn can_register_multiple_names_for_the_same_nym_address(mut setup: TestSetup) { + let name1 = NymName::new("name1").unwrap(); + let name2 = NymName::new("name2").unwrap(); + let address = Address::new("nymaddress"); + let owner = Addr::unchecked("owner"); + + let reg_name1 = setup.new_signed_name(&name1, &address, &owner, &nyms(100)); + setup.register(®_name1, &owner); + let reg_name2 = setup.new_signed_name(&name2, &address, &owner, &nyms(100)); + setup.register(®_name2, &owner); + + assert_eq!( + setup.query_all().names, + vec![ + new_name(1, &name1, &address, &owner, reg_name1.identity_key()), + new_name(2, &name2, &address, &owner, reg_name2.identity_key()), + ], + ); +} +// diff --git a/contracts/name-service/src/integration_tests/test_name.rs b/contracts/name-service/src/integration_tests/test_name.rs new file mode 100644 index 0000000000..f33233a0a0 --- /dev/null +++ b/contracts/name-service/src/integration_tests/test_name.rs @@ -0,0 +1,75 @@ +use nym_contracts_common::{signing::MessageSignature, IdentityKey}; +use nym_crypto::asymmetric::identity; +use nym_name_service_common::{ + signing_types::SignableNameRegisterMsg, Address, NameDetails, NymName, +}; +use rand_chacha::ChaCha20Rng; + +use crate::test_helpers::signing::ed25519_sign_message; + +pub struct TestName { + pub name: NameDetails, + pub keys: identity::KeyPair, + pub rng: ChaCha20Rng, +} + +impl TestName { + pub fn new(rng: &mut ChaCha20Rng, name: NymName, address: Address) -> Self { + let keys = identity::KeyPair::new(rng); + let name = NameDetails { + name, + address, + identity_key: keys.public_key().to_base58_string(), + }; + Self { + name, + keys, + rng: rng.clone(), + } + } + + pub fn identity_key(&self) -> &IdentityKey { + &self.name.identity_key + } + + pub fn details(&self) -> &NameDetails { + &self.name + } + + pub fn sign(self, payload: SignableNameRegisterMsg) -> SignedTestName { + let owner_signature = ed25519_sign_message(payload, self.keys.private_key()); + SignedTestName { + name: self.name, + keys: self.keys, + owner_signature, + } + } +} + +impl From for NameDetails { + fn from(test_name: TestName) -> Self { + test_name.name + } +} + +pub struct SignedTestName { + pub name: NameDetails, + pub keys: identity::KeyPair, + pub owner_signature: MessageSignature, +} + +impl SignedTestName { + pub fn identity_key(&self) -> &IdentityKey { + &self.name.identity_key + } + + pub fn details(&self) -> &NameDetails { + &self.name + } +} + +impl From for NameDetails { + fn from(signed_name: SignedTestName) -> Self { + signed_name.name + } +} diff --git a/contracts/name-service/src/test_helpers/test_setup.rs b/contracts/name-service/src/integration_tests/test_setup.rs similarity index 64% rename from contracts/name-service/src/test_helpers/test_setup.rs rename to contracts/name-service/src/integration_tests/test_setup.rs index 98afbb60a0..264d2d236b 100644 --- a/contracts/name-service/src/test_helpers/test_setup.rs +++ b/contracts/name-service/src/integration_tests/test_setup.rs @@ -1,13 +1,18 @@ use cosmwasm_std::{coins, Addr, Coin, Uint128}; use cw_multi_test::{App, AppBuilder, AppResponse, ContractWrapper, Executor}; +use nym_contracts_common::signing::Nonce; use nym_name_service_common::{ msg::{ExecuteMsg, InstantiateMsg, QueryMsg}, response::{ConfigResponse, PagedNamesListResponse}, - Address, NameEntry, NameId, NymName, + signing_types::{construct_name_register_sign_payload, SignableNameRegisterMsg}, + Address, NameDetails, NameId, NymName, RegisteredName, }; +use rand_chacha::ChaCha20Rng; use serde::de::DeserializeOwned; -use crate::test_helpers::helpers::get_app_attribute; +use crate::test_helpers::helpers::{get_app_attribute, test_rng}; + +use super::test_name::{SignedTestName, TestName}; const DENOM: &str = "unym"; const ADDRESSES: &[&str] = &[ @@ -19,6 +24,7 @@ const WEALTHY_ADDRESSES: &[&str] = &["wealthy_owner_1", "wealthy_owner_2"]; pub struct TestSetup { app: App, addr: Addr, + rng: ChaCha20Rng, } impl Default for TestSetup { @@ -44,7 +50,8 @@ impl TestSetup { let code = ContractWrapper::new(crate::execute, crate::instantiate, crate::query); let code_id = app.store_code(Box::new(code)); let addr = Self::instantiate(&mut app, code_id); - TestSetup { app, addr } + let rng = test_rng(); + TestSetup { app, addr, rng } } fn instantiate(app: &mut App, code_id: u64) -> Addr { @@ -76,7 +83,7 @@ impl TestSetup { self.query(&QueryMsg::Config {}) } - pub fn query_id(&self, name_id: NameId) -> NameEntry { + pub fn query_id(&self, name_id: NameId) -> RegisteredName { self.query(&QueryMsg::NameId { name_id }) } @@ -92,16 +99,48 @@ impl TestSetup { self.query(&QueryMsg::All { limit, start_after }) } + pub fn query_signing_nonce(&self, address: String) -> Nonce { + self.query(&QueryMsg::SigningNonce { address }) + } + + pub fn new_name(&mut self, name: &NymName, address: &Address) -> TestName { + TestName::new(&mut self.rng, name.clone(), address.clone()) + } + + pub fn payload_to_sign( + &mut self, + owner: &Addr, + deposit: &Coin, + name: &NameDetails, + ) -> SignableNameRegisterMsg { + let nonce = self.query_signing_nonce(owner.to_string()); + construct_name_register_sign_payload(nonce, owner.clone(), deposit.clone(), name.clone()) + } + + pub fn new_signed_name( + &mut self, + name: &NymName, + address: &Address, + owner: &Addr, + deposit: &Coin, + ) -> SignedTestName { + let name = self.new_name(name, address); + let payload = self.payload_to_sign(owner, deposit, name.details()); + name.sign(payload) + } + pub fn try_register( &mut self, - name: NymName, - address: Address, - owner: Addr, + name: &SignedTestName, + owner: &Addr, ) -> anyhow::Result { self.app.execute_contract( - owner, + owner.clone(), self.addr.clone(), - &ExecuteMsg::Register { name, address }, + &ExecuteMsg::Register { + name: name.name.clone(), + owner_signature: name.owner_signature.clone(), + }, &[Coin { denom: DENOM.to_string(), amount: Uint128::new(100), @@ -109,8 +148,8 @@ impl TestSetup { ) } - pub fn register(&mut self, name: NymName, address: Address, owner: Addr) -> AppResponse { - let resp = self.try_register(name, address, owner).unwrap(); + pub fn register(&mut self, name: &SignedTestName, owner: &Addr) -> AppResponse { + let resp = self.try_register(name, owner).unwrap(); assert_eq!( get_app_attribute(&resp, "wasm-register", "action"), "register" @@ -118,6 +157,19 @@ impl TestSetup { resp } + // Convenience function for creating a new signed name, and regsitering it + pub fn sign_and_register( + &mut self, + name: &NymName, + address: &Address, + owner: &Addr, + deposit: &Coin, + ) -> SignedTestName { + let signed_name = self.new_signed_name(name, address, owner, deposit); + self.register(&signed_name, owner); + signed_name + } + pub fn try_delete(&mut self, name_id: NameId, owner: Addr) -> anyhow::Result { self.app.execute_contract( owner, diff --git a/contracts/name-service/src/lib.rs b/contracts/name-service/src/lib.rs index c2d5b6c5d6..0f426dd72f 100644 --- a/contracts/name-service/src/lib.rs +++ b/contracts/name-service/src/lib.rs @@ -3,16 +3,15 @@ #![warn(clippy::expect_used)] #![warn(clippy::unwrap_used)] -use crate::error::Result; +pub use nym_name_service_common::error::{NameServiceError, Result}; + use nym_name_service_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response}; -use error::NameServiceError; mod contract; -mod error; mod state; pub mod constants; diff --git a/contracts/name-service/src/state/admin.rs b/contracts/name-service/src/state/admin.rs index e0ec915951..026e353626 100644 --- a/contracts/name-service/src/state/admin.rs +++ b/contracts/name-service/src/state/admin.rs @@ -1,7 +1,7 @@ use cosmwasm_std::{Addr, Deps, DepsMut}; use cw_controllers::Admin; -use crate::{constants::ADMIN_KEY, error::Result}; +use crate::{constants::ADMIN_KEY, Result}; const ADMIN: Admin = Admin::new(ADMIN_KEY); diff --git a/contracts/name-service/src/state/config.rs b/contracts/name-service/src/state/config.rs index ed032e670c..aa27617492 100644 --- a/contracts/name-service/src/state/config.rs +++ b/contracts/name-service/src/state/config.rs @@ -3,7 +3,7 @@ use cw_storage_plus::Item; use nym_name_service_common::response::ConfigResponse; use serde::{Deserialize, Serialize}; -use crate::{constants::CONFIG_KEY, error::Result}; +use crate::{constants::CONFIG_KEY, Result}; const CONFIG: Item = Item::new(CONFIG_KEY); diff --git a/contracts/name-service/src/state/mod.rs b/contracts/name-service/src/state/mod.rs index 4120ab91e8..8d86c67201 100644 --- a/contracts/name-service/src/state/mod.rs +++ b/contracts/name-service/src/state/mod.rs @@ -2,7 +2,9 @@ pub mod admin; pub mod config; pub mod name_id_counter; pub mod names; +pub mod nonce; pub(crate) use admin::{assert_admin, set_admin}; pub(crate) use config::{deposit_required, load_config, save_config, Config}; pub(crate) use name_id_counter::next_name_id_counter; +pub(crate) use nonce::{get_signing_nonce, increment_signing_nonce}; diff --git a/contracts/name-service/src/state/name_id_counter.rs b/contracts/name-service/src/state/name_id_counter.rs index bed384e7bb..c45e5169e6 100644 --- a/contracts/name-service/src/state/name_id_counter.rs +++ b/contracts/name-service/src/state/name_id_counter.rs @@ -2,7 +2,7 @@ use cosmwasm_std::Storage; use cw_storage_plus::Item; use nym_name_service_common::NameId; -use crate::{constants::NAME_ID_COUNTER_KEY, error::Result}; +use crate::{constants::NAME_ID_COUNTER_KEY, Result}; const NAME_ID_COUNTER: Item = Item::new(NAME_ID_COUNTER_KEY); @@ -16,33 +16,56 @@ pub(crate) fn next_name_id_counter(store: &mut dyn Storage) -> Result { #[cfg(test)] mod tests { - - use nym_name_service_common::NameEntry; + use cosmwasm_std::Addr; + use nym_name_service_common::RegisteredName; use crate::test_helpers::{ assert::assert_names, - fixture::name_fixture_name, - helpers::{delete_name_id, instantiate_test_contract, register_name}, + helpers::{nyms, test_rng}, + transactions::{delete_name_id, instantiate_test_contract, register_name}, }; #[test] fn get_next_name_id() { let mut deps = instantiate_test_contract(); + let mut rng = test_rng(); - assert_eq!(register_name(deps.as_mut(), &name_fixture_name("foo")), 1); - assert_names( - deps.as_ref(), - &[NameEntry::new(1, name_fixture_name("foo"))], - ); - - assert_eq!(register_name(deps.as_mut(), &name_fixture_name("bar")), 2); - assert_eq!(register_name(deps.as_mut(), &name_fixture_name("baz")), 3); + let (id1, name1) = register_name(deps.as_mut(), &mut rng, "foo", "addr1", "steve"); + let (id2, name2) = register_name(deps.as_mut(), &mut rng, "bar", "addr2", "steve"); + let (id3, name3) = register_name(deps.as_mut(), &mut rng, "baz", "addr3", "steve"); + assert_eq!(id1, 1); + assert_eq!(id2, 2); + assert_eq!(id3, 3); + assert_eq!(name1.name.as_str(), "foo"); + assert_eq!(name1.address.as_str(), "addr1"); + assert_eq!(name2.name.as_str(), "bar"); + assert_eq!(name2.address.as_str(), "addr2"); + assert_eq!(name3.name.as_str(), "baz"); + assert_eq!(name3.address.as_str(), "addr3"); assert_names( deps.as_ref(), &[ - NameEntry::new(1, name_fixture_name("foo")), - NameEntry::new(2, name_fixture_name("bar")), - NameEntry::new(3, name_fixture_name("baz")), + RegisteredName { + id: 1, + name: name1, + owner: Addr::unchecked("steve"), + block_height: 12345, + deposit: nyms(100), + }, + RegisteredName { + id: 2, + name: name2, + owner: Addr::unchecked("steve"), + block_height: 12345, + deposit: nyms(100), + }, + RegisteredName { + id: 3, + name: name3, + owner: Addr::unchecked("steve"), + block_height: 12345, + deposit: nyms(100), + }, ], ); } @@ -50,34 +73,28 @@ mod tests { #[test] fn deleted_name_id_is_not_reused() { let mut deps = instantiate_test_contract(); + let mut rng = test_rng(); // Register two names - assert_eq!(register_name(deps.as_mut(), &name_fixture_name("one")), 1); - assert_eq!(register_name(deps.as_mut(), &name_fixture_name("two")), 2); - assert_names( - deps.as_ref(), - &[ - NameEntry::new(1, name_fixture_name("one")), - NameEntry::new(2, name_fixture_name("two")), - ], - ); + let (_, name1) = register_name(deps.as_mut(), &mut rng, "one", "sdfjkhsdfhr", "steve"); + register_name(deps.as_mut(), &mut rng, "two", "suereljer", "steve"); // Delete the last entry delete_name_id(deps.as_mut(), 2, "steve"); assert_names( deps.as_ref(), - &[NameEntry::new(1, name_fixture_name("one"))], + &[RegisteredName { + id: 1, + name: name1, + owner: Addr::unchecked("steve"), + block_height: 12345, + deposit: nyms(100), + }], ); // Create a third entry. The index should not reuse the previous entry that we just // deleted. - assert_eq!(register_name(deps.as_mut(), &name_fixture_name("two")), 3); - assert_names( - deps.as_ref(), - &[ - NameEntry::new(1, name_fixture_name("one")), - NameEntry::new(3, name_fixture_name("two")), - ], - ); + let (id3, _) = register_name(deps.as_mut(), &mut rng, "three", "ufd", "steve"); + assert_eq!(id3, 3); } } diff --git a/contracts/name-service/src/state/names.rs b/contracts/name-service/src/state/names.rs index 81190687f6..27af9f3407 100644 --- a/contracts/name-service/src/state/names.rs +++ b/contracts/name-service/src/state/names.rs @@ -8,7 +8,7 @@ use crate::{ NAMES_ADDRESS_IDX_NAMESPACE, NAMES_NAME_IDX_NAMESPACE, NAMES_OWNER_IDX_NAMESPACE, NAMES_PK_NAMESPACE, NAME_DEFAULT_RETRIEVAL_LIMIT, NAME_MAX_RETRIEVAL_LIMIT, }, - error::{NameServiceError, Result}, + NameServiceError, Result, }; struct NameIndex<'a> { @@ -28,9 +28,9 @@ impl<'a> IndexList for NameIndex<'a> { fn names<'a>() -> IndexedMap<'a, NameId, RegisteredName, NameIndex<'a>> { let indexes = NameIndex { - name: UniqueIndex::new(|d| d.name.to_string(), NAMES_NAME_IDX_NAMESPACE), + name: UniqueIndex::new(|d| d.name.name.to_string(), NAMES_NAME_IDX_NAMESPACE), address: MultiIndex::new( - |d| d.address.to_string(), + |d| d.name.address.to_string(), NAMES_PK_NAMESPACE, NAMES_ADDRESS_IDX_NAMESPACE, ), @@ -43,19 +43,29 @@ fn names<'a>() -> IndexedMap<'a, NameId, RegisteredName, NameIndex<'a>> { IndexedMap::new(NAMES_PK_NAMESPACE, indexes) } -pub fn save(store: &mut dyn Storage, new_name: &RegisteredName) -> Result { - let name_id = super::next_name_id_counter(store)?; +pub fn save(store: &mut dyn Storage, new_name: &RegisteredName) -> Result<()> { + let name_id = new_name.id; names().save(store, name_id, new_name)?; - Ok(name_id) + Ok(()) } #[cfg(test)] -pub fn save_all(state: &mut dyn Storage, names: &[RegisteredName]) -> Result> { - let mut ids = vec![]; +pub fn save_all(state: &mut dyn Storage, names: &[RegisteredName]) -> Result<()> { for name in names { - ids.push(save(state, name)?); + save(state, name)?; } - Ok(ids) + Ok(()) +} + +pub fn remove_id(store: &mut dyn Storage, name_id: NameId) -> Result<()> { + Ok(names().remove(store, name_id)?) +} + +#[cfg(test)] +pub fn remove_name(store: &mut dyn Storage, name: NymName) -> Result { + let registered_name = load_name(store, &name)?; + remove_id(store, registered_name.id)?; + Ok(registered_name.id) } pub fn has_name_id(store: &dyn Storage, name_id: NameId) -> bool { @@ -66,23 +76,6 @@ pub fn has_name(store: &dyn Storage, name: &NymName) -> bool { load_name(store, name).is_ok() } -// Get the (key, name) entry for a given name -pub fn load_name_entry(store: &dyn Storage, name: &NymName) -> Result<(NameId, RegisteredName)> { - names() - .idx - .name - .range(store, None, None, Order::Ascending) - .find(|entry| { - if let Ok(entry) = entry { - &entry.1.name == name - } else { - false - } - }) - .ok_or(NameServiceError::NameNotFound { name: name.clone() })? - .map_err(NameServiceError::from) -} - pub fn load_id(store: &dyn Storage, name_id: NameId) -> Result { names().load(store, name_id).map_err(|err| match err { StdError::NotFound { .. } => NameServiceError::NotFound { name_id }, @@ -99,45 +92,33 @@ pub fn load_name(store: &dyn Storage, name: &NymName) -> Result .ok_or(NameServiceError::NameNotFound { name: name.clone() }) } -pub fn load_address( - store: &dyn Storage, - address: &Address, -) -> Result> { +pub fn load_address(store: &dyn Storage, address: &Address) -> Result> { names() .idx .address .prefix(address.to_string()) .range(store, None, None, Order::Ascending) .take(MAX_NUMBER_OF_NAMES_FOR_ADDRESS as usize) + .map(|res| res.map(|(_, name)| name)) .collect::>>() .map_err(NameServiceError::from) } -pub fn load_owner(store: &dyn Storage, owner: Addr) -> Result> { +pub fn load_owner(store: &dyn Storage, owner: Addr) -> Result> { names() .idx .owner .prefix(owner) .range(store, None, None, Order::Ascending) .take(MAX_NUMBER_OF_NAMES_PER_OWNER as usize) + .map(|res| res.map(|(_, name)| name)) .collect::>>() .map_err(NameServiceError::from) } -pub fn remove_id(store: &mut dyn Storage, name_id: NameId) -> Result<()> { - Ok(names().remove(store, name_id)?) -} - -#[cfg(test)] -pub fn remove_name(store: &mut dyn Storage, name: NymName) -> Result { - let name_info = load_name_entry(store, &name)?; - remove_id(store, name_info.0)?; - Ok(name_info.0) -} - #[derive(Debug, PartialEq)] pub struct PagedLoad { - pub names: Vec<(NameId, RegisteredName)>, + pub names: Vec, pub limit: usize, pub start_next_after: Option, } @@ -156,9 +137,10 @@ pub fn load_all_paged( let names = names() .range(store, start, None, Order::Ascending) .take(limit) + .map(|res| res.map(|(_, name)| name)) .collect::>>()?; - let start_next_after = names.last().map(|name| name.0); + let start_next_after = names.last().map(|name| name.id); Ok(PagedLoad { names, @@ -169,8 +151,6 @@ pub fn load_all_paged( #[cfg(test)] mod tests { - use std::iter::zip; - use cosmwasm_std::{ testing::{MockApi, MockQuerier}, MemoryStorage, OwnedDeps, @@ -178,11 +158,11 @@ mod tests { use rstest::rstest; use crate::{ - error::NameServiceError, test_helpers::{ fixture::{name_fixture, name_fixture_full}, - helpers::instantiate_test_contract, + transactions::instantiate_test_contract, }, + NameServiceError, }; use super::*; @@ -197,64 +177,55 @@ mod tests { #[rstest::fixture] fn uniq_names() -> Vec { vec![ - name_fixture_full("one", "address_one", "owner_one"), - name_fixture_full("two", "address_two", "owner_two"), - name_fixture_full("three", "address_three", "owner_three"), + name_fixture_full(1, "one", "address_one", "owner_one"), + name_fixture_full(2, "two", "address_two", "owner_two"), + name_fixture_full(3, "three", "address_three", "owner_three"), ] } #[rstest::fixture] fn overlapping_addresses() -> Vec { vec![ - name_fixture_full("one", "address_one", "owner_one"), - name_fixture_full("two", "address_two", "owner_two"), - name_fixture_full("three", "address_two", "owner_three"), + name_fixture_full(1, "one", "address_one", "owner_one"), + name_fixture_full(2, "two", "address_two", "owner_two"), + name_fixture_full(3, "three", "address_two", "owner_three"), ] } #[rstest::fixture] fn overlapping_owners() -> Vec { vec![ - name_fixture_full("one", "address_one", "owner_one"), - name_fixture_full("two", "address_two", "owner_two"), - name_fixture_full("three", "address_three", "owner_two"), + name_fixture_full(1, "one", "address_one", "owner_one"), + name_fixture_full(2, "two", "address_two", "owner_two"), + name_fixture_full(3, "three", "address_three", "owner_two"), ] } - fn assert_not_registered(store: &dyn Storage, names: Vec, ids: Vec) { - let names: Vec<(NameId, RegisteredName)> = zip(ids, names).collect(); + fn assert_not_registered(store: &dyn Storage, names: Vec) { let loaded = load_all_paged(store, None, None).unwrap(); - for (id, name) in &names { - assert!(!has_name_id(store, *id)); - assert!(!has_name(store, &name.name)); - assert!(!loaded.names.iter().any(|(i, _)| i == id)); - assert!(!loaded.names.iter().any(|(_, n)| n == name)); + for name in &names { + assert!(!has_name_id(store, name.id)); + assert!(!has_name(store, name.entry())); + assert!(!loaded.names.iter().any(|l_name| l_name.id == name.id)); + assert!(!loaded.names.iter().any(|l_name| l_name == name)); } } - fn assert_registered(store: &dyn Storage, names: Vec, ids: Vec) { - assert!(names.len() == ids.len()); - let names: Vec<(NameId, RegisteredName)> = zip(ids, names).collect(); + fn assert_registered(store: &dyn Storage, names: Vec) { let loaded = load_all_paged(store, None, None).unwrap(); - for (id, name) in &names { - assert!(has_name_id(store, *id)); - assert!(has_name(store, &name.name)); - assert!(loaded.names.iter().filter(|(i, _)| i == id).count() == 1); - assert!(loaded.names.iter().filter(|(_, n)| n == name).count() == 1); + for name in &names { + assert!(has_name_id(store, name.id)); + assert!(has_name(store, name.entry())); + assert!(loaded.names.iter().filter(|n| n == &name).count() == 1); } } - fn assert_only_these_registered( - store: &dyn Storage, - names: Vec, - ids: Vec, - ) { - let last_id = *ids.last().unwrap(); - let names: Vec<(NameId, RegisteredName)> = zip(ids, names).collect(); - for (id, name) in &names { - assert!(has_name_id(store, *id)); - assert!(has_name(store, &name.name)); + fn assert_only_these_registered(store: &dyn Storage, names: Vec) { + for name in &names { + assert!(has_name_id(store, name.id)); + assert!(has_name(store, name.entry())); } + let last_id = names.last().unwrap().id; assert_eq!( load_all_paged(store, None, None).unwrap(), PagedLoad { @@ -267,102 +238,107 @@ mod tests { #[rstest] fn single_basic_save_works(mut deps: TestDeps) { - save(deps.as_mut().storage, &name_fixture()).unwrap(); + save(deps.as_mut().storage, &name_fixture(1)).unwrap(); } #[rstest] fn save_same_name_twice_fails(mut deps: TestDeps) { - save(deps.as_mut().storage, &name_fixture()).unwrap(); + save(deps.as_mut().storage, &name_fixture(1)).unwrap(); assert!(matches!( - save(deps.as_mut().storage, &name_fixture()).unwrap_err(), + save(deps.as_mut().storage, &name_fixture(2)).unwrap_err(), NameServiceError::Std(StdError::GenericErr { .. }) )); } + #[rstest] + fn remove_id_works(mut deps: TestDeps) { + save(deps.as_mut().storage, &name_fixture(1)).unwrap(); + assert!(has_name_id(&deps.storage, 1)); + assert!(has_name(&deps.storage, name_fixture(1).entry())); + remove_id(deps.as_mut().storage, 1).unwrap(); + assert!(!has_name_id(&deps.storage, 1)); + assert!(!has_name(&deps.storage, name_fixture(1).entry())); + } + + #[rstest] + fn remove_name_works(mut deps: TestDeps) { + save(deps.as_mut().storage, &name_fixture(1)).unwrap(); + assert!(has_name_id(&deps.storage, 1)); + assert!(has_name(&deps.storage, name_fixture(1).entry())); + remove_name(deps.as_mut().storage, name_fixture(1).name.name).unwrap(); + assert!(!has_name_id(&deps.storage, 1)); + assert!(!has_name(&deps.storage, name_fixture(1).entry())); + } + #[rstest] fn has_name_works(mut deps: TestDeps) { - assert!(!has_name(&deps.storage, &name_fixture().name)); - save(deps.as_mut().storage, &name_fixture()).unwrap(); - assert!(has_name(&deps.storage, &name_fixture().name)); + assert!(!has_name(&deps.storage, name_fixture(1).entry())); + save(deps.as_mut().storage, &name_fixture(1)).unwrap(); + assert!(has_name(&deps.storage, name_fixture(1).entry())); } #[rstest] fn has_name_id_works(mut deps: TestDeps) { assert!(!has_name_id(&deps.storage, 1)); - save(deps.as_mut().storage, &name_fixture()).unwrap(); + save(deps.as_mut().storage, &name_fixture(1)).unwrap(); assert!(has_name_id(&deps.storage, 1)); } #[rstest] fn has_name_id_with_incorrect_id_fails(mut deps: TestDeps) { assert!(!has_name_id(&deps.storage, 2)); - save(deps.as_mut().storage, &name_fixture()).unwrap(); + save(deps.as_mut().storage, &name_fixture(1)).unwrap(); assert!(!has_name_id(&deps.storage, 2)); } - #[rstest] - fn load_name_entry_works(mut deps: TestDeps) { - assert_eq!( - load_name_entry(deps.as_ref().storage, &name_fixture().name).unwrap_err(), - NameServiceError::NameNotFound { - name: name_fixture().name - } - ); - save(deps.as_mut().storage, &name_fixture()).unwrap(); - assert_eq!( - load_name_entry(deps.as_ref().storage, &name_fixture().name).unwrap(), - (1, name_fixture()) - ); - } - #[rstest] fn load_id_works(mut deps: TestDeps) { assert_eq!( load_id(deps.as_ref().storage, 1).unwrap_err(), NameServiceError::NotFound { name_id: 1 } ); - save(deps.as_mut().storage, &name_fixture()).unwrap(); - assert_eq!(load_id(deps.as_ref().storage, 1).unwrap(), name_fixture(),); + save(deps.as_mut().storage, &name_fixture(1)).unwrap(); + assert_eq!(load_id(deps.as_ref().storage, 1).unwrap(), name_fixture(1),); } #[rstest] fn load_name_works(mut deps: TestDeps) { assert_eq!( - load_name(deps.as_ref().storage, &name_fixture().name).unwrap_err(), + load_name(deps.as_ref().storage, name_fixture(1).entry()).unwrap_err(), NameServiceError::NameNotFound { - name: name_fixture().name + name: name_fixture(1).name.name, } ); - save(deps.as_mut().storage, &name_fixture()).unwrap(); + save(deps.as_mut().storage, &name_fixture(1)).unwrap(); assert_eq!( - load_name(deps.as_ref().storage, &name_fixture().name).unwrap(), - name_fixture(), + load_name(deps.as_ref().storage, name_fixture(1).entry()).unwrap(), + name_fixture(1), ); } #[rstest] fn load_address_works(mut deps: TestDeps) { assert_eq!( - load_address(deps.as_ref().storage, &name_fixture().address).unwrap(), + load_address(deps.as_ref().storage, &name_fixture(1).name.address).unwrap(), vec![], ); - save(deps.as_mut().storage, &name_fixture()).unwrap(); + save(deps.as_mut().storage, &name_fixture(1)).unwrap(); assert_eq!( - load_address(deps.as_ref().storage, &name_fixture().address).unwrap(), - vec![(1, name_fixture())], + load_address(deps.as_ref().storage, &name_fixture(1).name.address).unwrap(), + vec![name_fixture(1)], ); } #[rstest] fn load_owner_works(mut deps: TestDeps) { assert_eq!( - load_owner(deps.as_ref().storage, name_fixture().owner).unwrap(), + load_owner(deps.as_ref().storage, name_fixture(1).owner).unwrap(), vec![], ); - save(deps.as_mut().storage, &name_fixture()).unwrap(); + save(deps.as_mut().storage, &name_fixture(1)).unwrap(); assert_eq!( - load_owner(deps.as_ref().storage, name_fixture().owner).unwrap(), - vec![(1, name_fixture())], + load_owner(deps.as_ref().storage, name_fixture(1).owner).unwrap(), + vec![name_fixture(1)], ); } @@ -380,60 +356,19 @@ mod tests { assert_eq!( load_all_paged(&deps.storage, None, None).unwrap(), PagedLoad { - names: vec![(1, uniq_names[0].clone())], + names: vec![uniq_names[0].clone()], limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, start_next_after: Some(1), } ); } - #[rstest] - fn remove_id_works(mut deps: TestDeps) { - save(deps.as_mut().storage, &name_fixture()).unwrap(); - assert!(has_name_id(&deps.storage, 1)); - assert!(has_name(&deps.storage, &name_fixture().name)); - remove_id(deps.as_mut().storage, 1).unwrap(); - assert!(!has_name_id(&deps.storage, 1)); - assert!(!has_name(&deps.storage, &name_fixture().name)); - } - - #[rstest] - fn remove_name_works(mut deps: TestDeps) { - save(deps.as_mut().storage, &name_fixture()).unwrap(); - assert!(has_name_id(&deps.storage, 1)); - assert!(has_name(&deps.storage, &name_fixture().name)); - remove_name(deps.as_mut().storage, name_fixture().name).unwrap(); - assert!(!has_name_id(&deps.storage, 1)); - assert!(!has_name(&deps.storage, &name_fixture().name)); - } - #[rstest] fn save_set_of_unique_names_works(mut deps: TestDeps, uniq_names: Vec) { - let num = uniq_names.len() as NameId; - let ids = (1..=num).collect::>(); - assert_not_registered(&deps.storage, uniq_names.clone(), ids.clone()); - let saved_ids = save_all(deps.as_mut().storage, &uniq_names).unwrap(); - assert_eq!(saved_ids, ids); - assert_registered(&deps.storage, uniq_names.clone(), ids.clone()); - assert_only_these_registered(&deps.storage, uniq_names, ids); - } - - #[rstest] - fn save_set_of_unique_names_generates_ids(mut deps: TestDeps, uniq_names: Vec) { - let num = uniq_names.len() as NameId; - let ids = save_all(deps.as_mut().storage, &uniq_names).unwrap(); - assert_eq!(ids, (1..=num).collect::>()); - } - - #[rstest] - fn load_name_entry_for_unique_set_works(mut deps: TestDeps, uniq_names: Vec) { + assert_not_registered(&deps.storage, uniq_names.clone()); save_all(deps.as_mut().storage, &uniq_names).unwrap(); - for (id, name) in uniq_names.iter().enumerate() { - assert_eq!( - load_name_entry(deps.as_ref().storage, &name.name).unwrap(), - (id as NameId + 1, name.clone()), - ); - } + assert_registered(&deps.storage, uniq_names.clone()); + assert_only_these_registered(&deps.storage, uniq_names); } #[rstest] @@ -441,7 +376,7 @@ mod tests { save_all(deps.as_mut().storage, &uniq_names).unwrap(); for name in uniq_names { assert_eq!( - load_name(deps.as_ref().storage, &name.name).unwrap(), + load_name(deps.as_ref().storage, name.entry()).unwrap(), name.clone(), ); } @@ -452,17 +387,14 @@ mod tests { mut deps: TestDeps, uniq_names: Vec, ) { - let ids = save_all(deps.as_mut().storage, &uniq_names).unwrap(); - remove_id(deps.as_mut().storage, ids[1]).unwrap(); + save_all(deps.as_mut().storage, &uniq_names).unwrap(); + remove_id(deps.as_mut().storage, 2).unwrap(); assert_eq!( load_all_paged(deps.as_ref().storage, None, None).unwrap(), PagedLoad { names: vec![ - (1, name_fixture_full("one", "address_one", "owner_one")), - ( - 3, - name_fixture_full("three", "address_three", "owner_three") - ), + name_fixture_full(1, "one", "address_one", "owner_one"), + name_fixture_full(3, "three", "address_three", "owner_three"), ], limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, start_next_after: Some(3), @@ -476,16 +408,13 @@ mod tests { uniq_names: Vec, ) { save_all(deps.as_mut().storage, &uniq_names).unwrap(); - remove_name(deps.as_mut().storage, uniq_names[1].name.clone()).unwrap(); + remove_name(deps.as_mut().storage, uniq_names[1].entry().clone()).unwrap(); assert_eq!( load_all_paged(deps.as_ref().storage, None, None).unwrap(), PagedLoad { names: vec![ - (1, name_fixture_full("one", "address_one", "owner_one")), - ( - 3, - name_fixture_full("three", "address_three", "owner_three") - ), + name_fixture_full(1, "one", "address_one", "owner_one"), + name_fixture_full(3, "three", "address_three", "owner_three"), ], limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, start_next_after: Some(3), @@ -498,9 +427,9 @@ mod tests { mut deps: TestDeps, overlapping_addresses: Vec, ) { - let ids = save_all(deps.as_mut().storage, &overlapping_addresses).unwrap(); - assert_registered(&deps.storage, overlapping_addresses.clone(), ids.clone()); - assert_only_these_registered(&deps.storage, overlapping_addresses, ids); + save_all(deps.as_mut().storage, &overlapping_addresses).unwrap(); + assert_registered(&deps.storage, overlapping_addresses.clone()); + assert_only_these_registered(&deps.storage, overlapping_addresses); } #[rstest] @@ -513,9 +442,9 @@ mod tests { load_all_paged(deps.as_ref().storage, None, None).unwrap(), PagedLoad { names: vec![ - (1, name_fixture_full("one", "address_one", "owner_one")), - (2, name_fixture_full("two", "address_two", "owner_two")), - (3, name_fixture_full("three", "address_two", "owner_three")), + name_fixture_full(1, "one", "address_one", "owner_one"), + name_fixture_full(2, "two", "address_two", "owner_two"), + name_fixture_full(3, "three", "address_two", "owner_three"), ], limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, start_next_after: Some(3), @@ -524,8 +453,8 @@ mod tests { assert_eq!( load_address(deps.as_ref().storage, &Address::new("address_two")).unwrap(), vec![ - (2, name_fixture_full("two", "address_two", "owner_two")), - (3, name_fixture_full("three", "address_two", "owner_three")), + name_fixture_full(2, "two", "address_two", "owner_two"), + name_fixture_full(3, "three", "address_two", "owner_three"), ] ); } @@ -535,14 +464,14 @@ mod tests { mut deps: TestDeps, overlapping_addresses: Vec, ) { - let ids = save_all(deps.as_mut().storage, &overlapping_addresses).unwrap(); - remove_id(deps.as_mut().storage, ids[1]).unwrap(); + save_all(deps.as_mut().storage, &overlapping_addresses).unwrap(); + remove_id(deps.as_mut().storage, 2).unwrap(); assert_eq!( load_all_paged(deps.as_ref().storage, None, None).unwrap(), PagedLoad { names: vec![ - (1, name_fixture_full("one", "address_one", "owner_one")), - (3, name_fixture_full("three", "address_two", "owner_three")), + name_fixture_full(1, "one", "address_one", "owner_one"), + name_fixture_full(3, "three", "address_two", "owner_three"), ], limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, start_next_after: Some(3), @@ -556,13 +485,17 @@ mod tests { overlapping_addresses: Vec, ) { save_all(deps.as_mut().storage, &overlapping_addresses).unwrap(); - remove_name(deps.as_mut().storage, overlapping_addresses[1].name.clone()).unwrap(); + remove_name( + deps.as_mut().storage, + overlapping_addresses[1].name.name.clone(), + ) + .unwrap(); assert_eq!( load_all_paged(deps.as_ref().storage, None, None).unwrap(), PagedLoad { names: vec![ - (1, name_fixture_full("one", "address_one", "owner_one")), - (3, name_fixture_full("three", "address_two", "owner_three")), + name_fixture_full(1, "one", "address_one", "owner_one"), + name_fixture_full(3, "three", "address_two", "owner_three"), ], limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, start_next_after: Some(3), @@ -575,9 +508,9 @@ mod tests { mut deps: TestDeps, overlapping_owners: Vec, ) { - let ids = save_all(deps.as_mut().storage, &overlapping_owners).unwrap(); - assert_registered(&deps.storage, overlapping_owners.clone(), ids.clone()); - assert_only_these_registered(&deps.storage, overlapping_owners, ids); + save_all(deps.as_mut().storage, &overlapping_owners).unwrap(); + assert_registered(&deps.storage, overlapping_owners.clone()); + assert_only_these_registered(&deps.storage, overlapping_owners); } #[rstest] @@ -590,9 +523,9 @@ mod tests { load_all_paged(deps.as_ref().storage, None, None).unwrap(), PagedLoad { names: vec![ - (1, name_fixture_full("one", "address_one", "owner_one")), - (2, name_fixture_full("two", "address_two", "owner_two")), - (3, name_fixture_full("three", "address_three", "owner_two")), + name_fixture_full(1, "one", "address_one", "owner_one"), + name_fixture_full(2, "two", "address_two", "owner_two"), + name_fixture_full(3, "three", "address_three", "owner_two"), ], limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, start_next_after: Some(3), @@ -601,8 +534,8 @@ mod tests { assert_eq!( load_owner(deps.as_ref().storage, Addr::unchecked("owner_two")).unwrap(), vec![ - (2, name_fixture_full("two", "address_two", "owner_two")), - (3, name_fixture_full("three", "address_three", "owner_two")), + name_fixture_full(2, "two", "address_two", "owner_two"), + name_fixture_full(3, "three", "address_three", "owner_two"), ] ); } @@ -612,16 +545,16 @@ mod tests { mut deps: TestDeps, overlapping_owners: Vec, ) { - let ids = save_all(deps.as_mut().storage, &overlapping_owners).unwrap(); - assert_registered(&deps.storage, overlapping_owners.clone(), ids.clone()); - assert_only_these_registered(&deps.storage, overlapping_owners, ids); + save_all(deps.as_mut().storage, &overlapping_owners).unwrap(); + assert_registered(&deps.storage, overlapping_owners.clone()); + assert_only_these_registered(&deps.storage, overlapping_owners); remove_id(deps.as_mut().storage, 2).unwrap(); assert_eq!( load_all_paged(deps.as_ref().storage, None, None).unwrap(), PagedLoad { names: vec![ - (1, name_fixture_full("one", "address_one", "owner_one")), - (3, name_fixture_full("three", "address_three", "owner_two")), + name_fixture_full(1, "one", "address_one", "owner_one"), + name_fixture_full(3, "three", "address_three", "owner_two"), ], limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, start_next_after: Some(3), @@ -634,16 +567,16 @@ mod tests { mut deps: TestDeps, overlapping_owners: Vec, ) { - let ids = save_all(deps.as_mut().storage, &overlapping_owners).unwrap(); - assert_registered(&deps.storage, overlapping_owners.clone(), ids.clone()); - assert_only_these_registered(&deps.storage, overlapping_owners.clone(), ids); - remove_name(deps.as_mut().storage, overlapping_owners[1].name.clone()).unwrap(); + save_all(deps.as_mut().storage, &overlapping_owners).unwrap(); + assert_registered(&deps.storage, overlapping_owners.clone()); + assert_only_these_registered(&deps.storage, overlapping_owners.clone()); + remove_name(deps.as_mut().storage, overlapping_owners[1].entry().clone()).unwrap(); assert_eq!( load_all_paged(deps.as_ref().storage, None, None).unwrap(), PagedLoad { names: vec![ - (1, name_fixture_full("one", "address_one", "owner_one")), - (3, name_fixture_full("three", "address_three", "owner_two")), + name_fixture_full(1, "one", "address_one", "owner_one"), + name_fixture_full(3, "three", "address_three", "owner_two"), ], limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize, start_next_after: Some(3), @@ -658,8 +591,8 @@ mod tests { load_all_paged(&deps.storage, Some(2), None).unwrap(), PagedLoad { names: vec![ - (1, name_fixture_full("one", "address_one", "owner_one")), - (2, name_fixture_full("two", "address_two", "owner_two")), + name_fixture_full(1, "one", "address_one", "owner_one"), + name_fixture_full(2, "two", "address_two", "owner_two"), ], limit: 2, start_next_after: Some(2), @@ -668,10 +601,12 @@ mod tests { assert_eq!( load_all_paged(&deps.storage, Some(1), Some(2)).unwrap(), PagedLoad { - names: vec![( + names: vec![name_fixture_full( 3, - name_fixture_full("three", "address_three", "owner_three") - ),], + "three", + "address_three", + "owner_three" + )], limit: 1, start_next_after: Some(3), } @@ -679,10 +614,12 @@ mod tests { assert_eq!( load_all_paged(&deps.storage, Some(2), Some(2)).unwrap(), PagedLoad { - names: vec![( + names: vec![name_fixture_full( 3, - name_fixture_full("three", "address_three", "owner_three") - ),], + "three", + "address_three", + "owner_three" + )], limit: 2, start_next_after: Some(3), } diff --git a/contracts/name-service/src/state/nonce.rs b/contracts/name-service/src/state/nonce.rs new file mode 100644 index 0000000000..bf865af82a --- /dev/null +++ b/contracts/name-service/src/state/nonce.rs @@ -0,0 +1,71 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::{constants::SIGNING_NONCES_NAMESPACE, Result}; + +use cosmwasm_std::{Addr, Storage}; +use cw_storage_plus::Map; +use nym_contracts_common::signing::Nonce; + +pub const NONCES: Map<'_, Addr, Nonce> = Map::new(SIGNING_NONCES_NAMESPACE); + +pub fn get_signing_nonce(storage: &dyn Storage, address: Addr) -> Result { + let nonce = NONCES.may_load(storage, address)?.unwrap_or(0); + Ok(nonce) +} + +fn update_signing_nonce(storage: &mut dyn Storage, address: Addr, value: Nonce) -> Result<()> { + NONCES + .save(storage, address, &value) + .map_err(|err| err.into()) +} + +pub fn increment_signing_nonce(storage: &mut dyn Storage, address: Addr) -> Result<()> { + // get the current nonce + let nonce = get_signing_nonce(storage, address.clone())?; + + // increment it for the next use + update_signing_nonce(storage, address, nonce + 1) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::test_helpers::transactions::instantiate_test_contract; + use cosmwasm_std::{ + testing::{MockApi, MockQuerier}, + MemoryStorage, OwnedDeps, + }; + use rstest::rstest; + + type TestDeps = OwnedDeps; + + #[rstest::fixture] + fn deps() -> TestDeps { + instantiate_test_contract() + } + + fn addr(s: &str) -> Addr { + Addr::unchecked(s) + } + + #[rstest] + fn getting_signing_nonce_doesnt_increment_it(deps: TestDeps) { + assert_eq!(get_signing_nonce(&deps.storage, addr("gunnar")).unwrap(), 0); + assert_eq!(get_signing_nonce(&deps.storage, addr("gunnar")).unwrap(), 0); + } + + #[rstest] + fn increment_works(mut deps: TestDeps) { + assert_eq!(get_signing_nonce(&deps.storage, addr("gunnar")).unwrap(), 0); + increment_signing_nonce(&mut deps.storage, addr("gunnar")).unwrap(); + assert_eq!(get_signing_nonce(&deps.storage, addr("gunnar")).unwrap(), 1); + } + + #[rstest] + fn incrementing_is_independent(mut deps: TestDeps) { + increment_signing_nonce(&mut deps.storage, addr("gunnar")).unwrap(); + assert_eq!(get_signing_nonce(&deps.storage, addr("gunnar")).unwrap(), 1); + assert_eq!(get_signing_nonce(&deps.storage, addr("bjorn")).unwrap(), 0); + } +} diff --git a/contracts/name-service/src/test_helpers/assert.rs b/contracts/name-service/src/test_helpers/assert.rs index b9c862906b..1f2475b196 100644 --- a/contracts/name-service/src/test_helpers/assert.rs +++ b/contracts/name-service/src/test_helpers/assert.rs @@ -1,11 +1,12 @@ use cosmwasm_std::{from_binary, testing::mock_env, Addr, Coin, Deps}; +use nym_contracts_common::signing::Nonce; use nym_name_service_common::{ msg::QueryMsg, response::{ConfigResponse, PagedNamesListResponse}, - NameEntry, NameId, + NameId, RegisteredName, }; -use crate::{constants::NAME_DEFAULT_RETRIEVAL_LIMIT, error::NameServiceError}; +use crate::{constants::NAME_DEFAULT_RETRIEVAL_LIMIT, NameServiceError}; pub fn assert_config(deps: Deps, admin: &Addr, deposit_required: Coin) { crate::state::assert_admin(deps, admin).unwrap(); @@ -14,10 +15,10 @@ pub fn assert_config(deps: Deps, admin: &Addr, deposit_required: Coin) { assert_eq!(config, ConfigResponse { deposit_required }); } -pub fn assert_names(deps: Deps, expected_names: &[NameEntry]) { +pub fn assert_names(deps: Deps, expected_names: &[RegisteredName]) { let res = crate::contract::query(deps, mock_env(), QueryMsg::all()).unwrap(); let names: PagedNamesListResponse = from_binary(&res).unwrap(); - let start_next_after = expected_names.iter().last().map(|s| s.name_id); + let start_next_after = expected_names.iter().last().map(|s| s.id); assert_eq!( names, PagedNamesListResponse { @@ -28,16 +29,16 @@ pub fn assert_names(deps: Deps, expected_names: &[NameEntry]) { ); } -pub fn assert_name(deps: Deps, expected_name: &NameEntry) { +pub fn assert_name(deps: Deps, expected_name: &RegisteredName) { let res = crate::contract::query( deps, mock_env(), QueryMsg::NameId { - name_id: expected_name.name_id, + name_id: expected_name.id, }, ) .unwrap(); - let names: NameEntry = from_binary(&res).unwrap(); + let names: RegisteredName = from_binary(&res).unwrap(); assert_eq!(&names, expected_name); } @@ -63,3 +64,16 @@ pub fn assert_not_found(deps: Deps, expected_id: NameId) { } )); } + +pub fn assert_current_nonce(deps: Deps, address: &Addr, expected_nonce: Nonce) { + let res = crate::contract::query( + deps, + mock_env(), + QueryMsg::SigningNonce { + address: address.to_string(), + }, + ) + .unwrap(); + let nonce: Nonce = from_binary(&res).unwrap(); + assert_eq!(nonce, expected_nonce); +} diff --git a/contracts/name-service/src/test_helpers/fixture.rs b/contracts/name-service/src/test_helpers/fixture.rs index 3df82f6086..5c24ece5d8 100644 --- a/contracts/name-service/src/test_helpers/fixture.rs +++ b/contracts/name-service/src/test_helpers/fixture.rs @@ -1,29 +1,103 @@ -use cosmwasm_std::Addr; -use nym_name_service_common::{Address, NameEntry, NameId, NymName, RegisteredName}; +use cosmwasm_std::{Addr, Coin, DepsMut}; +use nym_contracts_common::{signing::MessageSignature, IdentityKeyRef}; +use nym_crypto::asymmetric::identity; +use nym_name_service_common::{Address, NameDetails, NameId, NymName, RegisteredName}; +use rand_chacha::rand_core::{CryptoRng, RngCore}; -use super::helpers::nyms; +use super::{ + helpers::nyms, + signing::{ed25519_sign_message, name_register_sign_payload}, +}; -pub fn name_fixture_full(name: &str, nym_address: &str, owner: &str) -> RegisteredName { +pub fn new_name( + name_id: NameId, + name: &NymName, + address: &Address, + owner: &Addr, + identity_key: IdentityKeyRef, +) -> RegisteredName { RegisteredName { - name: NymName::new(name).unwrap(), - address: Address::new(nym_address), - owner: Addr::unchecked(owner), + id: name_id, + name: NameDetails { + name: name.clone(), + address: address.clone(), + identity_key: identity_key.to_string(), + }, + owner: owner.clone(), block_height: 12345, deposit: nyms(100), } } -pub fn name_fixture() -> RegisteredName { - name_fixture_full("my-service", "client_id.client_key@gateway_id", "steve") +pub fn name_fixture(id: NameId) -> RegisteredName { + new_name( + id, + &NymName::new("my-service").unwrap(), + &Address::new("client_id.client_key@gateway_id"), + &Addr::unchecked("steve"), + "identity", + ) } -pub fn name_fixture_name(name: &str) -> RegisteredName { - name_fixture_full(name, "client_id.client_key@gateway_id", "steve") +#[allow(unused)] +pub fn name_fixture_with_name(id: NameId, name: &str, address: &str) -> RegisteredName { + new_name( + id, + &NymName::new(name).unwrap(), + &Address::new(address), + &Addr::unchecked("steve"), + "identity", + ) } -pub fn name_entry(name_id: NameId, name: NymName, address: Address, owner: Addr) -> NameEntry { - NameEntry { - name_id, - name: name_fixture_full(name.as_str(), address.as_str(), owner.as_str()), - } +pub fn name_fixture_full(id: NameId, name: &str, address: &str, owner: &str) -> RegisteredName { + new_name( + id, + &NymName::new(name).unwrap(), + &Address::new(address), + &Addr::unchecked(owner), + "identity", + ) +} + +// Create a new name, using a correctly generted identity key +pub fn new_name_details( + rng: &mut R, + name: &str, + nym_address: &str, +) -> (NameDetails, identity::KeyPair) +where + R: RngCore + CryptoRng, +{ + let keypair = identity::KeyPair::new(rng); + ( + NameDetails { + name: NymName::new(name).unwrap(), + address: Address::new(nym_address), + identity_key: keypair.public_key().to_base58_string(), + }, + keypair, + ) +} + +// Create a new service, with a correctly generated identity key, and sign it +pub fn new_name_details_with_sign( + deps: DepsMut<'_>, + rng: &mut R, + name: &str, + nym_address: &str, + owner: &str, + deposit: Coin, +) -> (NameDetails, MessageSignature) +where + R: RngCore + CryptoRng, +{ + // Service + let (name, keypair) = new_name_details(rng, name, nym_address); + + // Sign + let sign_msg = name_register_sign_payload(deps.as_ref(), owner, name.clone(), deposit); + let owner_signature = ed25519_sign_message(sign_msg, keypair.private_key()); + + (name, owner_signature) } diff --git a/contracts/name-service/src/test_helpers/helpers.rs b/contracts/name-service/src/test_helpers/helpers.rs index 0bd4f2ef5f..145802e061 100644 --- a/contracts/name-service/src/test_helpers/helpers.rs +++ b/contracts/name-service/src/test_helpers/helpers.rs @@ -1,19 +1,16 @@ -use cosmwasm_std::{ - coin, coins, - testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier}, - Coin, DepsMut, Event, MemoryStorage, OwnedDeps, Response, -}; +use cosmwasm_std::{Coin, Event, Response}; use cw_multi_test::AppResponse; -use nym_name_service_common::{ - events::{NameEventType, NAME_ID}, - msg::{ExecuteMsg, InstantiateMsg}, - NameId, NymName, RegisteredName, -}; +use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; pub fn nyms(amount: u64) -> Coin { Coin::new(amount.into(), "unym") } +pub fn test_rng() -> ChaCha20Rng { + let dummy_seed = [42u8; 32]; + ChaCha20Rng::from_seed(dummy_seed) +} + pub fn get_event_types(response: &Response, event_type: &str) -> Vec { response .events @@ -55,53 +52,3 @@ pub fn get_app_attribute(response: &AppResponse, event_type: &str, key: &str) -> .value .clone() } - -#[allow(unused)] -pub fn get_app_attributes(response: &AppResponse, event_type: &str, key: &str) -> Vec { - get_app_event_types(response, event_type) - .iter() - .map(|ev| { - ev.attributes - .iter() - .find(|attr| attr.key == key) - .unwrap() - .value - .clone() - }) - .collect::>() -} - -pub fn instantiate_test_contract() -> OwnedDeps { - let mut deps = mock_dependencies(); - let msg = InstantiateMsg { - deposit_required: coin(100, "unym"), - }; - let env = mock_env(); - let info = mock_info("creator", &[]); - let res = crate::instantiate(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(res.messages.len(), 0); - deps -} - -pub fn register_name(deps: DepsMut<'_>, name: &RegisteredName) -> NameId { - let msg: ExecuteMsg = name.clone().into(); - let info = mock_info(name.owner.as_str(), &coins(100, "unym")); - let res = crate::execute(deps, mock_env(), info, msg).unwrap(); - let name_id: NameId = get_attribute(&res, &NameEventType::Register.to_string(), NAME_ID) - .parse() - .unwrap(); - name_id -} - -pub fn delete_name_id(deps: DepsMut<'_>, name_id: NameId, owner: &str) { - let msg = ExecuteMsg::DeleteId { name_id }; - let info = mock_info(owner, &[]); - crate::execute(deps, mock_env(), info, msg).unwrap(); -} - -#[allow(unused)] -pub fn delete_name(deps: DepsMut<'_>, name: NymName, owner: &str) { - let msg = ExecuteMsg::DeleteName { name }; - let info = mock_info(owner, &[]); - crate::execute(deps, mock_env(), info, msg).unwrap(); -} diff --git a/contracts/name-service/src/test_helpers/mod.rs b/contracts/name-service/src/test_helpers/mod.rs index b1e4a18e01..ee0717f4e4 100644 --- a/contracts/name-service/src/test_helpers/mod.rs +++ b/contracts/name-service/src/test_helpers/mod.rs @@ -1,4 +1,5 @@ pub mod assert; pub mod fixture; pub mod helpers; -pub mod test_setup; +pub mod signing; +pub mod transactions; diff --git a/contracts/name-service/src/test_helpers/signing.rs b/contracts/name-service/src/test_helpers/signing.rs new file mode 100644 index 0000000000..d7431fc7ed --- /dev/null +++ b/contracts/name-service/src/test_helpers/signing.rs @@ -0,0 +1,39 @@ +use cosmwasm_std::{Addr, Coin, Deps}; +use nym_contracts_common::signing::{ + MessageSignature, SignableMessage, SigningAlgorithm, SigningPurpose, +}; +use nym_crypto::asymmetric::identity; +use nym_name_service_common::{ + signing_types::{construct_name_register_sign_payload, SignableNameRegisterMsg}, + NameDetails, +}; +use serde::Serialize; + +use crate::state; + +pub fn name_register_sign_payload( + deps: Deps<'_>, + owner: &str, + name: NameDetails, + deposit: Coin, +) -> SignableNameRegisterMsg { + let owner = Addr::unchecked(owner); + let nonce = state::get_signing_nonce(deps.storage, owner.clone()).unwrap(); + construct_name_register_sign_payload(nonce, owner, deposit, name) +} + +pub fn ed25519_sign_message( + message: SignableMessage, + private_key: &identity::PrivateKey, +) -> MessageSignature { + match message.algorithm { + SigningAlgorithm::Ed25519 => { + let plaintext = message.to_plaintext().unwrap(); + let signature = private_key.sign(&plaintext); + MessageSignature::from(signature.to_bytes().as_ref()) + } + SigningAlgorithm::Secp256k1 => { + unimplemented!() + } + } +} diff --git a/contracts/name-service/src/test_helpers/transactions.rs b/contracts/name-service/src/test_helpers/transactions.rs new file mode 100644 index 0000000000..6458ad5b3e --- /dev/null +++ b/contracts/name-service/src/test_helpers/transactions.rs @@ -0,0 +1,72 @@ +use cosmwasm_std::{ + coin, + testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier}, + DepsMut, MemoryStorage, OwnedDeps, +}; +use nym_name_service_common::{ + events::{NameEventType, NAME_ID}, + msg::{ExecuteMsg, InstantiateMsg}, + NameDetails, NameId, NymName, +}; +use rand_chacha::rand_core::{CryptoRng, RngCore}; + +use super::helpers::{get_attribute, nyms}; + +pub fn instantiate_test_contract() -> OwnedDeps { + let mut deps = mock_dependencies(); + let msg = InstantiateMsg { + deposit_required: coin(100, "unym"), + }; + let env = mock_env(); + let info = mock_info("creator", &[]); + let res = crate::instantiate(deps.as_mut(), env, info, msg).unwrap(); + assert_eq!(res.messages.len(), 0); + deps +} + +pub fn register_name( + mut deps: DepsMut<'_>, + rng: &mut R, + name: &str, + nym_address: &str, + owner: &str, +) -> (NameId, NameDetails) +where + R: RngCore + CryptoRng, +{ + let deposit = nyms(100); + let (name, owner_signature) = super::fixture::new_name_details_with_sign( + deps.branch(), + rng, + name, + nym_address, + owner, + deposit.clone(), + ); + + // Register + let msg = ExecuteMsg::Register { + name: name.clone(), + owner_signature, + }; + let info = mock_info(owner, &[deposit]); + let res = crate::execute(deps, mock_env(), info, msg).unwrap(); + + let name_id: NameId = get_attribute(&res, &NameEventType::Register.to_string(), NAME_ID) + .parse() + .unwrap(); + (name_id, name) +} + +pub fn delete_name_id(deps: DepsMut<'_>, name_id: NameId, owner: &str) { + let msg = ExecuteMsg::DeleteId { name_id }; + let info = mock_info(owner, &[]); + crate::execute(deps, mock_env(), info, msg).unwrap(); +} + +#[allow(unused)] +pub fn delete_name(deps: DepsMut<'_>, name: NymName, owner: &str) { + let msg = ExecuteMsg::DeleteName { name }; + let info = mock_info(owner, &[]); + crate::execute(deps, mock_env(), info, msg).unwrap(); +} diff --git a/nym-api/src/nym_contract_cache/cache/data.rs b/nym-api/src/nym_contract_cache/cache/data.rs index 235afdb630..27285db41a 100644 --- a/nym-api/src/nym_contract_cache/cache/data.rs +++ b/nym-api/src/nym_contract_cache/cache/data.rs @@ -6,7 +6,7 @@ use nym_mixnet_contract_common::{ families::FamilyHead, GatewayBond, IdentityKey, Interval, MixId, MixNodeDetails, RewardingParams, }; -use nym_name_service_common::NameEntry; +use nym_name_service_common::RegisteredName; use nym_service_provider_directory_common::Service; use std::collections::HashSet; @@ -26,7 +26,7 @@ pub(crate) struct ValidatorCacheData { pub(crate) mix_to_family: Cache>, pub(crate) service_providers: Cache>, - pub(crate) registered_names: Cache>, + pub(crate) registered_names: Cache>, } impl ValidatorCacheData { diff --git a/nym-api/src/nym_contract_cache/cache/mod.rs b/nym-api/src/nym_contract_cache/cache/mod.rs index 13e2783e47..2eac4f0c61 100644 --- a/nym-api/src/nym_contract_cache/cache/mod.rs +++ b/nym-api/src/nym_contract_cache/cache/mod.rs @@ -5,7 +5,7 @@ use nym_mixnet_contract_common::{ families::FamilyHead, GatewayBond, IdentityKey, Interval, MixId, MixNodeBond, MixNodeDetails, RewardingParams, }; -use nym_name_service_common::NameEntry; +use nym_name_service_common::RegisteredName; use nym_service_provider_directory_common::Service; use rocket::fairing::AdHoc; use std::{ @@ -53,7 +53,7 @@ impl NymContractCache { current_interval: Interval, mix_to_family: Vec<(IdentityKey, FamilyHead)>, services: Option>, - names: Option>, + names: Option>, ) { match time::timeout(Duration::from_millis(100), self.inner.write()).await { Ok(mut cache) => { @@ -303,7 +303,7 @@ impl NymContractCache { } } - pub(crate) async fn names(&self) -> Cache> { + pub(crate) async fn names(&self) -> Cache> { match time::timeout(Duration::from_millis(100), self.inner.read()).await { Ok(cache) => cache.registered_names.clone(), Err(err) => { diff --git a/nym-connect/desktop/Cargo.lock b/nym-connect/desktop/Cargo.lock index 2ac9e0852a..0cb8b27caf 100644 --- a/nym-connect/desktop/Cargo.lock +++ b/nym-connect/desktop/Cargo.lock @@ -3564,8 +3564,12 @@ name = "nym-name-service-common" version = "0.1.0" dependencies = [ "cosmwasm-std", + "cw-controllers", + "cw-utils", + "nym-contracts-common", "schemars", "serde", + "thiserror", ] [[package]] diff --git a/nym-wallet/Cargo.lock b/nym-wallet/Cargo.lock index 70502fc84a..fa2722e281 100644 --- a/nym-wallet/Cargo.lock +++ b/nym-wallet/Cargo.lock @@ -3086,8 +3086,12 @@ name = "nym-name-service-common" version = "0.1.0" dependencies = [ "cosmwasm-std", + "cw-controllers", + "cw-utils", + "nym-contracts-common", "schemars", "serde", + "thiserror", ] [[package]] From 271a5fbab6cb33443837f4302c4497e19a66f930 Mon Sep 17 00:00:00 2001 From: Pierre Dommerc Date: Tue, 4 Jul 2023 11:56:23 +0200 Subject: [PATCH 40/74] ci: gh actions strapi (#3616) --- .../workflows/nym-connect-publish-macos.yml | 39 +++- .../workflows/nym-connect-publish-ubuntu.yml | 39 +++- .../nym-connect-publish-windows10.yml | 39 +++- .github/workflows/nym-release-publish.yml | 182 +++++++++++++++++- .../workflows/nym-wallet-publish-macos.yml | 40 +++- .../workflows/nym-wallet-publish-ubuntu.yml | 39 +++- .../nym-wallet-publish-windows10.yml | 39 +++- .github/workflows/push-release-data.yml | 18 +- 8 files changed, 411 insertions(+), 24 deletions(-) diff --git a/.github/workflows/nym-connect-publish-macos.yml b/.github/workflows/nym-connect-publish-macos.yml index 379443d4dd..e536ad5a08 100644 --- a/.github/workflows/nym-connect-publish-macos.yml +++ b/.github/workflows/nym-connect-publish-macos.yml @@ -15,8 +15,15 @@ jobs: fail-fast: false matrix: platform: [macos-latest] - runs-on: ${{ matrix.platform }} + + outputs: + release_id: ${{ steps.create-release.outputs.id }} + release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }} + version: ${{ steps.release-info.outputs.version }} + filename: ${{ steps.release-info.outputs.filename }} + file_hash: ${{ steps.release-info.outputs.file_hash }} + steps: - uses: actions/checkout@v2 @@ -81,10 +88,38 @@ jobs: run: | security delete-keychain $RUNNER_TEMP/app-signing.keychain-db - - name: Upload to release based on tag name + - id: create-release + name: Upload to release based on tag name uses: softprops/action-gh-release@v1 if: github.event_name == 'release' with: files: | nym-connect/desktop/target/release/bundle/dmg/*.dmg nym-connect/desktop/target/release/bundle/macos/*.app.tar.gz* + - id: release-info + name: Prepare release info + run: | + semver="${${{ github.ref_name }}##nym-connect-}" && semver="${semver##v}" + echo "version=$semver" >> "$GITHUB_OUTPUT" + echo "filename=nym-connect_$version_x64.dmg" >> "$GITHUB_OUTPUT" + echo "file_hash=${{ hashFiles('nym-connect/desktop/target/release/bundle/dmg/nym-connect_*_x64.dmg') }}" >> "$GITHUB_OUTPUT" + + push-release-data: + if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }} + uses: ./.github/workflows/push-release-data.yml + needs: publish-tauri + with: + release_tag: ${{ github.ref_name }} + release_id: ${{ needs.publish-tauri.outputs.release_id }} + release_date: ${{ needs.publish-tauri.outputs.release_date }} + download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }} + changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-connect/desktop/CHANGELOG.md + archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect.app.tar.gz + sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect.app.tar.gz.sig + version: ${{ needs.publish-tauri.outputs.version }} + filename: ${{ needs.publish-tauri.outputs.filename }} + file_hash: ${{ needs.publish-tauri.outputs.file_hash }} + name: NymConnect + category: connect + platform: MacOS + secrets: inherit diff --git a/.github/workflows/nym-connect-publish-ubuntu.yml b/.github/workflows/nym-connect-publish-ubuntu.yml index 25d288581d..1618167a26 100644 --- a/.github/workflows/nym-connect-publish-ubuntu.yml +++ b/.github/workflows/nym-connect-publish-ubuntu.yml @@ -15,8 +15,15 @@ jobs: fail-fast: false matrix: platform: [custom-runner-linux] - runs-on: ${{ matrix.platform }} + + outputs: + release_id: ${{ steps.create-release.outputs.id }} + release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }} + version: ${{ steps.release-info.outputs.version }} + filename: ${{ steps.release-info.outputs.filename }} + file_hash: ${{ steps.release-info.outputs.file_hash }} + steps: - uses: actions/checkout@v2 @@ -56,10 +63,38 @@ jobs: path: nym-connect/desktop/target/release/bundle/appimage/nym-connect_1.0.0_amd64.AppImage retention-days: 30 - - name: Upload to release based on tag name + - id: create-release + name: Upload to release based on tag name uses: softprops/action-gh-release@v1 if: github.event_name == 'release' with: files: | nym-connect/desktop/target/release/bundle/appimage/*.AppImage nym-connect/desktop/target/release/bundle/appimage/*.AppImage.tar.gz* + - id: release-info + name: Prepare release info + run: | + semver="${${{ github.ref_name }}##nym-connect-}" && semver="${semver##v}" + echo "version=$semver" >> "$GITHUB_OUTPUT" + echo "filename=nym-connect_$version_amd64.AppImage" >> "$GITHUB_OUTPUT" + echo "file_hash=${{ hashFiles('nym-connect/desktop/target/release/bundle/appimage/nym-connect_*_amd64.AppImage') }}" >> "$GITHUB_OUTPUT" + + push-release-data: + if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }} + uses: ./.github/workflows/push-release-data.yml + needs: publish-tauri + with: + release_tag: ${{ github.ref_name }} + release_id: ${{ needs.publish-tauri.outputs.release_id }} + release_date: ${{ needs.publish-tauri.outputs.release_date }} + download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }} + changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-connect/desktop/CHANGELOG.md + archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect_${{ needs.publish-tauri.outputs.version }}_amd64.AppImage.tar.gz + sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect_${{ needs.publish-tauri.outputs.version }}_amd64.AppImage.tar.gz.sig + version: ${{ needs.publish-tauri.outputs.version }} + filename: ${{ needs.publish-tauri.outputs.filename }} + file_hash: ${{ needs.publish-tauri.outputs.file_hash }} + name: NymConnect + category: connect + platform: Ubuntu + secrets: inherit diff --git a/.github/workflows/nym-connect-publish-windows10.yml b/.github/workflows/nym-connect-publish-windows10.yml index 4a869caf3e..9b568cfd74 100644 --- a/.github/workflows/nym-connect-publish-windows10.yml +++ b/.github/workflows/nym-connect-publish-windows10.yml @@ -15,8 +15,15 @@ jobs: fail-fast: false matrix: platform: [windows10] - runs-on: ${{ matrix.platform }} + + outputs: + release_id: ${{ steps.create-release.outputs.id }} + release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }} + version: ${{ steps.release-info.outputs.version }} + filename: ${{ steps.release-info.outputs.filename }} + file_hash: ${{ steps.release-info.outputs.file_hash }} + steps: - name: Clean up first continue-on-error: true @@ -75,10 +82,38 @@ jobs: path: nym-connect/desktop/target/release/bundle/msi/nym-connect_1.0.0_x64_en-US.msi retention-days: 30 - - name: Upload to release based on tag name + - id: create-release + name: Upload to release based on tag name uses: softprops/action-gh-release@v1 if: github.event_name == 'release' with: files: | nym-connect/desktop/target/release/bundle/msi/*.msi nym-connect/desktop/target/release/bundle/msi/*.msi.zip* + - id: release-info + name: Prepare release info + run: | + semver="${${{ github.ref_name }}##nym-connect-}" && semver="${semver##v}" + echo "version=$semver" >> "$GITHUB_OUTPUT" + echo "filename=nym-connect_$version_x64_en-US.msi" >> "$GITHUB_OUTPUT" + echo "file_hash=${{ hashFiles('nym-connect/desktop/target/release/bundle/msi/nym-connect_*_x64_en-US.msi') }}" >> "$GITHUB_OUTPUT" + + push-release-data: + if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }} + uses: ./.github/workflows/push-release-data.yml + needs: publish-tauri + with: + release_tag: ${{ github.ref_name }} + release_id: ${{ needs.publish-tauri.outputs.release_id }} + release_date: ${{ needs.publish-tauri.outputs.release_date }} + download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }} + changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-connect/desktop/CHANGELOG.md + archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect_${{ needs.publish-tauri.outputs.version }}_x64_en-US.msi.zip + sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect_${{ needs.publish-tauri.outputs.version }}_x64_en-US.msi.zip.sig + version: ${{ needs.publish-tauri.outputs.version }} + filename: ${{ needs.publish-tauri.outputs.filename }} + file_hash: ${{ needs.publish-tauri.outputs.file_hash }} + name: NymConnect + category: connect + platform: Windows + secrets: inherit diff --git a/.github/workflows/nym-release-publish.yml b/.github/workflows/nym-release-publish.yml index a73eabfcb3..9252d7122d 100644 --- a/.github/workflows/nym-release-publish.yml +++ b/.github/workflows/nym-release-publish.yml @@ -2,17 +2,17 @@ name: Publish Nym binaries on: workflow_dispatch: - inputs: + inputs: add_tokio_unstable: description: 'True to add RUSTFLAGS="--cfg tokio_unstable"' required: true default: false - type: boolean + type: boolean release: types: [created] - + env: - NETWORK: mainnet + NETWORK: mainnet jobs: publish-nym: @@ -21,15 +21,33 @@ jobs: fail-fast: false matrix: platform: [custom-runner-linux] - runs-on: ${{ matrix.platform }} + + outputs: + release_id: ${{ steps.create-release.outputs.id }} + release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }} + client_hash: ${{ steps.binary-hashes.outputs.client_hash }} + mixnode_hash: ${{ steps.binary-hashes.outputs.mixnode_hash }} + gateway_hash: ${{ steps.binary-hashes.outputs.gateway_hash }} + socks5_hash: ${{ steps.binary-hashes.outputs.socks5_hash }} + netreq_hash: ${{ steps.binary-hashes.outputs.netreq_hash }} + cli_hash: ${{ steps.binary-hashes.outputs.cli_hash }} + netstat_hash: ${{ steps.binary-hashes.outputs.netstat_hash }} + client_version: ${{ steps.binary-versions.outputs.client_version }} + mixnode_version: ${{ steps.binary-versions.outputs.mixnode_version }} + gateway_version: ${{ steps.binary-versions.outputs.gateway_version }} + socks5_version: ${{ steps.binary-versions.outputs.socks5_version }} + netreq_version: ${{ steps.binary-versions.outputs.netreq_version }} + cli_version: ${{ steps.binary-versions.outputs.cli_version }} + netstat_version: ${{ steps.binary-versions.outputs.netstat_version }} + steps: - uses: actions/checkout@v3 - name: Install Dependencies (Linux) - run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools + run: sudo apt-get update && sudo apt-get -y install ripgrep libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools continue-on-error: true - + - name: Sets env vars for tokio if set in manual dispatch inputs run: | echo 'RUSTFLAGS="--cfg tokio_unstable"' >> $GITHUB_ENV @@ -62,7 +80,8 @@ jobs: target/release/nym-cli retention-days: 30 - - name: Upload to release based on tag name + - id: create-release + name: Upload to release based on tag name uses: softprops/action-gh-release@v1 if: github.event_name == 'release' with: @@ -76,3 +95,150 @@ jobs: target/release/nym-network-requester target/release/nym-network-statistics target/release/nym-cli + + - id: release-info + name: Prepare release info + run: | + semver="${${{ github.ref_name }}##nym-binaries-}" && semver="${semver##v}" + echo "version=$semver" >> "$GITHUB_OUTPUT" + + - id: binary-hashes + name: Generate binary hashes + run: | + echo "client_hash=${{ hashFiles('target/release/nym-client') }}" >> "$GITHUB_OUTPUT" + echo "mixnode_hash=${{ hashFiles('target/release/nym-mixnode') }}" >> "$GITHUB_OUTPUT" + echo "gateway_hash=${{ hashFiles('target/release/nym-gateway') }}" >> "$GITHUB_OUTPUT" + echo "socks5_hash=${{ hashFiles('target/release/nym-socks5-client') }}" >> "$GITHUB_OUTPUT" + echo "netreq_hash=${{ hashFiles('target/release/nym-network-requester') }}" >> "$GITHUB_OUTPUT" + echo "cli_hash=${{ hashFiles('target/release/nym-cli') }}" >> "$GITHUB_OUTPUT" + echo "netstat_hash=${{ hashFiles('target/release/nym-network-statistics') }}" >> "$GITHUB_OUTPUT" + + - id: binary-versions + name: Get binary versions + run: | + v=$(rg '^version = "(.*)"' -or '$1' clients/native/Cargo.toml) && echo "client_version=$v" >> "$GITHUB_OUTPUT" + v=$(rg '^version = "(.*)"' -or '$1' mixnode/Cargo.toml) && echo "mixnode_version=$v" >> "$GITHUB_OUTPUT" + v=$(rg '^version = "(.*)"' -or '$1' gateway/Cargo.toml) && echo "gateway_version=$v" >> "$GITHUB_OUTPUT" + v=$(rg '^version = "(.*)"' -or '$1' clients/socks5/Cargo.toml) && echo "socks5_version=$v" >> "$GITHUB_OUTPUT" + v=$(rg '^version = "(.*)"' -or '$1' service-providers/network-requester/Cargo.toml) && echo "netreq_version=$v" >> "$GITHUB_OUTPUT" + v=$(rg '^version = "(.*)"' -or '$1' tools/nym-cli/Cargo.toml) && echo "cli_version=$v" >> "$GITHUB_OUTPUT" + v=$(rg '^version = "(.*)"' -or '$1' service-providers/network-statistics/Cargo.toml) && echo "netstat_version=$v" >> "$GITHUB_OUTPUT" + + push-release-data-client: + if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }} + uses: ./.github/workflows/push-release-data.yml + needs: publish-nym + with: + release_tag: ${{ github.ref_name }} + release_id: ${{ needs.publish-nym.outputs.release_id }} + release_date: ${{ needs.publish-nym.outputs.release_date }} + download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }} + changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md + version: ${{ needs.publish-nym.outputs.client_version }} + filename: nym-client + file_hash: ${{ needs.publish-nym.outputs.client_hash }} + name: Client + category: binaries + secrets: inherit + + push-release-data-mixnode: + if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }} + uses: ./.github/workflows/push-release-data.yml + needs: publish-nym + with: + release_tag: ${{ github.ref_name }} + release_id: ${{ needs.publish-nym.outputs.release_id }} + release_date: ${{ needs.publish-nym.outputs.release_date }} + download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }} + changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md + version: ${{ needs.publish-nym.outputs.mixnode_version }} + filename: nym-mixnode + file_hash: ${{ needs.publish-nym.outputs.mixnode_hash }} + name: Mixnode + category: binaries + secrets: inherit + + push-release-data-gateway: + if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }} + uses: ./.github/workflows/push-release-data.yml + needs: publish-nym + with: + release_tag: ${{ github.ref_name }} + release_id: ${{ needs.publish-nym.outputs.release_id }} + release_date: ${{ needs.publish-nym.outputs.release_date }} + download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }} + changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md + version: ${{ needs.publish-nym.outputs.gateway_version }} + filename: nym-gateway + file_hash: ${{ needs.publish-nym.outputs.gateway_hash }} + name: Gateway + category: binaries + secrets: inherit + + push-release-data-socks5: + if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }} + uses: ./.github/workflows/push-release-data.yml + needs: publish-nym + with: + release_tag: ${{ github.ref_name }} + release_id: ${{ needs.publish-nym.outputs.release_id }} + release_date: ${{ needs.publish-nym.outputs.release_date }} + download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }} + changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md + version: ${{ needs.publish-nym.outputs.socks5_version }} + filename: nym-socks5-client + file_hash: ${{ needs.publish-nym.outputs.socks5_hash }} + name: Socks5 Client + category: binaries + secrets: inherit + + push-release-data-network-requester: + if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }} + uses: ./.github/workflows/push-release-data.yml + needs: publish-nym + with: + release_tag: ${{ github.ref_name }} + release_id: ${{ needs.publish-nym.outputs.release_id }} + release_date: ${{ needs.publish-nym.outputs.release_date }} + download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }} + changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md + version: ${{ needs.publish-nym.outputs.netreq_version }} + filename: nym-network-requester + file_hash: ${{ needs.publish-nym.outputs.netreq_hash }} + name: Network Requester + category: binaries + secrets: inherit + + push-release-data-cli: + if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }} + uses: ./.github/workflows/push-release-data.yml + needs: publish-nym + with: + release_tag: ${{ github.ref_name }} + release_id: ${{ needs.publish-nym.outputs.release_id }} + release_date: ${{ needs.publish-nym.outputs.release_date }} + download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }} + changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md + version: ${{ needs.publish-nym.outputs.cli_version }} + filename: nym-cli + file_hash: ${{ needs.publish-nym.outputs.cli_hash }} + name: Cli + category: binaries + secrets: inherit + + push-release-data-network-stat: + if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }} + uses: ./.github/workflows/push-release-data.yml + needs: publish-nym + with: + release_tag: ${{ github.ref_name }} + release_id: ${{ needs.publish-nym.outputs.release_id }} + release_date: ${{ needs.publish-nym.outputs.release_date }} + download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }} + changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md + version: ${{ needs.publish-nym.outputs.netstat_version }} + filename: nym-network-statistics + file_hash: ${{ needs.publish-nym.outputs.netstat_hash }} + name: Network Statistics + category: binaries + secrets: inherit diff --git a/.github/workflows/nym-wallet-publish-macos.yml b/.github/workflows/nym-wallet-publish-macos.yml index 81c27a8338..2216222498 100644 --- a/.github/workflows/nym-wallet-publish-macos.yml +++ b/.github/workflows/nym-wallet-publish-macos.yml @@ -15,8 +15,15 @@ jobs: fail-fast: false matrix: platform: [macos-latest] - runs-on: ${{ matrix.platform }} + + outputs: + release_id: ${{ steps.create-release.outputs.id }} + release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }} + version: ${{ steps.release-info.outputs.version }} + filename: ${{ steps.release-info.outputs.filename }} + file_hash: ${{ steps.release-info.outputs.file_hash }} + steps: - uses: actions/checkout@v2 @@ -80,11 +87,38 @@ jobs: if: ${{ always() }} run: | security delete-keychain $RUNNER_TEMP/app-signing.keychain-db - - - name: Upload to release based on tag name + - id: create-release + name: Upload to release based on tag name uses: softprops/action-gh-release@v1 if: github.event_name == 'release' with: files: | nym-wallet/target/release/bundle/dmg/*.dmg nym-wallet/target/release/bundle/macos/*.app.tar.gz* + - id: release-info + name: Prepare release info + run: | + semver="${${{ github.ref_name }}##nym-wallet-}" && semver="${semver##v}" + echo "version=$semver" >> "$GITHUB_OUTPUT" + echo "filename=nym-wallet_$version_x64.dmg" >> "$GITHUB_OUTPUT" + echo "file_hash=${{ hashFiles('nym-wallet/target/release/bundle/dmg/nym-wallet_*_x64.dmg') }}" >> "$GITHUB_OUTPUT" + + push-release-data: + if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }} + uses: ./.github/workflows/push-release-data.yml + needs: publish-tauri + with: + release_tag: ${{ github.ref_name }} + release_id: ${{ needs.publish-tauri.outputs.release_id }} + release_date: ${{ needs.publish-tauri.outputs.release_date }} + download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }} + changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-wallet/CHANGELOG.md + archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet.app.tar.gz + sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet.app.tar.gz.sig + version: ${{ needs.publish-tauri.outputs.version }} + filename: ${{ needs.publish-tauri.outputs.filename }} + file_hash: ${{ needs.publish-tauri.outputs.file_hash }} + name: Wallet + category: wallet + platform: MacOS + secrets: inherit diff --git a/.github/workflows/nym-wallet-publish-ubuntu.yml b/.github/workflows/nym-wallet-publish-ubuntu.yml index 1f2bb0330d..bd40db0783 100644 --- a/.github/workflows/nym-wallet-publish-ubuntu.yml +++ b/.github/workflows/nym-wallet-publish-ubuntu.yml @@ -14,8 +14,15 @@ jobs: fail-fast: false matrix: platform: [custom-runner-linux] - runs-on: ${{ matrix.platform }} + + outputs: + release_id: ${{ steps.create-release.outputs.id }} + release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }} + version: ${{ steps.release-info.outputs.version }} + filename: ${{ steps.release-info.outputs.filename }} + file_hash: ${{ steps.release-info.outputs.file_hash }} + steps: - uses: actions/checkout@v2 @@ -47,9 +54,37 @@ jobs: env: TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} - - name: Upload to release based on tag name + - id: create-release + name: Upload to release based on tag name uses: softprops/action-gh-release@v1 with: files: | nym-wallet/target/release/bundle/appimage/*.AppImage nym-wallet/target/release/bundle/appimage/*.AppImage.tar.gz* + - id: release-info + name: Prepare release info + run: | + semver="${${{ github.ref_name }}##nym-wallet-}" && semver="${semver##v}" + echo "version=$semver" >> "$GITHUB_OUTPUT" + echo "filename=nym-wallet_$version_amd64.AppImage" >> "$GITHUB_OUTPUT" + echo "file_hash=${{ hashFiles('nym-wallet/target/release/bundle/appimage/nym-wallet_*_amd64.AppImage') }}" >> "$GITHUB_OUTPUT" + + push-release-data: + if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }} + uses: ./.github/workflows/push-release-data.yml + needs: publish-tauri + with: + release_tag: ${{ github.ref_name }} + release_id: ${{ needs.publish-tauri.outputs.release_id }} + release_date: ${{ needs.publish-tauri.outputs.release_date }} + download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }} + changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-wallet/CHANGELOG.md + archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet_${{ needs.publish-tauri.outputs.version }}_amd64.AppImage.tar.gz + sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet_${{ needs.publish-tauri.outputs.version }}_amd64.AppImage.tar.gz.sig + version: ${{ needs.publish-tauri.outputs.version }} + filename: ${{ needs.publish-tauri.outputs.filename }} + file_hash: ${{ needs.publish-tauri.outputs.file_hash }} + name: Wallet + category: wallet + platform: Ubuntu + secrets: inherit diff --git a/.github/workflows/nym-wallet-publish-windows10.yml b/.github/workflows/nym-wallet-publish-windows10.yml index 044816953b..567a34980f 100644 --- a/.github/workflows/nym-wallet-publish-windows10.yml +++ b/.github/workflows/nym-wallet-publish-windows10.yml @@ -15,8 +15,15 @@ jobs: fail-fast: false matrix: platform: [windows10] - runs-on: ${{ matrix.platform }} + + outputs: + release_id: ${{ steps.create-release.outputs.id }} + release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }} + version: ${{ steps.release-info.outputs.version }} + filename: ${{ steps.release-info.outputs.filename }} + file_hash: ${{ steps.release-info.outputs.file_hash }} + steps: - name: Clean up first continue-on-error: true @@ -75,10 +82,38 @@ jobs: path: nym-wallet/target/release/bundle/msi/nym-wallet_1.*.msi retention-days: 30 - - name: Upload to release based on tag name + - id: create-release + name: Upload to release based on tag name uses: softprops/action-gh-release@v1 if: github.event_name == 'release' with: files: | nym-wallet/target/release/bundle/msi/*.msi nym-wallet/target/release/bundle/msi/*.msi.zip* + - id: release-info + name: Prepare release info + run: | + semver="${${{ github.ref_name }}##nym-wallet-}" && semver="${semver##v}" + echo "version=$semver" >> "$GITHUB_OUTPUT" + echo "filename=nym-wallet_$version_x64_en-US.msi" >> "$GITHUB_OUTPUT" + echo "file_hash=${{ hashFiles('nym-wallet/target/release/bundle/msi/nym-wallet_*_x64_en-US.msi') }}" >> "$GITHUB_OUTPUT" + + push-release-data: + if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }} + uses: ./.github/workflows/push-release-data.yml + needs: publish-tauri + with: + release_tag: ${{ github.ref_name }} + release_id: ${{ needs.publish-tauri.outputs.release_id }} + release_date: ${{ needs.publish-tauri.outputs.release_date }} + download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }} + changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-wallet/CHANGELOG.md + archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet_${{ needs.publish-tauri.outputs.version }}_x64_en-US.msi.zip + sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet_${{ needs.publish-tauri.outputs.version }}_x64_en-US.msi.zip.sig + version: ${{ needs.publish-tauri.outputs.version }} + filename: ${{ needs.publish-tauri.outputs.filename }} + file_hash: ${{ needs.publish-tauri.outputs.file_hash }} + name: Wallet + category: wallet + platform: Windows + secrets: inherit diff --git a/.github/workflows/push-release-data.yml b/.github/workflows/push-release-data.yml index 96bda89178..d1aa591845 100644 --- a/.github/workflows/push-release-data.yml +++ b/.github/workflows/push-release-data.yml @@ -7,6 +7,10 @@ env: on: workflow_call: inputs: + release_tag: + required: true + description: Release tag + type: string release_id: required: true description: Release ID @@ -58,7 +62,7 @@ on: workflow_dispatch: inputs: # ⚠ since inputs are limited to 10 max for workflow_dispatch - # `archive_url` and `sig_url` properties were omitted + # some properties were omitted version: required: true description: Release version (semver) @@ -124,6 +128,10 @@ jobs: runs-on: custom-runner-linux steps: + - name: Release info + run: | + echo "version: ${{ inputs.version }}" + echo "tag: ${{ inputs.release_tag }}" - id: get_sig name: Get sig if: ${{ inputs.sig_url != null }} @@ -136,7 +144,7 @@ jobs: with: url: ${{ env.strapi_download_url }} method: 'POST' - # bearerToken: ${{ secrets.STRAPI_AUTH_TOKEN }} TODO + bearerToken: ${{ secrets.STRAPI_API_TOKEN_RELEASES }} customHeaders: '{"Content-Type": "application/json"}' data: | { @@ -165,6 +173,10 @@ jobs: if: ${{ inputs.category == 'wallet' || inputs.category == 'connect' }} steps: + - name: Release info + run: | + echo "version: ${{ inputs.version }}" + echo "tag: ${{ inputs.release_tag }}" - id: get_sig name: Get sig if: ${{ inputs.sig_url != null }} @@ -177,7 +189,7 @@ jobs: with: url: ${{ env.strapi_updater_url }} method: 'POST' - # bearerToken: ${{ secrets.STRAPI_AUTH_TOKEN }} TODO + bearerToken: ${{ secrets.STRAPI_API_TOKEN_RELEASES }} customHeaders: '{"Content-Type": "application/json"}' data: | { From 11ed3b3e45fbf24b02958ce5a29c035ecca396cf Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Tue, 4 Jul 2023 11:33:05 +0100 Subject: [PATCH 41/74] GitHub Actions: run Windows steps that use `yarn` in `bash` --- .github/workflows/nym-connect-publish-windows10.yml | 2 ++ .github/workflows/nym-wallet-publish-windows10.yml | 3 +++ 2 files changed, 5 insertions(+) diff --git a/.github/workflows/nym-connect-publish-windows10.yml b/.github/workflows/nym-connect-publish-windows10.yml index 4a869caf3e..d85b151e16 100644 --- a/.github/workflows/nym-connect-publish-windows10.yml +++ b/.github/workflows/nym-connect-publish-windows10.yml @@ -56,9 +56,11 @@ jobs: encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} - name: Install app dependencies + shell: bash run: yarn --network-timeout 100000 - name: Build and sign it + shell: bash env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }} diff --git a/.github/workflows/nym-wallet-publish-windows10.yml b/.github/workflows/nym-wallet-publish-windows10.yml index b9934bd1ff..0028074f01 100644 --- a/.github/workflows/nym-wallet-publish-windows10.yml +++ b/.github/workflows/nym-wallet-publish-windows10.yml @@ -45,6 +45,7 @@ jobs: node-version: 18 - name: Install Rust stable + shell: bash uses: actions-rs/toolchain@v1 with: toolchain: stable @@ -58,9 +59,11 @@ jobs: encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} - name: Install app dependencies + shell: bash run: yarn --network-timeout 100000 - name: Build and sign it + shell: bash env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }} From f95b9b7f4a7d02fdd03506cc9a7bac95b189c27f Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Tue, 4 Jul 2023 11:37:00 +0100 Subject: [PATCH 42/74] Add `preinstall` targets to some `package.json` files to build pre-requisites --- nym-wallet/package.json | 3 ++- package.json | 4 ++-- sdk/typescript/packages/sdk/package.json | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/nym-wallet/package.json b/nym-wallet/package.json index d6c7cdf442..ad02b9a010 100644 --- a/nym-wallet/package.json +++ b/nym-wallet/package.json @@ -18,7 +18,8 @@ "lint:fix": "eslint src --fix", "prestorybook": "yarn --cwd .. build", "storybook": "start-storybook -p 6006", - "storybook:build": "build-storybook" + "storybook:build": "build-storybook", + "preinstall": "yarn --cwd .. build" }, "dependencies": { "@emotion/react": "^11.7.0", diff --git a/package.json b/package.json index 58d32165d3..627359351b 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "build": "run-s build:types build:packages", "build:types": "lerna run --scope @nymproject/types build --stream", "build:packages": "run-s build:packages:theme build:packages:react build:packages:sdk", - "build:packages:sdk": "lerna run --scope @nymproject/sdk build:lint", + "build:packages:sdk": "lerna run --scope @nymproject/sdk build:local", "build:packages:theme": "lerna run --scope @nymproject/mui-theme build", "build:packages:react": "lerna run --scope @nymproject/react build", "build:react-example": "lerna run --scope @nymproject/react-webpack-with-theme-example build --stream", @@ -29,7 +29,7 @@ "tsc": "lerna run tsc --stream", "types:lint:fix": "lerna run lint:fix --scope @nymproject/types --scope @nymproject/nym-wallet-app", "audit:fix": "npm_config_yes=true npx yarn-audit-fix -- --dry-run", - "preinstall": "yarn install:copy-placeholders", + "preinstall": "run-s install:copy-placeholders", "install:copy-placeholders": "cp scripts/build/yarn/wasm-placeholder/package.json sdk/typescript/packages/nym-client-wasm" }, "devDependencies": { diff --git a/sdk/typescript/packages/sdk/package.json b/sdk/typescript/packages/sdk/package.json index 7b2b512f37..14a9b02e79 100644 --- a/sdk/typescript/packages/sdk/package.json +++ b/sdk/typescript/packages/sdk/package.json @@ -27,7 +27,8 @@ "prebuild:dev": "yarn build:dependencies", "build:dev": "yarn build:dev:only-this", "build:dev:only-this": "scripts/build.sh", - "build:lint": "run-s build:dependencies:nym-client-wasm build:dev:only-this" + "build:local": "run-s build:dependencies:nym-client-wasm build:dev:only-this", + "preinstall": "yarn build:local" }, "dependencies": { "@npmcli/node-gyp": "^3.0.0", From b134334ec77aa1cae91acdce7411cdd71282ed68 Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Tue, 4 Jul 2023 11:43:42 +0100 Subject: [PATCH 43/74] Fix package.json `preinstall` error --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 627359351b..49e9e5f8b2 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "tsc": "lerna run tsc --stream", "types:lint:fix": "lerna run lint:fix --scope @nymproject/types --scope @nymproject/nym-wallet-app", "audit:fix": "npm_config_yes=true npx yarn-audit-fix -- --dry-run", - "preinstall": "run-s install:copy-placeholders", + "preinstall": "yarn install:copy-placeholders", "install:copy-placeholders": "cp scripts/build/yarn/wasm-placeholder/package.json sdk/typescript/packages/nym-client-wasm" }, "devDependencies": { From 2e366a094d041eb533ffe2e6a9027060b4e232c7 Mon Sep 17 00:00:00 2001 From: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com> Date: Tue, 4 Jul 2023 11:52:13 +0100 Subject: [PATCH 44/74] Update nym-wallet-publish-windows10.yml --- .github/workflows/nym-wallet-publish-windows10.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nym-wallet-publish-windows10.yml b/.github/workflows/nym-wallet-publish-windows10.yml index 0028074f01..7a8fc79f7f 100644 --- a/.github/workflows/nym-wallet-publish-windows10.yml +++ b/.github/workflows/nym-wallet-publish-windows10.yml @@ -45,11 +45,11 @@ jobs: node-version: 18 - name: Install Rust stable - shell: bash uses: actions-rs/toolchain@v1 with: toolchain: stable - name: Install wasm-pack + shell: bash run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - name: Create env file From 730f03de30b415b291f852c5ec50caf14a6d854d Mon Sep 17 00:00:00 2001 From: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com> Date: Tue, 4 Jul 2023 11:54:46 +0100 Subject: [PATCH 45/74] Update nym-wallet-publish-windows10.yml --- .github/workflows/nym-wallet-publish-windows10.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/nym-wallet-publish-windows10.yml b/.github/workflows/nym-wallet-publish-windows10.yml index 7a8fc79f7f..274327ff90 100644 --- a/.github/workflows/nym-wallet-publish-windows10.yml +++ b/.github/workflows/nym-wallet-publish-windows10.yml @@ -49,8 +49,7 @@ jobs: with: toolchain: stable - name: Install wasm-pack - shell: bash - run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + run: cargo install wasm-pack - name: Create env file uses: timheuer/base64-to-file@v1.1 From 565e7768e329ed5a9255d68781a442c80929e66a Mon Sep 17 00:00:00 2001 From: Gala Date: Tue, 4 Jul 2023 14:33:09 +0200 Subject: [PATCH 46/74] Update README.md --- clients/credential/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clients/credential/README.md b/clients/credential/README.md index e332e42555..9d82b4b839 100644 --- a/clients/credential/README.md +++ b/clients/credential/README.md @@ -15,9 +15,9 @@ The credential binary is still experimental software. The infrastructure for usi From the project's root directory, run: ``` -cargo build -p credential +cargo build -p nym-credential-client ``` -which generates the `credential` binary in `target/debug/credential`. +which generates the `nym-credential-client` binary in `target/debug/nym-credential-client`. ### Running @@ -25,7 +25,7 @@ which generates the `credential` binary in `target/debug/credential`. For example, you can get a credential worth 3 nym (3000000 unym) in a socks5 client that was already initialized like so: ``` -./target/debug/credential --config-env-file envs/sandbox.env --client-home-directory ~/.nym/socks5-clients/cred_client --nyxd-url https://sandbox-validator1.nymtech.net --mnemonic $MNEMONIC --recovery-dir /tmp/recovery --amount 3000000 +./target/debug/nym-credential-client --config-env-file envs/sandbox.env --client-home-directory ~/.nym/socks5-clients/cred_client --nyxd-url https://sandbox-validator1.nymtech.net --mnemonic $MNEMONIC --recovery-dir /tmp/recovery --amount 3000000 ``` More information regarding how to run the binary can be found by running it with the `--help` argument. From 997faeb1e61420f865efc2c5d01551d4dc39ae7f Mon Sep 17 00:00:00 2001 From: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com> Date: Tue, 4 Jul 2023 15:27:15 +0100 Subject: [PATCH 47/74] Create sdk-publish.yml --- .github/workflows/sdk-publish.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/sdk-publish.yml diff --git a/.github/workflows/sdk-publish.yml b/.github/workflows/sdk-publish.yml new file mode 100644 index 0000000000..28bc96f314 --- /dev/null +++ b/.github/workflows/sdk-publish.yml @@ -0,0 +1,19 @@ +name: Publish SDK to NPM +on: + workflow_dispatch: + +defaults: + run: + working-directory: sdk/typescript/packages/sdk + +jobs: + publish: + runs-on: [custom-runner-linux] + steps: + - name: Install Node + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Setup yarn + run: npm install -g yarn From 16d6444169ff033e5894fc644ce4f36cfae2497a Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Tue, 4 Jul 2023 15:30:49 +0100 Subject: [PATCH 48/74] Add GH Actions workflow to publish the SDK --- .github/workflows/sdk-publish.yml | 32 +++++++++++++++++++ sdk/typescript/packages/sdk/DEVELOPERS.md | 10 ++++++ sdk/typescript/packages/sdk/package.json | 2 +- .../packages/sdk/scripts/publish.sh | 22 +++++++++++++ 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/sdk-publish.yml create mode 100755 sdk/typescript/packages/sdk/scripts/publish.sh diff --git a/.github/workflows/sdk-publish.yml b/.github/workflows/sdk-publish.yml new file mode 100644 index 0000000000..8cabbfe978 --- /dev/null +++ b/.github/workflows/sdk-publish.yml @@ -0,0 +1,32 @@ +name: Publish SDK to NPM +on: + workflow_dispatch: + +defaults: + run: + working-directory: sdk/typescript/packages/sdk + +jobs: + publish: + runs-on: [custom-runner-linux] + steps: + - name: Install Node + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Setup yarn + run: npm install -g yarn + + - name: Install Rust stable + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + + - name: Install wasm-pack + run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + + - name: Build and publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} + run: scripts/publish.sh \ No newline at end of file diff --git a/sdk/typescript/packages/sdk/DEVELOPERS.md b/sdk/typescript/packages/sdk/DEVELOPERS.md index 015271fb96..5215673a2b 100644 --- a/sdk/typescript/packages/sdk/DEVELOPERS.md +++ b/sdk/typescript/packages/sdk/DEVELOPERS.md @@ -34,6 +34,16 @@ The output bundle will be created in the `dist` directory. If you're a Nym platform developer who's made changes to the Rust (or JS) files and wants to re-publish the package to NPM, here's how you do it: +Make sure you have logged into the NPM registry (`npm login`). + +### Scripted + +1. bump version numbers as necessary for SemVer +2. make sure you're in the SDK directory (`cd sdk/typescript/packages/sdk`) +3. run `scripts/publish.sh` + +### Manually + 1. bump version numbers as necessary for SemVer 2. `yarn build` builds the release directory in the root of the repo in `dist/sdk` 3. `cd ../../../../dist/sdk` diff --git a/sdk/typescript/packages/sdk/package.json b/sdk/typescript/packages/sdk/package.json index 14a9b02e79..5e661b79c3 100644 --- a/sdk/typescript/packages/sdk/package.json +++ b/sdk/typescript/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/sdk", - "version": "1.1.7", + "version": "1.1.8", "license": "Apache-2.0", "author": "Nym Technologies SA", "type": "module", diff --git a/sdk/typescript/packages/sdk/scripts/publish.sh b/sdk/typescript/packages/sdk/scripts/publish.sh new file mode 100755 index 0000000000..94aa4f689b --- /dev/null +++ b/sdk/typescript/packages/sdk/scripts/publish.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +rm -rf dist || true +rm -rf ../../../../dist || true + +yarn +yarn build +cd ../../../../dist/sdk + +cd cjs +echo "Publishing CommonJS package to NPM.." +npm publish --access=public +cd .. + +cd esm +echo "Publishing ESM package to NPM.." +npm publish --access=public +cd .. From 9e0bcc025fb01d3d1d3ecf2f99b1c89cd184438b Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Tue, 4 Jul 2023 15:34:37 +0100 Subject: [PATCH 49/74] Fix up working directory in GH Action to publish to NPM --- .github/workflows/sdk-publish.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/sdk-publish.yml b/.github/workflows/sdk-publish.yml index 8cabbfe978..7622a6bf17 100644 --- a/.github/workflows/sdk-publish.yml +++ b/.github/workflows/sdk-publish.yml @@ -2,10 +2,6 @@ name: Publish SDK to NPM on: workflow_dispatch: -defaults: - run: - working-directory: sdk/typescript/packages/sdk - jobs: publish: runs-on: [custom-runner-linux] @@ -29,4 +25,5 @@ jobs: - name: Build and publish env: NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} - run: scripts/publish.sh \ No newline at end of file + working-directory: ./sdk/typescript/packages/sdk + run: cd sdk/typescript/packages/sdk && scripts/publish.sh \ No newline at end of file From 4899ccf4eff08551b6f3c3cec7c9853c3734d65c Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Tue, 4 Jul 2023 15:36:26 +0100 Subject: [PATCH 50/74] GitHub Action to publish SDK --- .github/workflows/sdk-publish.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/sdk-publish.yml b/.github/workflows/sdk-publish.yml index 7622a6bf17..75eb7e512d 100644 --- a/.github/workflows/sdk-publish.yml +++ b/.github/workflows/sdk-publish.yml @@ -6,6 +6,8 @@ jobs: publish: runs-on: [custom-runner-linux] steps: + - uses: actions/checkout@v2 + - name: Install Node uses: actions/setup-node@v3 with: From adbeeb3e5f3ba2a997819cfdbc920d86a5ea7dc4 Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Tue, 4 Jul 2023 15:39:11 +0100 Subject: [PATCH 51/74] GitHub Action to publish SDK --- .github/workflows/sdk-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sdk-publish.yml b/.github/workflows/sdk-publish.yml index 75eb7e512d..db78b453c5 100644 --- a/.github/workflows/sdk-publish.yml +++ b/.github/workflows/sdk-publish.yml @@ -28,4 +28,4 @@ jobs: env: NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} working-directory: ./sdk/typescript/packages/sdk - run: cd sdk/typescript/packages/sdk && scripts/publish.sh \ No newline at end of file + run: scripts/publish.sh \ No newline at end of file From 578765321095e380b3bc700b703298b71b011b4b Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Tue, 4 Jul 2023 15:40:45 +0100 Subject: [PATCH 52/74] GitHub Action to publish SDK --- .github/workflows/sdk-publish.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/sdk-publish.yml b/.github/workflows/sdk-publish.yml index db78b453c5..b38fff9d26 100644 --- a/.github/workflows/sdk-publish.yml +++ b/.github/workflows/sdk-publish.yml @@ -24,6 +24,9 @@ jobs: - name: Install wasm-pack run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + - name: Install dependencies + run: yarn + - name: Build and publish env: NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} From a91c997aedc64de91092a55ba0ce5970dbb2eab4 Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Tue, 4 Jul 2023 15:48:44 +0100 Subject: [PATCH 53/74] Revert building SDK from root package.json --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 49e9e5f8b2..cad6eaf88d 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,7 @@ "clean": "lerna run clean", "build": "run-s build:types build:packages", "build:types": "lerna run --scope @nymproject/types build --stream", - "build:packages": "run-s build:packages:theme build:packages:react build:packages:sdk", - "build:packages:sdk": "lerna run --scope @nymproject/sdk build:local", + "build:packages": "run-s build:packages:theme build:packages:react", "build:packages:theme": "lerna run --scope @nymproject/mui-theme build", "build:packages:react": "lerna run --scope @nymproject/react build", "build:react-example": "lerna run --scope @nymproject/react-webpack-with-theme-example build --stream", From 2d7003dfae1b9b4a993f009d7fce0d48d3db0419 Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Tue, 4 Jul 2023 16:06:55 +0100 Subject: [PATCH 54/74] Add npm registry to setup-node to create `.npmrc` file with reg details --- .github/workflows/sdk-publish.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/sdk-publish.yml b/.github/workflows/sdk-publish.yml index b38fff9d26..7ef5f90b1b 100644 --- a/.github/workflows/sdk-publish.yml +++ b/.github/workflows/sdk-publish.yml @@ -12,6 +12,7 @@ jobs: uses: actions/setup-node@v3 with: node-version: 18 + registry-url: 'https://registry.npmjs.org' - name: Setup yarn run: npm install -g yarn From 3051d84e8d47cb3bd34a4e21809cc1632e99db08 Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Tue, 4 Jul 2023 16:59:57 +0100 Subject: [PATCH 55/74] Revert GitHub Action changes to add wasm-pack to Typescript workflows --- .github/workflows/build-ts-packages.yml | 6 ------ .github/workflows/nym-wallet-publish-macos.yml | 2 -- .github/workflows/nym-wallet-publish-ubuntu.yml | 2 -- .github/workflows/nym-wallet-publish-windows10.yml | 6 +----- .github/workflows/nym-wallet-storybook.yml | 6 ------ .github/workflows/typescript-lint.yml | 6 ------ 6 files changed, 1 insertion(+), 27 deletions(-) diff --git a/.github/workflows/build-ts-packages.yml b/.github/workflows/build-ts-packages.yml index 1fb210bd8e..7c0ead8933 100644 --- a/.github/workflows/build-ts-packages.yml +++ b/.github/workflows/build-ts-packages.yml @@ -19,12 +19,6 @@ jobs: node-version: 18 - name: Setup yarn run: npm install -g yarn - - name: Install Rust stable - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - - name: Install wasm-pack - run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - name: Build run: yarn && yarn build && yarn build:ci - name: Deploy branch to CI www (storybook) diff --git a/.github/workflows/nym-wallet-publish-macos.yml b/.github/workflows/nym-wallet-publish-macos.yml index 9df72181b6..81c27a8338 100644 --- a/.github/workflows/nym-wallet-publish-macos.yml +++ b/.github/workflows/nym-wallet-publish-macos.yml @@ -28,8 +28,6 @@ jobs: uses: actions-rs/toolchain@v1 with: toolchain: stable - - name: Install wasm-pack - run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - name: Install the Apple developer certificate for code signing env: APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} diff --git a/.github/workflows/nym-wallet-publish-ubuntu.yml b/.github/workflows/nym-wallet-publish-ubuntu.yml index e9470ffcea..db61b24805 100644 --- a/.github/workflows/nym-wallet-publish-ubuntu.yml +++ b/.github/workflows/nym-wallet-publish-ubuntu.yml @@ -34,8 +34,6 @@ jobs: uses: actions-rs/toolchain@v1 with: toolchain: stable - - name: Install wasm-pack - run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - name: Install app dependencies run: yarn diff --git a/.github/workflows/nym-wallet-publish-windows10.yml b/.github/workflows/nym-wallet-publish-windows10.yml index 274327ff90..044816953b 100644 --- a/.github/workflows/nym-wallet-publish-windows10.yml +++ b/.github/workflows/nym-wallet-publish-windows10.yml @@ -48,9 +48,7 @@ jobs: uses: actions-rs/toolchain@v1 with: toolchain: stable - - name: Install wasm-pack - run: cargo install wasm-pack - + - name: Create env file uses: timheuer/base64-to-file@v1.1 with: @@ -58,11 +56,9 @@ jobs: encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} - name: Install app dependencies - shell: bash run: yarn --network-timeout 100000 - name: Build and sign it - shell: bash env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }} diff --git a/.github/workflows/nym-wallet-storybook.yml b/.github/workflows/nym-wallet-storybook.yml index 99eb4ce262..88f1230895 100644 --- a/.github/workflows/nym-wallet-storybook.yml +++ b/.github/workflows/nym-wallet-storybook.yml @@ -19,12 +19,6 @@ jobs: node-version: 18 - name: Setup yarn run: npm install -g yarn - - name: Install Rust stable - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - - name: Install wasm-pack - run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - name: Build dependencies run: yarn && yarn build - name: Build storybook diff --git a/.github/workflows/typescript-lint.yml b/.github/workflows/typescript-lint.yml index b473107386..829ffb22e9 100644 --- a/.github/workflows/typescript-lint.yml +++ b/.github/workflows/typescript-lint.yml @@ -38,12 +38,6 @@ jobs: node-version: 18 - name: Setup yarn run: npm install -g yarn - - name: Install Rust stable - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - - name: Install wasm-pack - run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - name: Install run: yarn - name: Build packages From 58958a2449ecfce02f0ab198c9a001169a7a01b4 Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Tue, 4 Jul 2023 17:01:05 +0100 Subject: [PATCH 56/74] nym-wallet: use NPM published package and add `-rc0` prefix to workspace SDK package --- nym-wallet/package.json | 5 ++--- sdk/typescript/packages/sdk/DEVELOPERS.md | 3 +++ sdk/typescript/packages/sdk/package.json | 2 +- yarn.lock | 5 +++++ 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/nym-wallet/package.json b/nym-wallet/package.json index ad02b9a010..f14d6dd227 100644 --- a/nym-wallet/package.json +++ b/nym-wallet/package.json @@ -18,8 +18,7 @@ "lint:fix": "eslint src --fix", "prestorybook": "yarn --cwd .. build", "storybook": "start-storybook -p 6006", - "storybook:build": "build-storybook", - "preinstall": "yarn --cwd .. build" + "storybook:build": "build-storybook" }, "dependencies": { "@emotion/react": "^11.7.0", @@ -32,7 +31,7 @@ "@nymproject/mui-theme": "^1.0.0", "@nymproject/react": "^1.0.0", "@nymproject/types": "^1.0.0", - "@nymproject/sdk": "1", + "@nymproject/sdk": "^1.1.8", "@storybook/react": "^6.5.15", "@tauri-apps/api": "^1.2.0", "@tauri-apps/tauri-forage": "^1.0.0-beta.2", diff --git a/sdk/typescript/packages/sdk/DEVELOPERS.md b/sdk/typescript/packages/sdk/DEVELOPERS.md index 5215673a2b..c8a19f360f 100644 --- a/sdk/typescript/packages/sdk/DEVELOPERS.md +++ b/sdk/typescript/packages/sdk/DEVELOPERS.md @@ -55,3 +55,6 @@ Publish the CJS package: Publish the ESM package: - `cd ../esm` - `npm publish --access=public` will publish your changed package to NPM + +4. bump the minor version and add `-rc0` to avoid local packages from using the workspace SDK, e.g. (`1.1.10` -> `1.1.11-rc0`) +5. commit the updated `package.json` to git diff --git a/sdk/typescript/packages/sdk/package.json b/sdk/typescript/packages/sdk/package.json index 5e661b79c3..617752ebfb 100644 --- a/sdk/typescript/packages/sdk/package.json +++ b/sdk/typescript/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/sdk", - "version": "1.1.8", + "version": "1.1.9-rc0", "license": "Apache-2.0", "author": "Nym Technologies SA", "type": "module", diff --git a/yarn.lock b/yarn.lock index 197fe4355b..2eb29a1a15 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2838,6 +2838,11 @@ "@cosmjs/stargate" "^0.25.5" axios "^0.21.1" +"@nymproject/sdk@^1.1.8": + version "1.1.8" + resolved "https://registry.yarnpkg.com/@nymproject/sdk/-/sdk-1.1.8.tgz#384ee824971dee413755b14634c3d60fb22eff9a" + integrity sha512-nAyem2wqTfc6l9e6Y7JR2V1teDfwjxMHpRjxg90FMkUWl/JP7Ww752gDsSq3nvObLt+cvxjWMHy1mswvwQfZyQ== + "@octokit/auth-token@^3.0.0": version "3.0.4" resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-3.0.4.tgz#70e941ba742bdd2b49bdb7393e821dea8520a3db" From 847f3a0ecce9ab24a177a8c9a9346df9b36cb010 Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Tue, 4 Jul 2023 17:03:24 +0100 Subject: [PATCH 57/74] Remove preinstall target that needs wasm-pack --- sdk/typescript/packages/sdk/package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sdk/typescript/packages/sdk/package.json b/sdk/typescript/packages/sdk/package.json index 617752ebfb..de6d16554d 100644 --- a/sdk/typescript/packages/sdk/package.json +++ b/sdk/typescript/packages/sdk/package.json @@ -27,8 +27,7 @@ "prebuild:dev": "yarn build:dependencies", "build:dev": "yarn build:dev:only-this", "build:dev:only-this": "scripts/build.sh", - "build:local": "run-s build:dependencies:nym-client-wasm build:dev:only-this", - "preinstall": "yarn build:local" + "build:local": "run-s build:dependencies:nym-client-wasm build:dev:only-this" }, "dependencies": { "@npmcli/node-gyp": "^3.0.0", From 351552b8636d02dccb52f5b9900ce11b82ac4f34 Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Tue, 4 Jul 2023 17:22:54 +0100 Subject: [PATCH 58/74] Add back preinstall target --- nym-wallet/package.json | 3 ++- package.json | 6 ++++- yarn.lock | 54 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/nym-wallet/package.json b/nym-wallet/package.json index f14d6dd227..36c3ca5017 100644 --- a/nym-wallet/package.json +++ b/nym-wallet/package.json @@ -18,7 +18,8 @@ "lint:fix": "eslint src --fix", "prestorybook": "yarn --cwd .. build", "storybook": "start-storybook -p 6006", - "storybook:build": "build-storybook" + "storybook:build": "build-storybook", + "preinstall": "yarn --cwd .. setup:dependencies" }, "dependencies": { "@emotion/react": "^11.7.0", diff --git a/package.json b/package.json index cad6eaf88d..cc37b9438d 100644 --- a/package.json +++ b/package.json @@ -29,10 +29,14 @@ "types:lint:fix": "lerna run lint:fix --scope @nymproject/types --scope @nymproject/nym-wallet-app", "audit:fix": "npm_config_yes=true npx yarn-audit-fix -- --dry-run", "preinstall": "yarn install:copy-placeholders", - "install:copy-placeholders": "cp scripts/build/yarn/wasm-placeholder/package.json sdk/typescript/packages/nym-client-wasm" + "setup:dependencies": "yarn install:copy-placeholders", + "install:copy-placeholders": "copyfiles -V -s -f scripts/build/yarn/wasm-placeholder/package.json sdk/typescript/packages/nym-client-wasm" }, "devDependencies": { "lerna": "^6.6.2", "npm-run-all": "^4.1.5" + }, + "dependencies": { + "copyfiles": "^2.4.1" } } diff --git a/yarn.lock b/yarn.lock index 2eb29a1a15..235fc7d7a7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7823,6 +7823,19 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== +copyfiles@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.4.1.tgz#d2dcff60aaad1015f09d0b66e7f0f1c5cd3c5da5" + integrity sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg== + dependencies: + glob "^7.0.5" + minimatch "^3.0.3" + mkdirp "^1.0.4" + noms "0.0.0" + through2 "^2.0.1" + untildify "^4.0.0" + yargs "^16.1.0" + core-js-compat@^3.30.1, core-js-compat@^3.30.2, core-js-compat@^3.8.1: version "3.31.0" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.31.0.tgz#4030847c0766cc0e803dcdfb30055d7ef2064bf1" @@ -10615,7 +10628,7 @@ glob@^10.2.2: minipass "^5.0.0 || ^6.0.2" path-scurry "^1.10.0" -glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: +glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -12000,6 +12013,11 @@ is-wsl@^2.1.1, is-wsl@^2.2.0: dependencies: is-docker "^2.0.0" +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== + isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -14208,7 +14226,7 @@ minimatch@5.0.1: dependencies: brace-expansion "^2.0.1" -minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -14705,6 +14723,14 @@ nodemon@^2.0.21: touch "^3.1.0" undefsafe "^2.0.5" +noms@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859" + integrity sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow== + dependencies: + inherits "^2.0.1" + readable-stream "~1.0.31" + nopt@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/nopt/-/nopt-6.0.0.tgz#245801d8ebf409c6df22ab9d95b65e1309cdb16d" @@ -16963,6 +16989,16 @@ readable-stream@^4.1.0: events "^3.3.0" process "^0.11.10" +readable-stream@~1.0.31: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + readdirp@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" @@ -18324,6 +18360,11 @@ string_decoder@^1.0.0, string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== + string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -18756,7 +18797,7 @@ throat@^6.0.1: resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.2.tgz#51a3fbb5e11ae72e2cf74861ed5c8020f89f29fe" integrity sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ== -through2@^2.0.0: +through2@^2.0.0, through2@^2.0.1: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== @@ -19492,6 +19533,11 @@ untildify@^2.0.0: dependencies: os-homedir "^1.0.0" +untildify@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" + integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== + upath@2.0.1, upath@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b" @@ -20420,7 +20466,7 @@ yargs-unparser@2.0.0: flat "^5.0.2" is-plain-obj "^2.1.0" -yargs@16.2.0, yargs@^16.2.0: +yargs@16.2.0, yargs@^16.1.0, yargs@^16.2.0: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== From 879e3246963517e4d2e7f1be08171460e3387ee6 Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Tue, 4 Jul 2023 17:26:41 +0100 Subject: [PATCH 59/74] Add another target for install and CI --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index cc37b9438d..ec9de014c0 100644 --- a/package.json +++ b/package.json @@ -29,8 +29,9 @@ "types:lint:fix": "lerna run lint:fix --scope @nymproject/types --scope @nymproject/nym-wallet-app", "audit:fix": "npm_config_yes=true npx yarn-audit-fix -- --dry-run", "preinstall": "yarn install:copy-placeholders", - "setup:dependencies": "yarn install:copy-placeholders", - "install:copy-placeholders": "copyfiles -V -s -f scripts/build/yarn/wasm-placeholder/package.json sdk/typescript/packages/nym-client-wasm" + "setup:dependencies": "yarn install:copy-placeholders:crossplatform", + "install:copy-placeholders": "cp scripts/build/yarn/wasm-placeholder/package.json sdk/typescript/packages/nym-client-wasm", + "install:copy-placeholders:crossplatform": "copyfiles -V -s -f scripts/build/yarn/wasm-placeholder/package.json sdk/typescript/packages/nym-client-wasm" }, "devDependencies": { "lerna": "^6.6.2", From 57e2628928fe30c84543f87f3d686c5ca02289c9 Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Tue, 4 Jul 2023 17:32:32 +0100 Subject: [PATCH 60/74] GitHub Actions adding `bash` to Windows publish workflow --- .github/workflows/nym-wallet-publish-windows10.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/nym-wallet-publish-windows10.yml b/.github/workflows/nym-wallet-publish-windows10.yml index 044816953b..48fb9a301c 100644 --- a/.github/workflows/nym-wallet-publish-windows10.yml +++ b/.github/workflows/nym-wallet-publish-windows10.yml @@ -56,9 +56,11 @@ jobs: encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} - name: Install app dependencies + shell: bash run: yarn --network-timeout 100000 - name: Build and sign it + shell: bash env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }} From 136f4a8473222add00bd07c2e96f4e802db35b2b Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Tue, 4 Jul 2023 17:42:36 +0100 Subject: [PATCH 61/74] Revert adding copyfiles --- package.json | 8 ++------ yarn.lock | 54 ++++------------------------------------------------ 2 files changed, 6 insertions(+), 56 deletions(-) diff --git a/package.json b/package.json index ec9de014c0..c796364c77 100644 --- a/package.json +++ b/package.json @@ -29,15 +29,11 @@ "types:lint:fix": "lerna run lint:fix --scope @nymproject/types --scope @nymproject/nym-wallet-app", "audit:fix": "npm_config_yes=true npx yarn-audit-fix -- --dry-run", "preinstall": "yarn install:copy-placeholders", - "setup:dependencies": "yarn install:copy-placeholders:crossplatform", - "install:copy-placeholders": "cp scripts/build/yarn/wasm-placeholder/package.json sdk/typescript/packages/nym-client-wasm", - "install:copy-placeholders:crossplatform": "copyfiles -V -s -f scripts/build/yarn/wasm-placeholder/package.json sdk/typescript/packages/nym-client-wasm" + "setup:dependencies": "yarn install:copy-placeholders", + "install:copy-placeholders": "cp scripts/build/yarn/wasm-placeholder/package.json sdk/typescript/packages/nym-client-wasm" }, "devDependencies": { "lerna": "^6.6.2", "npm-run-all": "^4.1.5" - }, - "dependencies": { - "copyfiles": "^2.4.1" } } diff --git a/yarn.lock b/yarn.lock index 235fc7d7a7..2eb29a1a15 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7823,19 +7823,6 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== -copyfiles@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.4.1.tgz#d2dcff60aaad1015f09d0b66e7f0f1c5cd3c5da5" - integrity sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg== - dependencies: - glob "^7.0.5" - minimatch "^3.0.3" - mkdirp "^1.0.4" - noms "0.0.0" - through2 "^2.0.1" - untildify "^4.0.0" - yargs "^16.1.0" - core-js-compat@^3.30.1, core-js-compat@^3.30.2, core-js-compat@^3.8.1: version "3.31.0" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.31.0.tgz#4030847c0766cc0e803dcdfb30055d7ef2064bf1" @@ -10628,7 +10615,7 @@ glob@^10.2.2: minipass "^5.0.0 || ^6.0.2" path-scurry "^1.10.0" -glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: +glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -12013,11 +12000,6 @@ is-wsl@^2.1.1, is-wsl@^2.2.0: dependencies: is-docker "^2.0.0" -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== - isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -14226,7 +14208,7 @@ minimatch@5.0.1: dependencies: brace-expansion "^2.0.1" -minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -14723,14 +14705,6 @@ nodemon@^2.0.21: touch "^3.1.0" undefsafe "^2.0.5" -noms@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859" - integrity sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow== - dependencies: - inherits "^2.0.1" - readable-stream "~1.0.31" - nopt@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/nopt/-/nopt-6.0.0.tgz#245801d8ebf409c6df22ab9d95b65e1309cdb16d" @@ -16989,16 +16963,6 @@ readable-stream@^4.1.0: events "^3.3.0" process "^0.11.10" -readable-stream@~1.0.31: - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - readdirp@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" @@ -18360,11 +18324,6 @@ string_decoder@^1.0.0, string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== - string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -18797,7 +18756,7 @@ throat@^6.0.1: resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.2.tgz#51a3fbb5e11ae72e2cf74861ed5c8020f89f29fe" integrity sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ== -through2@^2.0.0, through2@^2.0.1: +through2@^2.0.0: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== @@ -19533,11 +19492,6 @@ untildify@^2.0.0: dependencies: os-homedir "^1.0.0" -untildify@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" - integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== - upath@2.0.1, upath@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b" @@ -20466,7 +20420,7 @@ yargs-unparser@2.0.0: flat "^5.0.2" is-plain-obj "^2.1.0" -yargs@16.2.0, yargs@^16.1.0, yargs@^16.2.0: +yargs@16.2.0, yargs@^16.2.0: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== From de05e32845345b640296b3e61cc4e0022d80d07e Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Tue, 4 Jul 2023 17:45:23 +0100 Subject: [PATCH 62/74] Removing `bash` shell from GitHub Action --- .github/workflows/nym-wallet-publish-windows10.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/nym-wallet-publish-windows10.yml b/.github/workflows/nym-wallet-publish-windows10.yml index 48fb9a301c..044816953b 100644 --- a/.github/workflows/nym-wallet-publish-windows10.yml +++ b/.github/workflows/nym-wallet-publish-windows10.yml @@ -56,11 +56,9 @@ jobs: encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} - name: Install app dependencies - shell: bash run: yarn --network-timeout 100000 - name: Build and sign it - shell: bash env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }} From 7743554bb8607bc0289f5cfca4db45c4f6a5b084 Mon Sep 17 00:00:00 2001 From: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com> Date: Wed, 5 Jul 2023 11:43:33 +0100 Subject: [PATCH 63/74] Update nym-wallet-publish-windows10.yml --- .github/workflows/nym-wallet-publish-windows10.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/nym-wallet-publish-windows10.yml b/.github/workflows/nym-wallet-publish-windows10.yml index 044816953b..48fb9a301c 100644 --- a/.github/workflows/nym-wallet-publish-windows10.yml +++ b/.github/workflows/nym-wallet-publish-windows10.yml @@ -56,9 +56,11 @@ jobs: encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} - name: Install app dependencies + shell: bash run: yarn --network-timeout 100000 - name: Build and sign it + shell: bash env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }} From 36253e3f364ea9fe31891c1b95cdc0c083adb63e Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Wed, 5 Jul 2023 12:13:21 +0100 Subject: [PATCH 64/74] GitHub Actions: fix up naming and versions --- .github/workflows/nym-connect-publish-macos.yml | 4 ++-- .github/workflows/nym-connect-publish-ubuntu.yml | 4 ++-- .github/workflows/nym-connect-publish-windows10.yml | 4 ++-- .github/workflows/nym-wallet-publish-macos.yml | 4 ++-- .github/workflows/nym-wallet-publish-ubuntu.yml | 4 ++-- .github/workflows/nym-wallet-publish-windows10.yml | 4 ++-- .github/workflows/nym_wallet.yml | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/nym-connect-publish-macos.yml b/.github/workflows/nym-connect-publish-macos.yml index 379443d4dd..eb0ff1423a 100644 --- a/.github/workflows/nym-connect-publish-macos.yml +++ b/.github/workflows/nym-connect-publish-macos.yml @@ -20,7 +20,7 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Node v16 + - name: Node uses: actions/setup-node@v3 with: node-version: 18 @@ -51,7 +51,7 @@ jobs: security list-keychain -d user -s $KEYCHAIN_PATH - name: Create env file - uses: timheuer/base64-to-file@v1.1 + uses: timheuer/base64-to-file@v1.2 with: fileName: '.env' encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} diff --git a/.github/workflows/nym-connect-publish-ubuntu.yml b/.github/workflows/nym-connect-publish-ubuntu.yml index 25d288581d..3997eb3695 100644 --- a/.github/workflows/nym-connect-publish-ubuntu.yml +++ b/.github/workflows/nym-connect-publish-ubuntu.yml @@ -26,7 +26,7 @@ jobs: sudo apt-get install -y webkit2gtk-4.0 libayatana-appindicator3-dev continue-on-error: true - - name: Node v16 + - name: Node uses: actions/setup-node@v3 with: node-version: 18 @@ -38,7 +38,7 @@ jobs: - name: Install app dependencies run: yarn - name: Create env file - uses: timheuer/base64-to-file@v1.1 + uses: timheuer/base64-to-file@v1.2 with: fileName: '.env' encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} diff --git a/.github/workflows/nym-connect-publish-windows10.yml b/.github/workflows/nym-connect-publish-windows10.yml index d85b151e16..3c4f07f557 100644 --- a/.github/workflows/nym-connect-publish-windows10.yml +++ b/.github/workflows/nym-connect-publish-windows10.yml @@ -39,7 +39,7 @@ jobs: Remove-Item -path certificate -include tempCert.txt Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText) - - name: Node v16 + - name: Node uses: actions/setup-node@v3 with: node-version: 18 @@ -50,7 +50,7 @@ jobs: toolchain: stable - name: Create env file - uses: timheuer/base64-to-file@v1.1 + uses: timheuer/base64-to-file@v1.2 with: fileName: '.env' encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} diff --git a/.github/workflows/nym-wallet-publish-macos.yml b/.github/workflows/nym-wallet-publish-macos.yml index 81c27a8338..16be7ef2c8 100644 --- a/.github/workflows/nym-wallet-publish-macos.yml +++ b/.github/workflows/nym-wallet-publish-macos.yml @@ -20,7 +20,7 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Node v16 + - name: Node uses: actions/setup-node@v3 with: node-version: 18 @@ -51,7 +51,7 @@ jobs: security list-keychain -d user -s $KEYCHAIN_PATH - name: Create env file - uses: timheuer/base64-to-file@v1.1 + uses: timheuer/base64-to-file@v1.2 with: fileName: '.env' encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} diff --git a/.github/workflows/nym-wallet-publish-ubuntu.yml b/.github/workflows/nym-wallet-publish-ubuntu.yml index db61b24805..4073c16f1a 100644 --- a/.github/workflows/nym-wallet-publish-ubuntu.yml +++ b/.github/workflows/nym-wallet-publish-ubuntu.yml @@ -25,7 +25,7 @@ jobs: sudo apt-get install -y webkit2gtk-4.0 continue-on-error: true - - name: Node v16 + - name: Node uses: actions/setup-node@v3 with: node-version: 18 @@ -38,7 +38,7 @@ jobs: - name: Install app dependencies run: yarn - name: Create env file - uses: timheuer/base64-to-file@v1.1 + uses: timheuer/base64-to-file@v1.2 with: fileName: '.env' encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} diff --git a/.github/workflows/nym-wallet-publish-windows10.yml b/.github/workflows/nym-wallet-publish-windows10.yml index 48fb9a301c..194e6ae14c 100644 --- a/.github/workflows/nym-wallet-publish-windows10.yml +++ b/.github/workflows/nym-wallet-publish-windows10.yml @@ -39,7 +39,7 @@ jobs: Remove-Item -path certificate -include tempCert.txt Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText) - - name: Node v16 + - name: Node uses: actions/setup-node@v3 with: node-version: 18 @@ -50,7 +50,7 @@ jobs: toolchain: stable - name: Create env file - uses: timheuer/base64-to-file@v1.1 + uses: timheuer/base64-to-file@v1.2 with: fileName: '.env' encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} diff --git a/.github/workflows/nym_wallet.yml b/.github/workflows/nym_wallet.yml index d110314899..8c7f6fe267 100644 --- a/.github/workflows/nym_wallet.yml +++ b/.github/workflows/nym_wallet.yml @@ -34,7 +34,7 @@ jobs: profile: minimal toolchain: stable - - name: Node v16 + - name: Node uses: actions/setup-node@v3 with: node-version: 18 From d829837275183aa9e26b9b134d929f5fb7cd8d0f Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Wed, 5 Jul 2023 12:13:39 +0100 Subject: [PATCH 65/74] GitHub Actions: install project root dependencies first --- .github/workflows/nym-wallet-publish-windows10.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/nym-wallet-publish-windows10.yml b/.github/workflows/nym-wallet-publish-windows10.yml index 194e6ae14c..92ce582d32 100644 --- a/.github/workflows/nym-wallet-publish-windows10.yml +++ b/.github/workflows/nym-wallet-publish-windows10.yml @@ -55,6 +55,10 @@ jobs: fileName: '.env' encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} + - name: Install project dependencies + shell: bash + run: cd .. && yarn --network-timeout 100000 + - name: Install app dependencies shell: bash run: yarn --network-timeout 100000 From 1f4f312e8e345114f35c30cd009b58761fef1ae2 Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Wed, 5 Jul 2023 12:24:06 +0100 Subject: [PATCH 66/74] Removing pre-install target --- nym-wallet/package.json | 3 +-- package.json | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/nym-wallet/package.json b/nym-wallet/package.json index 36c3ca5017..f14d6dd227 100644 --- a/nym-wallet/package.json +++ b/nym-wallet/package.json @@ -18,8 +18,7 @@ "lint:fix": "eslint src --fix", "prestorybook": "yarn --cwd .. build", "storybook": "start-storybook -p 6006", - "storybook:build": "build-storybook", - "preinstall": "yarn --cwd .. setup:dependencies" + "storybook:build": "build-storybook" }, "dependencies": { "@emotion/react": "^11.7.0", diff --git a/package.json b/package.json index c796364c77..cad6eaf88d 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,6 @@ "types:lint:fix": "lerna run lint:fix --scope @nymproject/types --scope @nymproject/nym-wallet-app", "audit:fix": "npm_config_yes=true npx yarn-audit-fix -- --dry-run", "preinstall": "yarn install:copy-placeholders", - "setup:dependencies": "yarn install:copy-placeholders", "install:copy-placeholders": "cp scripts/build/yarn/wasm-placeholder/package.json sdk/typescript/packages/nym-client-wasm" }, "devDependencies": { From 493f0366876d8e72a44664972b0c989a2dca583b Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Wed, 5 Jul 2023 13:07:19 +0100 Subject: [PATCH 67/74] GitHub Actions: fix up installing project dependencies --- .github/workflows/nym-connect-publish-macos.yml | 4 ++++ .github/workflows/nym-connect-publish-ubuntu.yml | 6 ++++++ .github/workflows/nym-connect-publish-windows10.yml | 4 ++++ .github/workflows/nym-wallet-publish-macos.yml | 4 ++++ .github/workflows/nym-wallet-publish-ubuntu.yml | 4 ++++ 5 files changed, 22 insertions(+) diff --git a/.github/workflows/nym-connect-publish-macos.yml b/.github/workflows/nym-connect-publish-macos.yml index eb0ff1423a..59b8085f6e 100644 --- a/.github/workflows/nym-connect-publish-macos.yml +++ b/.github/workflows/nym-connect-publish-macos.yml @@ -56,6 +56,10 @@ jobs: fileName: '.env' encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} + - name: Install project dependencies + shell: bash + run: cd .. && yarn --network-timeout 100000 + - name: Install app dependencies and build it env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/nym-connect-publish-ubuntu.yml b/.github/workflows/nym-connect-publish-ubuntu.yml index 3997eb3695..87dd024d0c 100644 --- a/.github/workflows/nym-connect-publish-ubuntu.yml +++ b/.github/workflows/nym-connect-publish-ubuntu.yml @@ -35,8 +35,14 @@ jobs: uses: actions-rs/toolchain@v1 with: toolchain: stable + + - name: Install project dependencies + shell: bash + run: cd .. && yarn --network-timeout 100000 + - name: Install app dependencies run: yarn + - name: Create env file uses: timheuer/base64-to-file@v1.2 with: diff --git a/.github/workflows/nym-connect-publish-windows10.yml b/.github/workflows/nym-connect-publish-windows10.yml index 3c4f07f557..a8f723d319 100644 --- a/.github/workflows/nym-connect-publish-windows10.yml +++ b/.github/workflows/nym-connect-publish-windows10.yml @@ -55,6 +55,10 @@ jobs: fileName: '.env' encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} + - name: Install project dependencies + shell: bash + run: cd .. && yarn --network-timeout 100000 + - name: Install app dependencies shell: bash run: yarn --network-timeout 100000 diff --git a/.github/workflows/nym-wallet-publish-macos.yml b/.github/workflows/nym-wallet-publish-macos.yml index 16be7ef2c8..1023af55ba 100644 --- a/.github/workflows/nym-wallet-publish-macos.yml +++ b/.github/workflows/nym-wallet-publish-macos.yml @@ -56,6 +56,10 @@ jobs: fileName: '.env' encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} + - name: Install project dependencies + shell: bash + run: cd .. && yarn --network-timeout 100000 + - name: Install app dependencies and build it env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/nym-wallet-publish-ubuntu.yml b/.github/workflows/nym-wallet-publish-ubuntu.yml index 4073c16f1a..d11e5d10dd 100644 --- a/.github/workflows/nym-wallet-publish-ubuntu.yml +++ b/.github/workflows/nym-wallet-publish-ubuntu.yml @@ -35,6 +35,10 @@ jobs: with: toolchain: stable + - name: Install project dependencies + shell: bash + run: cd .. && yarn --network-timeout 100000 + - name: Install app dependencies run: yarn - name: Create env file From e17ae9dce085318fceaa751dbb1762e5339598ac Mon Sep 17 00:00:00 2001 From: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com> Date: Wed, 5 Jul 2023 13:09:21 +0100 Subject: [PATCH 68/74] Update nym-wallet-publish-ubuntu.yml --- .github/workflows/nym-wallet-publish-ubuntu.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/nym-wallet-publish-ubuntu.yml b/.github/workflows/nym-wallet-publish-ubuntu.yml index bd40db0783..1f76ed34ca 100644 --- a/.github/workflows/nym-wallet-publish-ubuntu.yml +++ b/.github/workflows/nym-wallet-publish-ubuntu.yml @@ -1,5 +1,6 @@ name: Publish Nym Wallet (Ubuntu) on: + workflow_dispatch: release: types: [created] From 68d6ece6c27e75fce44d80ae8ed31f446802b412 Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Wed, 5 Jul 2023 13:11:03 +0100 Subject: [PATCH 69/74] GitHub Actions: add manual trigger --- .github/workflows/nym-wallet-publish-ubuntu.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/nym-wallet-publish-ubuntu.yml b/.github/workflows/nym-wallet-publish-ubuntu.yml index d11e5d10dd..3194032973 100644 --- a/.github/workflows/nym-wallet-publish-ubuntu.yml +++ b/.github/workflows/nym-wallet-publish-ubuntu.yml @@ -1,5 +1,6 @@ name: Publish Nym Wallet (Ubuntu) on: + workflow_dispatch: release: types: [created] From 0e48ff5e9ed6be65d4e9ac44c2ca791a67157a9f Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Wed, 5 Jul 2023 13:49:12 +0100 Subject: [PATCH 70/74] GitHub Action: upload artifact --- .github/workflows/nym-wallet-publish-ubuntu.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/nym-wallet-publish-ubuntu.yml b/.github/workflows/nym-wallet-publish-ubuntu.yml index 3194032973..bb653d7593 100644 --- a/.github/workflows/nym-wallet-publish-ubuntu.yml +++ b/.github/workflows/nym-wallet-publish-ubuntu.yml @@ -53,8 +53,17 @@ jobs: env: TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} + + - name: Upload Artifact + uses: actions/upload-artifact@v3 + with: + name: nym-wallet_1.0.0_amd64.AppImage.tar.gz + path: nym-wallet/target/release/bundle/appimage/nym-wallet*.AppImage.tar.gz + retention-days: 30 + - name: Upload to release based on tag name uses: softprops/action-gh-release@v1 + if: github.event_name == 'release' with: files: | nym-wallet/target/release/bundle/appimage/*.AppImage From bdda08c0b436218a848fe8eefe705db5b82cf7f5 Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Wed, 5 Jul 2023 14:28:10 +0100 Subject: [PATCH 71/74] GitHub Actions: Change artifact upload paths to wildcards --- .github/workflows/nym-connect-publish-macos.yml | 2 +- .github/workflows/nym-connect-publish-ubuntu.yml | 2 +- .github/workflows/nym-connect-publish-windows10.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/nym-connect-publish-macos.yml b/.github/workflows/nym-connect-publish-macos.yml index 59b8085f6e..fd52c251e2 100644 --- a/.github/workflows/nym-connect-publish-macos.yml +++ b/.github/workflows/nym-connect-publish-macos.yml @@ -77,7 +77,7 @@ jobs: uses: actions/upload-artifact@v3 with: name: nym-connect_1.0.0_x64.dmg - path: nym-connect/desktop/target/release/bundle/dmg/nym-connect_1.0.0_x64.dmg + path: nym-connect/desktop/target/release/bundle/dmg/nym-connect_1*_x64.dmg retention-days: 30 - name: Clean up keychain diff --git a/.github/workflows/nym-connect-publish-ubuntu.yml b/.github/workflows/nym-connect-publish-ubuntu.yml index 87dd024d0c..dbeef8a378 100644 --- a/.github/workflows/nym-connect-publish-ubuntu.yml +++ b/.github/workflows/nym-connect-publish-ubuntu.yml @@ -59,7 +59,7 @@ jobs: uses: actions/upload-artifact@v3 with: name: nym-connect.AppImage.tar.gz - path: nym-connect/desktop/target/release/bundle/appimage/nym-connect_1.0.0_amd64.AppImage + path: nym-connect/desktop/target/release/bundle/appimage/nym-connect_1*_amd64.AppImage retention-days: 30 - name: Upload to release based on tag name diff --git a/.github/workflows/nym-connect-publish-windows10.yml b/.github/workflows/nym-connect-publish-windows10.yml index a8f723d319..0a7911c6ed 100644 --- a/.github/workflows/nym-connect-publish-windows10.yml +++ b/.github/workflows/nym-connect-publish-windows10.yml @@ -78,7 +78,7 @@ jobs: uses: actions/upload-artifact@v3 with: name: nym-connect_1.0.0_x64_en-US.msi - path: nym-connect/desktop/target/release/bundle/msi/nym-connect_1.0.0_x64_en-US.msi + path: nym-connect/desktop/target/release/bundle/msi/nym-connect_1*_x64_en-US.msi retention-days: 30 - name: Upload to release based on tag name From 90cc68435cf96734b33068b2e932e19abb1ff9a4 Mon Sep 17 00:00:00 2001 From: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com> Date: Wed, 5 Jul 2023 15:56:31 +0100 Subject: [PATCH 72/74] Update connect-desktop-ci.yml --- .github/workflows/connect-desktop-ci.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/connect-desktop-ci.yml b/.github/workflows/connect-desktop-ci.yml index 569203cfff..76f39572dc 100644 --- a/.github/workflows/connect-desktop-ci.yml +++ b/.github/workflows/connect-desktop-ci.yml @@ -23,8 +23,14 @@ jobs: node-version: 18 - name: Install Yarn run: npm install -g yarn - - run: yarn + + - name: Install project dependencies + run: cd ../.. && yarn --network-timeout 100000 + + - name: Install app dependencies + run: yarn continue-on-error: true + - name: Set environment from the example run: cp .env.sample .env - run: yarn storybook:build From ad995b1934a51f8563c4dbd7f8a7fdb4e674a6ee Mon Sep 17 00:00:00 2001 From: Fouad Date: Wed, 5 Jul 2023 16:14:21 +0100 Subject: [PATCH 73/74] Node Tester SDK examples (#3641) * create parcel example * update plain html example * move chat examples into own dir * add examples to workspace * update tsconfig path * move webpack base to parent dir --- .../examples/{ => chat-app}/parcel/README.md | 0 .../{ => chat-app}/parcel/package.json | 0 .../{ => chat-app}/parcel/src/dom-utils.ts | 0 .../{ => chat-app}/parcel/src/index.html | 0 .../{ => chat-app}/parcel/src/index.ts | 0 .../examples/chat-app/parcel/tsconfig.json | 9 ++ .../{ => chat-app}/plain-html/.babelrc | 0 .../{ => chat-app}/plain-html/README.md | 0 .../{ => chat-app}/plain-html/jest.config.js | 0 .../{ => chat-app}/plain-html/package.json | 0 .../plain-html/src/dom-utils.ts | 0 .../{ => chat-app}/plain-html/src/index.html | 0 .../{ => chat-app}/plain-html/src/index.ts | 0 .../chat-app/plain-html/tsconfig.json | 9 ++ .../plain-html/tsconfig.prod.json | 0 .../plain-html/webpack.common.js | 2 +- .../plain-html/webpack.config.js | 0 .../{ => chat-app}/plain-html/webpack.prod.js | 0 .../react-webpack-with-theme-example/.babelrc | 0 .../README.md | 0 .../jest.config.js | 0 .../package.json | 0 .../src/App.tsx | 0 .../src/ThemeToggle.tsx | 0 .../src/context/index.tsx | 0 .../src/context/mixnet.tsx | 0 .../src/index.html | 0 .../src/index.tsx | 0 .../src/tests/App.test.tsx | 0 .../src/theme/common.ts | 0 .../src/theme/index.tsx | 0 .../src/theme/mui-theme.d.ts | 0 .../src/theme/theme.ts | 0 .../src/typings/FC.d.ts | 0 .../src/typings/svg.d.ts | 0 .../tsconfig.json | 9 ++ .../tsconfig.prod.json | 0 .../webpack.common.js | 0 .../webpack.config.js | 0 .../webpack.prod.js | 0 .../examples/node-tester/parcel/README.md | 14 +++ .../examples/node-tester/parcel/package.json | 43 +++++++ .../node-tester/parcel/src/index.html | 29 +++++ .../examples/node-tester/parcel/src/index.ts | 118 ++++++++++++++++++ .../examples/node-tester/parcel/tsconfig.json | 8 ++ .../examples/node-tester/plain-html/README.md | 2 +- .../node-tester/plain-html/package.json | 3 + .../node-tester/plain-html/tsconfig.json | 1 - sdk/typescript/examples/parcel/tsconfig.json | 16 --- .../examples/plain-html/tsconfig.json | 16 --- .../tsconfig.json | 16 --- 51 files changed, 244 insertions(+), 51 deletions(-) rename sdk/typescript/examples/{ => chat-app}/parcel/README.md (100%) rename sdk/typescript/examples/{ => chat-app}/parcel/package.json (100%) rename sdk/typescript/examples/{ => chat-app}/parcel/src/dom-utils.ts (100%) rename sdk/typescript/examples/{ => chat-app}/parcel/src/index.html (100%) rename sdk/typescript/examples/{ => chat-app}/parcel/src/index.ts (100%) create mode 100644 sdk/typescript/examples/chat-app/parcel/tsconfig.json rename sdk/typescript/examples/{ => chat-app}/plain-html/.babelrc (100%) rename sdk/typescript/examples/{ => chat-app}/plain-html/README.md (100%) rename sdk/typescript/examples/{ => chat-app}/plain-html/jest.config.js (100%) rename sdk/typescript/examples/{ => chat-app}/plain-html/package.json (100%) rename sdk/typescript/examples/{ => chat-app}/plain-html/src/dom-utils.ts (100%) rename sdk/typescript/examples/{ => chat-app}/plain-html/src/index.html (100%) rename sdk/typescript/examples/{ => chat-app}/plain-html/src/index.ts (100%) create mode 100644 sdk/typescript/examples/chat-app/plain-html/tsconfig.json rename sdk/typescript/examples/{ => chat-app}/plain-html/tsconfig.prod.json (100%) rename sdk/typescript/examples/{ => chat-app}/plain-html/webpack.common.js (89%) rename sdk/typescript/examples/{ => chat-app}/plain-html/webpack.config.js (100%) rename sdk/typescript/examples/{ => chat-app}/plain-html/webpack.prod.js (100%) rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/.babelrc (100%) rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/README.md (100%) rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/jest.config.js (100%) rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/package.json (100%) rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/src/App.tsx (100%) rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/src/ThemeToggle.tsx (100%) rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/src/context/index.tsx (100%) rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/src/context/mixnet.tsx (100%) rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/src/index.html (100%) rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/src/index.tsx (100%) rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/src/tests/App.test.tsx (100%) rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/src/theme/common.ts (100%) rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/src/theme/index.tsx (100%) rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/src/theme/mui-theme.d.ts (100%) rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/src/theme/theme.ts (100%) rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/src/typings/FC.d.ts (100%) rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/src/typings/svg.d.ts (100%) create mode 100644 sdk/typescript/examples/chat-app/react-webpack-with-theme-example/tsconfig.json rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/tsconfig.prod.json (100%) rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/webpack.common.js (100%) rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/webpack.config.js (100%) rename sdk/typescript/examples/{ => chat-app}/react-webpack-with-theme-example/webpack.prod.js (100%) create mode 100644 sdk/typescript/examples/node-tester/parcel/README.md create mode 100644 sdk/typescript/examples/node-tester/parcel/package.json create mode 100644 sdk/typescript/examples/node-tester/parcel/src/index.html create mode 100644 sdk/typescript/examples/node-tester/parcel/src/index.ts create mode 100644 sdk/typescript/examples/node-tester/parcel/tsconfig.json delete mode 100644 sdk/typescript/examples/parcel/tsconfig.json delete mode 100644 sdk/typescript/examples/plain-html/tsconfig.json delete mode 100644 sdk/typescript/examples/react-webpack-with-theme-example/tsconfig.json diff --git a/sdk/typescript/examples/parcel/README.md b/sdk/typescript/examples/chat-app/parcel/README.md similarity index 100% rename from sdk/typescript/examples/parcel/README.md rename to sdk/typescript/examples/chat-app/parcel/README.md diff --git a/sdk/typescript/examples/parcel/package.json b/sdk/typescript/examples/chat-app/parcel/package.json similarity index 100% rename from sdk/typescript/examples/parcel/package.json rename to sdk/typescript/examples/chat-app/parcel/package.json diff --git a/sdk/typescript/examples/parcel/src/dom-utils.ts b/sdk/typescript/examples/chat-app/parcel/src/dom-utils.ts similarity index 100% rename from sdk/typescript/examples/parcel/src/dom-utils.ts rename to sdk/typescript/examples/chat-app/parcel/src/dom-utils.ts diff --git a/sdk/typescript/examples/parcel/src/index.html b/sdk/typescript/examples/chat-app/parcel/src/index.html similarity index 100% rename from sdk/typescript/examples/parcel/src/index.html rename to sdk/typescript/examples/chat-app/parcel/src/index.html diff --git a/sdk/typescript/examples/parcel/src/index.ts b/sdk/typescript/examples/chat-app/parcel/src/index.ts similarity index 100% rename from sdk/typescript/examples/parcel/src/index.ts rename to sdk/typescript/examples/chat-app/parcel/src/index.ts diff --git a/sdk/typescript/examples/chat-app/parcel/tsconfig.json b/sdk/typescript/examples/chat-app/parcel/tsconfig.json new file mode 100644 index 0000000000..86902367db --- /dev/null +++ b/sdk/typescript/examples/chat-app/parcel/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "jsx": "react-jsx", + "outDir": "./dist" + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "build", "dist"] +} diff --git a/sdk/typescript/examples/plain-html/.babelrc b/sdk/typescript/examples/chat-app/plain-html/.babelrc similarity index 100% rename from sdk/typescript/examples/plain-html/.babelrc rename to sdk/typescript/examples/chat-app/plain-html/.babelrc diff --git a/sdk/typescript/examples/plain-html/README.md b/sdk/typescript/examples/chat-app/plain-html/README.md similarity index 100% rename from sdk/typescript/examples/plain-html/README.md rename to sdk/typescript/examples/chat-app/plain-html/README.md diff --git a/sdk/typescript/examples/plain-html/jest.config.js b/sdk/typescript/examples/chat-app/plain-html/jest.config.js similarity index 100% rename from sdk/typescript/examples/plain-html/jest.config.js rename to sdk/typescript/examples/chat-app/plain-html/jest.config.js diff --git a/sdk/typescript/examples/plain-html/package.json b/sdk/typescript/examples/chat-app/plain-html/package.json similarity index 100% rename from sdk/typescript/examples/plain-html/package.json rename to sdk/typescript/examples/chat-app/plain-html/package.json diff --git a/sdk/typescript/examples/plain-html/src/dom-utils.ts b/sdk/typescript/examples/chat-app/plain-html/src/dom-utils.ts similarity index 100% rename from sdk/typescript/examples/plain-html/src/dom-utils.ts rename to sdk/typescript/examples/chat-app/plain-html/src/dom-utils.ts diff --git a/sdk/typescript/examples/plain-html/src/index.html b/sdk/typescript/examples/chat-app/plain-html/src/index.html similarity index 100% rename from sdk/typescript/examples/plain-html/src/index.html rename to sdk/typescript/examples/chat-app/plain-html/src/index.html diff --git a/sdk/typescript/examples/plain-html/src/index.ts b/sdk/typescript/examples/chat-app/plain-html/src/index.ts similarity index 100% rename from sdk/typescript/examples/plain-html/src/index.ts rename to sdk/typescript/examples/chat-app/plain-html/src/index.ts diff --git a/sdk/typescript/examples/chat-app/plain-html/tsconfig.json b/sdk/typescript/examples/chat-app/plain-html/tsconfig.json new file mode 100644 index 0000000000..86902367db --- /dev/null +++ b/sdk/typescript/examples/chat-app/plain-html/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "jsx": "react-jsx", + "outDir": "./dist" + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "build", "dist"] +} diff --git a/sdk/typescript/examples/plain-html/tsconfig.prod.json b/sdk/typescript/examples/chat-app/plain-html/tsconfig.prod.json similarity index 100% rename from sdk/typescript/examples/plain-html/tsconfig.prod.json rename to sdk/typescript/examples/chat-app/plain-html/tsconfig.prod.json diff --git a/sdk/typescript/examples/plain-html/webpack.common.js b/sdk/typescript/examples/chat-app/plain-html/webpack.common.js similarity index 89% rename from sdk/typescript/examples/plain-html/webpack.common.js rename to sdk/typescript/examples/chat-app/plain-html/webpack.common.js index 3d5f37c912..ae6ef6dc8e 100644 --- a/sdk/typescript/examples/plain-html/webpack.common.js +++ b/sdk/typescript/examples/chat-app/plain-html/webpack.common.js @@ -1,6 +1,6 @@ const path = require('path'); const { mergeWithRules } = require('webpack-merge'); -const { webpackCommon } = require('../.webpack/webpack.base'); +const { webpackCommon } = require('../../.webpack/webpack.base'); module.exports = mergeWithRules({ module: { diff --git a/sdk/typescript/examples/plain-html/webpack.config.js b/sdk/typescript/examples/chat-app/plain-html/webpack.config.js similarity index 100% rename from sdk/typescript/examples/plain-html/webpack.config.js rename to sdk/typescript/examples/chat-app/plain-html/webpack.config.js diff --git a/sdk/typescript/examples/plain-html/webpack.prod.js b/sdk/typescript/examples/chat-app/plain-html/webpack.prod.js similarity index 100% rename from sdk/typescript/examples/plain-html/webpack.prod.js rename to sdk/typescript/examples/chat-app/plain-html/webpack.prod.js diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/.babelrc b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/.babelrc similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/.babelrc rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/.babelrc diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/README.md b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/README.md similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/README.md rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/README.md diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/jest.config.js b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/jest.config.js similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/jest.config.js rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/jest.config.js diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/package.json b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/package.json similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/package.json rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/package.json diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/src/App.tsx b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/App.tsx similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/src/App.tsx rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/App.tsx diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/src/ThemeToggle.tsx b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/ThemeToggle.tsx similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/src/ThemeToggle.tsx rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/ThemeToggle.tsx diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/src/context/index.tsx b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/context/index.tsx similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/src/context/index.tsx rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/context/index.tsx diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/src/context/mixnet.tsx b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/context/mixnet.tsx similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/src/context/mixnet.tsx rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/context/mixnet.tsx diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/src/index.html b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/index.html similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/src/index.html rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/index.html diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/src/index.tsx b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/index.tsx similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/src/index.tsx rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/index.tsx diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/src/tests/App.test.tsx b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/tests/App.test.tsx similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/src/tests/App.test.tsx rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/tests/App.test.tsx diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/src/theme/common.ts b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/theme/common.ts similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/src/theme/common.ts rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/theme/common.ts diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/src/theme/index.tsx b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/theme/index.tsx similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/src/theme/index.tsx rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/theme/index.tsx diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/src/theme/mui-theme.d.ts b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/theme/mui-theme.d.ts similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/src/theme/mui-theme.d.ts rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/theme/mui-theme.d.ts diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/src/theme/theme.ts b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/theme/theme.ts similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/src/theme/theme.ts rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/theme/theme.ts diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/src/typings/FC.d.ts b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/typings/FC.d.ts similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/src/typings/FC.d.ts rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/typings/FC.d.ts diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/src/typings/svg.d.ts b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/typings/svg.d.ts similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/src/typings/svg.d.ts rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/src/typings/svg.d.ts diff --git a/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/tsconfig.json b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/tsconfig.json new file mode 100644 index 0000000000..86902367db --- /dev/null +++ b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "jsx": "react-jsx", + "outDir": "./dist" + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "build", "dist"] +} diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/tsconfig.prod.json b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/tsconfig.prod.json similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/tsconfig.prod.json rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/tsconfig.prod.json diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/webpack.common.js b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/webpack.common.js similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/webpack.common.js rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/webpack.common.js diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/webpack.config.js b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/webpack.config.js similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/webpack.config.js rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/webpack.config.js diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/webpack.prod.js b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/webpack.prod.js similarity index 100% rename from sdk/typescript/examples/react-webpack-with-theme-example/webpack.prod.js rename to sdk/typescript/examples/chat-app/react-webpack-with-theme-example/webpack.prod.js diff --git a/sdk/typescript/examples/node-tester/parcel/README.md b/sdk/typescript/examples/node-tester/parcel/README.md new file mode 100644 index 0000000000..6669b8f164 --- /dev/null +++ b/sdk/typescript/examples/node-tester/parcel/README.md @@ -0,0 +1,14 @@ +# Nym Node Tester - Parcel bundler + +This is an example of using the Nym Mixnet node tester. + +You can use this example as a seed for a new project. + +## Running the example + +Try out the node tester app by running: + +``` +npm install +npm start +``` diff --git a/sdk/typescript/examples/node-tester/parcel/package.json b/sdk/typescript/examples/node-tester/parcel/package.json new file mode 100644 index 0000000000..27c563a40e --- /dev/null +++ b/sdk/typescript/examples/node-tester/parcel/package.json @@ -0,0 +1,43 @@ +{ + "name": "@nymproject/sdk-example-node-tester-plain-html-parcel", + "description": "An example project that uses WASM and plain HTML bundled with Parcel v2", + "version": "1.0.0", + "license": "Apache-2.0", + "source": "src/index.html", + "browserslist": "> 0.5%, last 2 versions, not dead", + "dependencies": { + "@nymproject/sdk": "1" + }, + "devDependencies": { + "@types/jest": "^27.0.1", + "@types/node": "^16.7.13", + "@typescript-eslint/eslint-plugin": "^5.13.0", + "@typescript-eslint/parser": "^5.13.0", + "eslint": "^8.10.0", + "eslint-config-airbnb": "^19.0.4", + "eslint-config-airbnb-typescript": "^16.1.0", + "eslint-config-prettier": "^8.5.0", + "eslint-import-resolver-root-import": "^1.0.4", + "eslint-plugin-import": "^2.25.4", + "eslint-plugin-jest": "^26.1.1", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-prettier": "^4.0.0", + "jest": "^27.1.0", + "mini-css-extract-plugin": "^2.2.2", + "npm-run-all": "^4.1.5", + "prettier": "^2.8.7", + "ts-jest": "^27.0.5", + "typescript": "^4.6.2" + }, + "scripts": { + "start": "npx parcel", + "build": "npx parcel build", + "build:serve": "npx serve dist", + "test": "jest", + "test:watch": "jest --watch", + "tsc": "tsc", + "tsc:watch": "tsc --watch", + "lint": "eslint src", + "lint:fix": "eslint src --fix" + } +} diff --git a/sdk/typescript/examples/node-tester/parcel/src/index.html b/sdk/typescript/examples/node-tester/parcel/src/index.html new file mode 100644 index 0000000000..a7bd3057e7 --- /dev/null +++ b/sdk/typescript/examples/node-tester/parcel/src/index.html @@ -0,0 +1,29 @@ + + + + + + + Nym WebAssembly Demo + + + +

+ +

+

+ + + + +

+ +

Test a mixnode by entering the mixnode id above and click the Test button

+ +
+

+

+

+ + + diff --git a/sdk/typescript/examples/node-tester/parcel/src/index.ts b/sdk/typescript/examples/node-tester/parcel/src/index.ts new file mode 100644 index 0000000000..350be6e469 --- /dev/null +++ b/sdk/typescript/examples/node-tester/parcel/src/index.ts @@ -0,0 +1,118 @@ +import { createNodeTesterClient, NodeTester } from '@nymproject/sdk'; + +let nodeTester: NodeTester | null = null; + +/** + * Display messages that have been sent up the websocket. Colours them blue. + * + * @param {string} message + */ +function displayOutput(message: string, color?: string) { + const timestamp = new Date().toISOString().substr(11, 12); + + const sendDiv = document.createElement('div'); + const paragraph = document.createElement('p'); + paragraph.setAttribute('style', `color: ${color || 'blue'}`); + const paragraphContent = document.createTextNode(`${timestamp} >>> ${message}`); + paragraph.appendChild(paragraphContent); + + sendDiv.appendChild(paragraph); + document.getElementById('output')?.appendChild(sendDiv); +} + +/** + * The main entry point + */ +async function main() { + nodeTester = await createNodeTesterClient(); + + // add node tester to the Window globally, so that it can be used from the dev tools console + (window as any).nodeTester = nodeTester; + + if (!nodeTester) { + console.error('Oh no! Could not the node test'); + return; + } + + const nymApiUrl = 'https://validator.nymtech.net/api'; + const nodeTesterId = new Date().toISOString(); // make a new tester id for each session + await nodeTester.tester.init(nymApiUrl, nodeTesterId); + + const mixnodes = await (await fetch(`${nymApiUrl}/v1/mixnodes/active`)).json(); + + const exampleMixnodeIdentityKey = mixnodes[0].bond_information.mix_node.identity_key; + + const testButton: HTMLButtonElement = document.querySelector('#test-button') as HTMLButtonElement; + const reconnectButton: HTMLButtonElement = document.querySelector('#reconnect-button') as HTMLButtonElement; + const disconnectButton: HTMLButtonElement = document.querySelector('#disconnect-button') as HTMLButtonElement; + const terminateButton: HTMLButtonElement = document.querySelector('#terminate-button') as HTMLButtonElement; + + const mixnodeIdInput = document.getElementById('mixnodeId') as HTMLFormElement; + + mixnodeIdInput.value = exampleMixnodeIdentityKey; + + reconnectButton.onclick = async function () { + try { + await nodeTester?.tester.reconnectToGateway(); + } catch (e: any) { + console.error('Error', e); + displayOutput(`ERROR: ${e.message}`, 'red'); + } + }; + + disconnectButton.onclick = async function () { + try { + await nodeTester?.tester.disconnectFromGateway(); + } catch (e: any) { + console.error('Error', e); + displayOutput(`ERROR: ${e.message}`, 'red'); + } + }; + + terminateButton.onclick = async function () { + try { + await nodeTester?.terminate(); + } catch (e: any) { + console.error('Error', e); + displayOutput(`ERROR: ${e.message}`, 'red'); + } + }; + + if (testButton) { + testButton.onclick = async function () { + console.log('clicked'); + + const mixnodeId = mixnodeIdInput.value; + if (!nodeTester) { + displayOutput('ERROR: The node tester is not defined'); + console.error('The node tester is not defined'); + return; + } + if (!mixnodeId) { + displayOutput('ERROR: No mix id specified'); + console.error('No mix id specified'); + return; + } + + if (nodeTester && mixnodeId) { + displayOutput('Starting test...'); + try { + const response = await nodeTester.tester.startTest(mixnodeId); + displayOutput('Done!'); + if (response) { + displayOutput(JSON.stringify(response, null, 2), 'green'); + } + } catch (e: any) { + console.error('Error', e); + displayOutput(`ERROR: ${e.message}`, 'red'); + } + } + }; + } +} + +// wait for the html to load +window.addEventListener('DOMContentLoaded', () => { + // let's do this! + main(); +}); diff --git a/sdk/typescript/examples/node-tester/parcel/tsconfig.json b/sdk/typescript/examples/node-tester/parcel/tsconfig.json new file mode 100644 index 0000000000..5403eafc03 --- /dev/null +++ b/sdk/typescript/examples/node-tester/parcel/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist" + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "build", "dist"] +} diff --git a/sdk/typescript/examples/node-tester/plain-html/README.md b/sdk/typescript/examples/node-tester/plain-html/README.md index a255725316..7a613f68a2 100644 --- a/sdk/typescript/examples/node-tester/plain-html/README.md +++ b/sdk/typescript/examples/node-tester/plain-html/README.md @@ -1,4 +1,4 @@ -# HTML Nyn Node Test +# Nym Node Tester - HTML This is an example of using the Nym Mixnet node tester. diff --git a/sdk/typescript/examples/node-tester/plain-html/package.json b/sdk/typescript/examples/node-tester/plain-html/package.json index a3befe83ea..b80734f6d4 100644 --- a/sdk/typescript/examples/node-tester/plain-html/package.json +++ b/sdk/typescript/examples/node-tester/plain-html/package.json @@ -3,6 +3,9 @@ "description": "An example project that uses WASM node tester and plain HTML", "version": "1.0.0", "license": "Apache-2.0", + "dependencies": { + "@nymproject/sdk": "1" + }, "devDependencies": { "@babel/core": "^7.15.0", "@babel/plugin-transform-async-to-generator": "^7.14.5", diff --git a/sdk/typescript/examples/node-tester/plain-html/tsconfig.json b/sdk/typescript/examples/node-tester/plain-html/tsconfig.json index 86902367db..5403eafc03 100644 --- a/sdk/typescript/examples/node-tester/plain-html/tsconfig.json +++ b/sdk/typescript/examples/node-tester/plain-html/tsconfig.json @@ -1,7 +1,6 @@ { "extends": "../../../tsconfig.json", "compilerOptions": { - "jsx": "react-jsx", "outDir": "./dist" }, "include": ["src/**/*.ts", "src/**/*.tsx"], diff --git a/sdk/typescript/examples/parcel/tsconfig.json b/sdk/typescript/examples/parcel/tsconfig.json deleted file mode 100644 index b8059e8698..0000000000 --- a/sdk/typescript/examples/parcel/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "jsx": "react-jsx", - "outDir": "./dist" - }, - "include": [ - "src/**/*.ts", - "src/**/*.tsx" - ], - "exclude": [ - "node_modules", - "build", - "dist" - ] -} diff --git a/sdk/typescript/examples/plain-html/tsconfig.json b/sdk/typescript/examples/plain-html/tsconfig.json deleted file mode 100644 index b8059e8698..0000000000 --- a/sdk/typescript/examples/plain-html/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "jsx": "react-jsx", - "outDir": "./dist" - }, - "include": [ - "src/**/*.ts", - "src/**/*.tsx" - ], - "exclude": [ - "node_modules", - "build", - "dist" - ] -} diff --git a/sdk/typescript/examples/react-webpack-with-theme-example/tsconfig.json b/sdk/typescript/examples/react-webpack-with-theme-example/tsconfig.json deleted file mode 100644 index b8059e8698..0000000000 --- a/sdk/typescript/examples/react-webpack-with-theme-example/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "jsx": "react-jsx", - "outDir": "./dist" - }, - "include": [ - "src/**/*.ts", - "src/**/*.tsx" - ], - "exclude": [ - "node_modules", - "build", - "dist" - ] -} From a1334577220372f945dd8b4f57db96214785e1c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 6 Jul 2023 10:08:39 +0100 Subject: [PATCH 74/74] chore: applied fmt for let-else statements (#3649) --- clients/native/src/websocket/handler.rs | 11 +++++---- common/async-file-watcher/src/lib.rs | 2 +- .../src/client/cover_traffic_stream.rs | 2 +- .../real_messages_control/message_handler.rs | 2 +- .../real_traffic_stream.rs | 2 +- .../client/replies/reply_controller/mod.rs | 9 +++++-- .../src/client/transmission_buffer.rs | 2 +- .../create_family_join_permit_sign_payload.rs | 9 +++++-- common/node-tester-utils/src/tester.rs | 15 ++++++++---- .../socks5-client-core/src/socks/request.rs | 2 +- common/store-cipher/src/lib.rs | 2 +- .../mixnet/src/families/signature_helpers.rs | 8 +++++-- .../src/network_monitor/monitor/preparer.rs | 24 +++++++++---------- .../network-requester/src/core.rs | 4 +++- 14 files changed, 59 insertions(+), 35 deletions(-) diff --git a/clients/native/src/websocket/handler.rs b/clients/native/src/websocket/handler.rs index 3830a31894..3185d71900 100644 --- a/clients/native/src/websocket/handler.rs +++ b/clients/native/src/websocket/handler.rs @@ -117,10 +117,11 @@ impl Handler { let Ok(base_length) = self .lane_queue_lengths .lock() - .map(|guard| guard.get(&conn_lane).unwrap_or_default()) else { + .map(|guard| guard.get(&conn_lane).unwrap_or_default()) + else { // I'd argue we should panic here as this error it not recoverable error!("The lane queue length lock is poisoned!!"); - return None + return None; }; // get the number of pending replies waiting for reply surbs @@ -174,7 +175,7 @@ impl Handler { // Only reply back with a `LaneQueueLength` if the sender providided a connection id let TransmissionLane::ConnectionId(connection_id) = lane else { - return None + return None; }; self.get_lane_queue_length(connection_id).await @@ -206,7 +207,7 @@ impl Handler { // Only reply back with a `LaneQueueLength` if the sender providided a connection id let TransmissionLane::ConnectionId(connection_id) = lane else { - return None + return None; }; self.get_lane_queue_length(connection_id).await @@ -233,7 +234,7 @@ impl Handler { // Only reply back with a `LaneQueueLength` if the sender providided a connection id let TransmissionLane::ConnectionId(connection_id) = lane else { - return None + return None; }; self.get_lane_queue_length(connection_id).await diff --git a/common/async-file-watcher/src/lib.rs b/common/async-file-watcher/src/lib.rs index 73faaa3dfa..e2ff23e830 100644 --- a/common/async-file-watcher/src/lib.rs +++ b/common/async-file-watcher/src/lib.rs @@ -101,7 +101,7 @@ impl AsyncFileWatcher { } let Some(filters) = &self.filters else { - return true + return true; }; for filter in filters { diff --git a/common/client-core/src/client/cover_traffic_stream.rs b/common/client-core/src/client/cover_traffic_stream.rs index 5e0a1408d9..8784bfb7ba 100644 --- a/common/client-core/src/client/cover_traffic_stream.rs +++ b/common/client-core/src/client/cover_traffic_stream.rs @@ -153,7 +153,7 @@ impl LoopCoverTrafficStream { fn loop_cover_message_size(&mut self) -> PacketSize { let Some(secondary_packet_size) = self.secondary_packet_size else { - return self.primary_packet_size + return self.primary_packet_size; }; let use_primary = self diff --git a/common/client-core/src/client/real_messages_control/message_handler.rs b/common/client-core/src/client/real_messages_control/message_handler.rs index b0846955c1..07482aa77f 100644 --- a/common/client-core/src/client/real_messages_control/message_handler.rs +++ b/common/client-core/src/client/real_messages_control/message_handler.rs @@ -224,7 +224,7 @@ where // if secondary packet was never set, then it's obvious we have to use the primary packet let Some(secondary_packet) = self.config.secondary_packet_size else { trace!("only primary packet size is available"); - return self.config.primary_packet_size + return self.config.primary_packet_size; }; let primary_count = diff --git a/common/client-core/src/client/real_messages_control/real_traffic_stream.rs b/common/client-core/src/client/real_messages_control/real_traffic_stream.rs index 39c0e25f41..44c9810e70 100644 --- a/common/client-core/src/client/real_messages_control/real_traffic_stream.rs +++ b/common/client-core/src/client/real_messages_control/real_traffic_stream.rs @@ -200,7 +200,7 @@ where fn loop_cover_message_size(&mut self) -> PacketSize { let Some(secondary_packet_size) = self.config.traffic.secondary_packet_size else { - return self.config.traffic.primary_packet_size + return self.config.traffic.primary_packet_size; }; let use_primary = self diff --git a/common/client-core/src/client/replies/reply_controller/mod.rs b/common/client-core/src/client/replies/reply_controller/mod.rs index 0e5a5a0ae9..4ba9ce3ac9 100644 --- a/common/client-core/src/client/replies/reply_controller/mod.rs +++ b/common/client-core/src/client/replies/reply_controller/mod.rs @@ -727,7 +727,11 @@ where continue; } - let Some(last_received) = self.full_reply_storage.surbs_storage_ref().surbs_last_received_at(pending_reply_target) else { + let Some(last_received) = self + .full_reply_storage + .surbs_storage_ref() + .surbs_last_received_at(pending_reply_target) + else { error!("we have {} pending replies for {pending_reply_target}, but we somehow never received any reply surbs from them!", vals.total_size()); to_remove.push(*pending_reply_target); continue; @@ -811,7 +815,8 @@ where // this should never ever happen (famous last words, eh?), but in case it DOES happen eventually // purge that malformed data - let Ok(sent_at) = OffsetDateTime::from_unix_timestamp(reply_key.sent_at_timestamp) else { + let Ok(sent_at) = OffsetDateTime::from_unix_timestamp(reply_key.sent_at_timestamp) + else { error!("somehow our stored timestamp ({}) for one of our reply key is corrupted!. Going to remove all the entry", reply_key.sent_at_timestamp); to_remove_keys.push(*digest); continue; diff --git a/common/client-core/src/client/transmission_buffer.rs b/common/client-core/src/client/transmission_buffer.rs index 65c0e23976..326cfa7f53 100644 --- a/common/client-core/src/client/transmission_buffer.rs +++ b/common/client-core/src/client/transmission_buffer.rs @@ -180,7 +180,7 @@ impl TransmissionBuffer { while items.len() < n { let Some(next) = self.pop_next_message_at_random(rng) else { - break + break; }; items.push(next) } diff --git a/common/commands/src/validator/mixnet/operators/mixnode/families/create_family_join_permit_sign_payload.rs b/common/commands/src/validator/mixnet/operators/mixnode/families/create_family_join_permit_sign_payload.rs index 735832be08..a305df4839 100644 --- a/common/commands/src/validator/mixnet/operators/mixnode/families/create_family_join_permit_sign_payload.rs +++ b/common/commands/src/validator/mixnet/operators/mixnode/families/create_family_join_permit_sign_payload.rs @@ -35,9 +35,14 @@ pub async fn create_family_join_permit_sign_payload(args: Args, client: QueryCli info!("Create family join permit sign payload"); // get the address of our mixnode to recover the family head information - let Some(mixnode) = client.get_owned_mixnode(&args.address).await.unwrap().mixnode_details else { + let Some(mixnode) = client + .get_owned_mixnode(&args.address) + .await + .unwrap() + .mixnode_details + else { eprintln!("{} does not seem to even own a mixnode!", args.address); - return + return; }; // make sure this mixnode is actually a family head diff --git a/common/node-tester-utils/src/tester.rs b/common/node-tester-utils/src/tester.rs index 0b807c54f2..6577ef61f5 100644 --- a/common/node-tester-utils/src/tester.rs +++ b/common/node-tester-utils/src/tester.rs @@ -154,7 +154,7 @@ where T: Serialize + Clone, { let Some(node) = self.base_topology.find_mix(mix_id) else { - return Err(NetworkTestingError::NonExistentMixnode {mix_id}) + return Err(NetworkTestingError::NonExistentMixnode { mix_id }); }; self.mixnode_test_packets(&node.clone(), msg_ext, test_packets, custom_recipient) @@ -170,8 +170,13 @@ where where T: Serialize + Clone, { - let Some(node) = self.base_topology.find_mix_by_identity(&encoded_mix_identity) else { - return Err(NetworkTestingError::NonExistentMixnodeIdentity { mix_identity: encoded_mix_identity }) + let Some(node) = self + .base_topology + .find_mix_by_identity(&encoded_mix_identity) + else { + return Err(NetworkTestingError::NonExistentMixnodeIdentity { + mix_identity: encoded_mix_identity, + }); }; self.mixnode_test_packets(&node.clone(), msg_ext, test_packets, custom_recipient) @@ -212,7 +217,9 @@ where T: Serialize + Clone, { let Some(node) = self.base_topology.find_gateway(&encoded_gateway_identity) else { - return Err(NetworkTestingError::NonExistentGateway { gateway_identity: encoded_gateway_identity }) + return Err(NetworkTestingError::NonExistentGateway { + gateway_identity: encoded_gateway_identity, + }); }; self.gateway_test_packets(&node.clone(), msg_ext, test_packets, custom_recipient) diff --git a/common/socks5-client-core/src/socks/request.rs b/common/socks5-client-core/src/socks/request.rs index 525391c9ab..db222bdc20 100644 --- a/common/socks5-client-core/src/socks/request.rs +++ b/common/socks5-client-core/src/socks/request.rs @@ -107,7 +107,7 @@ impl SocksRequest { // ATYP let Some(addr_type) = AddrType::from(packet[3] as usize) else { error!("No Addr"); - return Err(ResponseCodeV5::AddrTypeNotSupported.into()) + return Err(ResponseCodeV5::AddrTypeNotSupported.into()); }; // DST.ADDR diff --git a/common/store-cipher/src/lib.rs b/common/store-cipher/src/lib.rs index b5bf471b8f..98d586151f 100644 --- a/common/store-cipher/src/lib.rs +++ b/common/store-cipher/src/lib.rs @@ -190,7 +190,7 @@ impl StoreCipher { exported.ciphertext_info.ciphertext(), ) else { key.zeroize(); - return Err(Error::InvalidImportPassphrase) + return Err(Error::InvalidImportPassphrase); }; // if we successfully decrypted aes256gcm ciphertext, it's almost certainly correct diff --git a/contracts/mixnet/src/families/signature_helpers.rs b/contracts/mixnet/src/families/signature_helpers.rs index 186bbc19bc..222c7548cd 100644 --- a/contracts/mixnet/src/families/signature_helpers.rs +++ b/contracts/mixnet/src/families/signature_helpers.rs @@ -24,8 +24,12 @@ pub(crate) fn verify_family_join_permit( let Some(head_mixnode) = mixnodes_storage::mixnode_bonds() .idx .identity_key - .item(deps.storage, granter.identity().to_owned())?.map(|record| record.1) else { - return Err(MixnetContractError::FamilyDoesNotExist { head: granter.identity().to_string() }) + .item(deps.storage, granter.identity().to_owned())? + .map(|record| record.1) + else { + return Err(MixnetContractError::FamilyDoesNotExist { + head: granter.identity().to_string(), + }); }; let nonce = signing_storage::get_signing_nonce(deps.storage, head_mixnode.owner)?; let msg = construct_family_join_permit(nonce, granter, proxy, member.to_owned()); diff --git a/nym-api/src/network_monitor/monitor/preparer.rs b/nym-api/src/network_monitor/monitor/preparer.rs index b873669f99..8b49055476 100644 --- a/nym-api/src/network_monitor/monitor/preparer.rs +++ b/nym-api/src/network_monitor/monitor/preparer.rs @@ -250,24 +250,24 @@ impl PacketPreparer { let mut routes = Vec::new(); for i in 0..most_available { let Ok(node_1) = self.try_parse_mix_bond(rand_l1[i]) else { - blacklist.insert(rand_l1[i].identity().to_owned()); - continue - }; + blacklist.insert(rand_l1[i].identity().to_owned()); + continue; + }; let Ok(node_2) = self.try_parse_mix_bond(rand_l2[i]) else { - blacklist.insert(rand_l2[i].identity().to_owned()); - continue - }; + blacklist.insert(rand_l2[i].identity().to_owned()); + continue; + }; let Ok(node_3) = self.try_parse_mix_bond(rand_l3[i]) else { - blacklist.insert(rand_l3[i].identity().to_owned()); - continue - }; + blacklist.insert(rand_l3[i].identity().to_owned()); + continue; + }; let Ok(gateway) = self.try_parse_gateway_bond(rand_gateways[i]) else { - blacklist.insert(rand_gateways[i].identity().to_owned()); - continue - }; + blacklist.insert(rand_gateways[i].identity().to_owned()); + continue; + }; routes.push(TestRoute::new(rng.gen(), node_1, node_2, node_3, gateway)) } diff --git a/service-providers/network-requester/src/core.rs b/service-providers/network-requester/src/core.rs index 8fa5979c78..b60bc30f41 100644 --- a/service-providers/network-requester/src/core.rs +++ b/service-providers/network-requester/src/core.rs @@ -421,7 +421,9 @@ impl NRServiceProvider { sender_tag: Option, connect_req: Box, ) { - let Some(return_address) = reply::MixnetAddress::new(connect_req.return_address, sender_tag) else { + let Some(return_address) = + reply::MixnetAddress::new(connect_req.return_address, sender_tag) + else { log::warn!( "attempted to start connection with no way of returning data back to the sender" );