Compare commits

...

73 Commits

Author SHA1 Message Date
benedetta davico aa833310da Update validator-api-tests.yml 2023-02-22 13:05:25 +01:00
benedettadavico 17ed80018f adding tests for circulating endpoints 2023-02-06 11:22:52 +01:00
benedettadavico cdfcb065b7 merge develop into feature/wallet-tests 2023-02-06 09:41:23 +01:00
Mark Sinclair fd1c0ae62b Update build-and-upload-binaries-ci.yml 2023-02-03 12:03:13 +00:00
Mark Sinclair bd7399091b Update build-and-upload-binaries-ci.yml 2023-02-03 11:57:32 +00:00
Mark Sinclair 00fad44e2e Update build-and-upload-binaries-ci.yml 2023-02-03 11:46:07 +00:00
Mark Sinclair ea33c332ee GitHub Actions: add action to build and upload binaries to CI server 2023-02-03 11:35:03 +00:00
Bogdan-Ștefan Neacșu b39f8af8d0 Fix flaky dkg test 2023-02-03 12:29:21 +02:00
dependabot[bot] a400463b7e build(deps): bump ua-parser-js in /nym-wallet/webdriver (#2909)
Bumps [ua-parser-js](https://github.com/faisalman/ua-parser-js) from 0.7.28 to 0.7.33.
- [Release notes](https://github.com/faisalman/ua-parser-js/releases)
- [Changelog](https://github.com/faisalman/ua-parser-js/blob/master/changelog.md)
- [Commits](https://github.com/faisalman/ua-parser-js/compare/0.7.28...0.7.33)

---
updated-dependencies:
- dependency-name: ua-parser-js
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-03 10:00:09 +00:00
dependabot[bot] 82928af64c build(deps): bump http-cache-semantics in /nym-wallet/webdriver (#2960)
Bumps [http-cache-semantics](https://github.com/kornelski/http-cache-semantics) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/kornelski/http-cache-semantics/releases)
- [Commits](https://github.com/kornelski/http-cache-semantics/commits)

---
updated-dependencies:
- dependency-name: http-cache-semantics
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-03 09:59:08 +00:00
dependabot[bot] c5891f546c build(deps): bump http-cache-semantics from 4.1.0 to 4.1.1 (#2961)
Bumps [http-cache-semantics](https://github.com/kornelski/http-cache-semantics) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/kornelski/http-cache-semantics/releases)
- [Commits](https://github.com/kornelski/http-cache-semantics/commits)

---
updated-dependencies:
- dependency-name: http-cache-semantics
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-03 09:58:34 +00:00
Tommy Verrall 580b677489 Binary checker, introduction 2023-02-03 08:46:40 -01:00
Jędrzej Stuczyński 2093789c5c Added an option to set custom 'host' for the native client (#2939)
* Added an option to set custom 'host' for the native client

* Changelog entry
2023-02-02 16:38:39 +00:00
Pierre Dommerc d09864b99f build(nc-android): prepare for apk release (#2943)
* chore(nc-android): prepare for production build

* refactor(nc-android): remove dead code

* feat(nc-android): update native color theme

* feat(nc-android): update native color theme

* build(nc-android): fix rfd version issue

* build(nc-android): fix dist dir no such file error

* fix(nc-android): post rebase changes
2023-02-02 15:18:58 +01:00
Bogdan-Ștefan Neacşu f6e8278592 Fix typo during merge back to develop (#2956) 2023-02-02 13:55:58 +02:00
cgi-bin/ b085a8a636 typo: electrum (#2954) 2023-02-02 09:34:08 +00:00
farbanas e6ce531aeb fix: formatting 2023-02-01 17:16:53 +01:00
farbanas 1a860eb3f5 fix: wrong parameter type for addresses in generator commands (should be AccountId instead of String) 2023-02-01 12:45:51 +01:00
Fran Arbanas 09cfd9ff05 Update CHANGELOG.md 2023-01-31 14:42:16 +00:00
Bogdan-Ștefan Neacșu 2c88ca137a Resolve merge conflict 2023-01-31 16:19:34 +02:00
farbanas ca3bfc859a merge conflicts 2023-01-31 15:09:35 +01:00
benedettadavico 529db99b8e Merge branch 'develop' into feature/wallet-tests 2023-01-26 11:59:07 +01:00
benedettadavico fd4f083742 adding missing endpoints 2023-01-26 11:58:41 +01:00
benedettadavico 06256e512d adding tests 2023-01-24 15:18:30 +01:00
benedettadavico 6b4e915cd6 Merge branch 'release/v1.1.7' into feature/wallet-tests 2023-01-24 13:20:36 +01:00
benedettadavico 19cdb7f629 adding tests, cleaning up 2023-01-18 10:52:57 +01:00
benedettadavico 029f8904fe Merge branch 'develop' of https://github.com/nymtech/nym into feature/wallet-tests 2023-01-17 16:12:58 +01:00
benedettadavico 5f852e04a0 run diff envs 2023-01-06 17:49:23 +01:00
benedettadavico 365b955c90 Merge branch 'release/v1.1.5' into feature/wallet-tests 2023-01-06 17:05:22 +01:00
benedettadavico f14a87809e editing tests 2023-01-06 17:04:22 +01:00
benedettadavico a18eec2fe5 fix renaming merge conflicts 2023-01-04 10:50:00 +01:00
benedettadavico 3c99644420 conflicts 2023-01-04 10:45:57 +01:00
benedettadavico d6e6369389 Merge branch 'release/v1.1.4' of https://github.com/nymtech/nym into feature/wallet-tests 2022-12-21 17:13:01 +01:00
Fouad eff1f383c3 Feature/node settings apy playground (#1677) (#2738)
* initial ui for test my node

use svg for node path

add stories for test my node

* add initial rewards calculation

* update validation for rewards playground

* init playground with default values

* get node uptime

* get mixnode reward estimation

* calculate saturation

calculate stake saturation

* Make ComputeRewardEstParam derive Debug

* set active set to be always true

Co-authored-by: Jon Häggblad <jon.haggblad@gmail.com>

Co-authored-by: Jon Häggblad <jon.haggblad@gmail.com>
2022-12-21 12:56:40 +00:00
benedettadavico a192e0d745 Add family to mixnode detailed 2022-12-08 17:52:20 +01:00
benedettadavico 6168ac9e9b Merge branch 'feature/wallet-tests' of https://github.com/nymtech/nym into feature/wallet-tests 2022-12-08 17:39:54 +01:00
benedettadavico f7d96042de Merge branch 'develop' of https://github.com/nymtech/nym into feature/wallet-tests 2022-12-08 17:38:47 +01:00
tommy 353ccbe258 refine... 2022-11-16 17:07:06 +01:00
tommy 6b74a1f091 add ignore - for some reason it wasn't there 2022-11-16 15:48:29 +01:00
tommy 2f191f50ee remove 2022-11-16 13:24:28 +01:00
tommy 0de1196f85 put in placeholder for things 2022-11-16 13:24:05 +01:00
tommy 78c1cc05e1 remove the check for the wallet 2022-11-16 12:42:08 +01:00
tommy ee8101db04 run formatter and remove duplicate deleteFile 2022-11-16 12:36:09 +01:00
benedettadavico cd6c68907c WIP 2022-11-14 13:28:34 +01:00
benedettadavico 452e9ed637 WIP; debugging issues 2022-11-11 17:44:03 +01:00
benedettadavico eeeb8052b6 Merge branch 'release/v1.1.0' into feature/wallet-tests 2022-11-11 10:23:49 +01:00
benedettadavico bc79ee0cad WIP 2022-11-10 18:29:16 +01:00
benedettadavico aa5cbd06d4 WIP 2022-11-10 11:58:08 +01:00
benedettadavico 15cdf579b2 WIP 2022-11-10 11:57:13 +01:00
benedettadavico caf9429431 Merge branch 'release/v1.1.0', remote-tracking branch 'origin' into feature/wallet-tests 2022-11-10 10:30:06 +01:00
benedettadavico 708782fdf9 WIP 2022-11-10 10:27:11 +01:00
benedettadavico 3fc11d8bef WIP 2022-11-09 18:56:27 +01:00
benedettadavico 2eadda2295 WIP 2022-11-09 16:51:32 +01:00
benedettadavico 9434cb266b WIP 2022-11-09 14:28:49 +01:00
benedettadavico 8f49db1150 WIP 2022-11-09 10:57:24 +01:00
benedettadavico c45e8da43d Merge branch 'develop-with-release-1.1.0-merged-in' into feature/validator-api-tests 2022-11-09 10:15:54 +01:00
benedettadavico 12cc49a734 WIP 2022-11-09 10:05:47 +01:00
benedettadavico 7e56a9e88c WIP 2022-11-08 16:22:39 +01:00
benedettadavico 9790009eac WIP 2022-11-08 12:30:27 +01:00
benedettadavico 379d593daf Updating more tests 2022-11-07 18:37:31 +01:00
benedettadavico ce75b99b6f Merge branch 'release/v1.1.0' into feature/validator-api-tests 2022-11-07 17:36:21 +01:00
benedettadavico bcb7c41fd7 Updating validator api tests for v2 contracts 2022-11-07 17:31:25 +01:00
benedettadavico bb091ce47f Updating validator api tests for v2 contracts 2022-11-07 17:28:13 +01:00
benedettadavico effed4d7d6 Merge branch 'release/v1.1.0' into feature/validator-api-tests 2022-11-07 09:36:16 +01:00
benedettadavico d480ddb133 fixing failing tests 2022-08-15 15:20:23 +02:00
benedettadavico b119820591 Clean up 2022-08-15 09:25:28 +02:00
benedettadavico e128949dc2 Clean up 2022-08-13 20:40:08 +02:00
benedettadavico 9499b987e5 possible approach to validating address length and proxy type 2022-08-13 20:31:50 +02:00
benedettadavico d6ac786295 adding tests 2022-08-12 15:51:23 +02:00
tommy 4d09d9c3db remove 1-2-1 mapping 2022-08-12 13:30:27 +02:00
tommy 8c9044adf3 remove the need to map to type 2022-08-12 13:26:46 +02:00
tommy 472085ca52 Fix up look sharp
- added missing .git files
- fixed paths
- run the linter
2022-08-12 11:18:17 +02:00
benedettadavico 2f089e80ff adding onto the validator-api tests 2022-08-12 10:12:57 +02:00
259 changed files with 12810 additions and 5069 deletions
Vendored
BIN
View File
Binary file not shown.
@@ -0,0 +1,105 @@
name: Build and upload binaries to CI
on:
workflow_dispatch:
push:
paths:
- 'clients/**'
- 'common/**'
- 'contracts/**'
- 'explorer-api/**'
- 'gateway/**'
- 'integrations/**'
- 'mixnode/**'
- 'sdk/rust/nym-sdk/**'
- 'service-providers/**'
- 'nym-api/**'
- 'nym-outfox/**'
- 'tools/nym-cli/**'
- 'tools/ts-rs-cli/**'
pull_request:
paths:
- 'clients/**'
- 'common/**'
- 'contracts/**'
- 'explorer-api/**'
- 'gateway/**'
- 'integrations/**'
- 'mixnode/**'
- 'sdk/rust/nym-sdk/**'
- 'service-providers/**'
- 'nym-api/**'
- 'nym-outfox/**'
- 'tools/nym-cli/**'
- 'tools/ts-rs-cli/**'
env:
NETWORK: mainnet
jobs:
publish-nym:
strategy:
fail-fast: false
matrix:
platform: [ubuntu-20.04]
runs-on: ${{ matrix.platform }}
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
continue-on-error: true
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Build all binaries
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace --release
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: wasm32-unknown-unknown
override: true
components: rustfmt, clippy
- name: Build release contracts
run: make wasm
- name: Prepare build output
shell: bash
run: |
rm -rf ci-builds || true
mkdir ci-builds
cp target/release/nym-client ci-builds
cp target/release/nym-gateway ci-builds
cp target/release/nym-mixnode ci-builds
cp target/release/nym-socks5-client ci-builds
cp target/release/nym-api ci-builds
cp target/release/nym-network-requester ci-builds
cp target/release/nym-network-statistics ci-builds
cp target/release/nym-cli ci-builds
cp contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm ci-builds
cp contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm ci-builds
- name: Deploy branch to CI www
continue-on-error: true
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "ci-builds/"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/builds/${{ env.GITHUB_REF_NAME }}/
EXCLUDE: "/dist/, /node_modules/"
+32
View File
@@ -0,0 +1,32 @@
name: Tests for validator API
on:
push:
paths:
- "nym-api/tests/**"
defaults:
run:
working-directory: nym-api/tests
jobs:
test:
name: validator api tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Node v18
uses: actions/setup-node@v3
with:
node-version: 18.1.0
- name: Install yarn
run: yarn install
- name: Run yarn
run: yarn
- name: Launch tests
run: yarn test:qa
working-directory: nym-api/tests
+23 -8
View File
@@ -4,18 +4,33 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
# [Unreleased] # [Unreleased]
### Added
- remove coconut feature and unify builds ([#2890])
- native-client: is now capable of listening for requests on sockets different than `127.0.0.1` ([#2939]). This can be specified via `--host` flag during `init` or `run`. Alternatively a custom `host` can be set in `config.toml` file under `socket` section.
[#2890]: https://github.com/nymtech/nym/pull/2890
[#2939]: https://github.com/nymtech/nym/pull/2939
# [v1.1.8] (2023-01-31)
### Added ### Added
- dkg rerun from scratch and dkg-specific epochs ([#2839]) - Rust SDK - Support SURBS (anonymous send + storage) ([#2754])
- nym-sdk: add support for surb storage ([#2870]) - dkg rerun from scratch and dkg-specific epochs ([#2810])
- nym-sdk: enable reply-SURBs by default ([#2874]) - Rename `'initial_supply'` field to `'total_supply'` in the circulating supply endpoint ([#2931])
- remove coconut feature and unify builds ([#2890]) - Circulating supply api endpoint (read the note inside before testing/deploying) ([#1902])
### Changed
- nym-api: an `--id` flag is now always explicitly required ([#2873])
[#2754]: https://github.com/nymtech/nym/issues/2754
[#2810]: https://github.com/nymtech/nym/issues/2810
[#2931]: https://github.com/nymtech/nym/issues/2931
[#1902]: https://github.com/nymtech/nym/issues/1902
[#2873]: https://github.com/nymtech/nym/issues/2873
[#2839]: https://github.com/nymtech/nym/pull/2839
[#2870]: https://github.com/nymtech/nym/pull/2870
[#2874]: https://github.com/nymtech/nym/pull/2874
[#2890]: https://github.com/nymtech/nym/pull/2890
# [v1.1.7] (2023-01-24) # [v1.1.7] (2023-01-24)
Generated
+11 -10
View File
@@ -701,7 +701,7 @@ dependencies = [
[[package]] [[package]]
name = "client-core" name = "client-core"
version = "1.1.7" version = "1.1.8"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"client-connections", "client-connections",
@@ -1891,7 +1891,7 @@ dependencies = [
[[package]] [[package]]
name = "explorer-api" name = "explorer-api"
version = "1.1.7" version = "1.1.8"
dependencies = [ dependencies = [
"chrono", "chrono",
"clap 4.1.3", "clap 4.1.3",
@@ -3314,6 +3314,7 @@ dependencies = [
"cw4", "cw4",
"schemars", "schemars",
"serde", "serde",
"thiserror",
] ]
[[package]] [[package]]
@@ -3437,7 +3438,7 @@ dependencies = [
[[package]] [[package]]
name = "nym-api" name = "nym-api"
version = "1.1.7" version = "1.1.8"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@@ -3535,7 +3536,7 @@ dependencies = [
[[package]] [[package]]
name = "nym-cli" name = "nym-cli"
version = "1.1.7" version = "1.1.8"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base64 0.13.1", "base64 0.13.1",
@@ -3593,7 +3594,7 @@ dependencies = [
[[package]] [[package]]
name = "nym-client" name = "nym-client"
version = "1.1.7" version = "1.1.8"
dependencies = [ dependencies = [
"build-information", "build-information",
"clap 4.1.3", "clap 4.1.3",
@@ -3633,7 +3634,7 @@ dependencies = [
[[package]] [[package]]
name = "nym-gateway" name = "nym-gateway"
version = "1.1.7" version = "1.1.8"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@@ -3685,7 +3686,7 @@ dependencies = [
[[package]] [[package]]
name = "nym-mixnode" name = "nym-mixnode"
version = "1.1.8" version = "1.1.9"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"atty", "atty",
@@ -3730,7 +3731,7 @@ dependencies = [
[[package]] [[package]]
name = "nym-network-requester" name = "nym-network-requester"
version = "1.1.7" version = "1.1.8"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"clap 4.1.3", "clap 4.1.3",
@@ -3762,7 +3763,7 @@ dependencies = [
[[package]] [[package]]
name = "nym-network-statistics" name = "nym-network-statistics"
version = "1.1.7" version = "1.1.8"
dependencies = [ dependencies = [
"dirs", "dirs",
"log", "log",
@@ -3819,7 +3820,7 @@ dependencies = [
[[package]] [[package]]
name = "nym-socks5-client" name = "nym-socks5-client"
version = "1.1.7" version = "1.1.8"
dependencies = [ dependencies = [
"build-information", "build-information",
"clap 4.1.3", "clap 4.1.3",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "client-core" name = "client-core"
version = "1.1.7" version = "1.1.8"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"] authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
edition = "2021" edition = "2021"
rust-version = "1.66" rust-version = "1.66"
+8 -8
View File
@@ -546,35 +546,35 @@ impl<T: NymConfig> Default for Client<T> {
impl<T: NymConfig> Client<T> { impl<T: NymConfig> Client<T> {
fn default_private_identity_key_file(id: &str) -> PathBuf { fn default_private_identity_key_file(id: &str) -> PathBuf {
T::default_data_directory(Some(id)).join("private_identity.pem") T::default_data_directory(id).join("private_identity.pem")
} }
fn default_public_identity_key_file(id: &str) -> PathBuf { fn default_public_identity_key_file(id: &str) -> PathBuf {
T::default_data_directory(Some(id)).join("public_identity.pem") T::default_data_directory(id).join("public_identity.pem")
} }
fn default_private_encryption_key_file(id: &str) -> PathBuf { fn default_private_encryption_key_file(id: &str) -> PathBuf {
T::default_data_directory(Some(id)).join("private_encryption.pem") T::default_data_directory(id).join("private_encryption.pem")
} }
fn default_public_encryption_key_file(id: &str) -> PathBuf { fn default_public_encryption_key_file(id: &str) -> PathBuf {
T::default_data_directory(Some(id)).join("public_encryption.pem") T::default_data_directory(id).join("public_encryption.pem")
} }
fn default_gateway_shared_key_file(id: &str) -> PathBuf { fn default_gateway_shared_key_file(id: &str) -> PathBuf {
T::default_data_directory(Some(id)).join("gateway_shared.pem") T::default_data_directory(id).join("gateway_shared.pem")
} }
fn default_ack_key_file(id: &str) -> PathBuf { fn default_ack_key_file(id: &str) -> PathBuf {
T::default_data_directory(Some(id)).join("ack_key.pem") T::default_data_directory(id).join("ack_key.pem")
} }
fn default_reply_surb_database_path(id: &str) -> PathBuf { fn default_reply_surb_database_path(id: &str) -> PathBuf {
T::default_data_directory(Some(id)).join("persistent_reply_store.sqlite") T::default_data_directory(id).join("persistent_reply_store.sqlite")
} }
fn default_database_path(id: &str) -> PathBuf { fn default_database_path(id: &str) -> PathBuf {
T::default_data_directory(Some(id)).join(DB_FILE_NAME) T::default_data_directory(id).join(DB_FILE_NAME)
} }
} }
+1 -1
View File
@@ -149,7 +149,7 @@ pub fn load_existing_gateway_config<T>(id: &str) -> Result<GatewayEndpointConfig
where where
T: NymConfig + ClientCoreConfigTrait, T: NymConfig + ClientCoreConfigTrait,
{ {
T::load_from_file(Some(id)) T::load_from_file(id)
.map(|existing_config| existing_config.get_gateway_endpoint().clone()) .map(|existing_config| existing_config.get_gateway_endpoint().clone())
.map_err(|err| { .map_err(|err| {
log::error!( log::error!(
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "nym-client" name = "nym-client"
version = "1.1.7" version = "1.1.8"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"] authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client" description = "Implementation of the Nym Client"
edition = "2021" edition = "2021"
+13 -1
View File
@@ -9,6 +9,7 @@ use config::defaults::DEFAULT_WEBSOCKET_LISTENING_PORT;
use config::{NymConfig, OptionalSet}; use config::{NymConfig, OptionalSet};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt::Debug; use std::fmt::Debug;
use std::net::{IpAddr, Ipv4Addr};
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
@@ -104,6 +105,11 @@ impl Config {
self self
} }
pub fn with_host(mut self, host: IpAddr) -> Self {
self.socket.host = host;
self
}
pub fn with_port(mut self, port: u16) -> Self { pub fn with_port(mut self, port: u16) -> Self {
self.socket.listening_port = port; self.socket.listening_port = port;
self self
@@ -130,6 +136,10 @@ impl Config {
self.socket.socket_type self.socket.socket_type
} }
pub fn get_listening_ip(&self) -> IpAddr {
self.socket.host
}
pub fn get_listening_port(&self) -> u16 { pub fn get_listening_port(&self) -> u16 {
self.socket.listening_port self.socket.listening_port
} }
@@ -180,9 +190,10 @@ impl Config {
} }
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize)] #[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)] #[serde(default, deny_unknown_fields)]
pub struct Socket { pub struct Socket {
socket_type: SocketType, socket_type: SocketType,
host: IpAddr,
listening_port: u16, listening_port: u16,
} }
@@ -190,6 +201,7 @@ impl Default for Socket {
fn default() -> Self { fn default() -> Self {
Socket { Socket {
socket_type: SocketType::WebSocket, socket_type: SocketType::WebSocket,
host: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
listening_port: DEFAULT_WEBSOCKET_LISTENING_PORT, listening_port: DEFAULT_WEBSOCKET_LISTENING_PORT,
} }
} }
@@ -93,6 +93,9 @@ socket_type = '{{ socket.socket_type }}'
# will be listening for incoming requests # will be listening for incoming requests
listening_port = {{ socket.listening_port }} listening_port = {{ socket.listening_port }}
# if applicable (for the case of 'WebSocket'), the ip address on which the client
# will be listening for incoming requests
host = '{{ socket.host }}'
##### logging configuration options ##### ##### logging configuration options #####
+2 -1
View File
@@ -102,7 +102,8 @@ impl SocketClient {
reply_controller_sender, reply_controller_sender,
); );
websocket::Listener::new(config.get_listening_port()).start(websocket_handler, shutdown); websocket::Listener::new(config.get_listening_ip(), config.get_listening_port())
.start(websocket_handler, shutdown);
} }
/// blocking version of `start_socket` method. Will run forever (or until SIGINT is sent) /// blocking version of `start_socket` method. Will run forever (or until SIGINT is sent)
+7 -1
View File
@@ -12,6 +12,7 @@ use crypto::asymmetric::identity;
use nymsphinx::addressing::clients::Recipient; use nymsphinx::addressing::clients::Recipient;
use serde::Serialize; use serde::Serialize;
use std::fmt::Display; use std::fmt::Display;
use std::net::IpAddr;
use tap::TapFallible; use tap::TapFallible;
#[derive(Args, Clone)] #[derive(Args, Clone)]
@@ -46,6 +47,10 @@ pub(crate) struct Init {
#[clap(short, long)] #[clap(short, long)]
port: Option<u16>, port: Option<u16>,
/// Ip for the socket (if applicable) to listen for requests.
#[clap(long)]
host: Option<IpAddr>,
/// Mostly debug-related option to increase default traffic rate so that you would not need to /// Mostly debug-related option to increase default traffic rate so that you would not need to
/// modify config post init /// modify config post init
#[clap(long, hide = true)] #[clap(long, hide = true)]
@@ -71,6 +76,7 @@ impl From<Init> for OverrideConfig {
nym_apis: init_config.nym_apis, nym_apis: init_config.nym_apis,
disable_socket: init_config.disable_socket, disable_socket: init_config.disable_socket,
port: init_config.port, port: init_config.port,
host: init_config.host,
fastmode: init_config.fastmode, fastmode: init_config.fastmode,
no_cover: init_config.no_cover, no_cover: init_config.no_cover,
@@ -108,7 +114,7 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
let id = &args.id; let id = &args.id;
let already_init = Config::default_config_file_path(Some(id)).exists(); let already_init = Config::default_config_file_path(id).exists();
if already_init { if already_init {
println!("Client \"{id}\" was already initialised before"); println!("Client \"{id}\" was already initialised before");
} }
+3
View File
@@ -9,6 +9,7 @@ use completions::{fig_generate, ArgShell};
use config::OptionalSet; use config::OptionalSet;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use std::error::Error; use std::error::Error;
use std::net::IpAddr;
pub(crate) mod init; pub(crate) mod init;
pub(crate) mod run; pub(crate) mod run;
@@ -56,6 +57,7 @@ pub(crate) struct OverrideConfig {
nym_apis: Option<Vec<url::Url>>, nym_apis: Option<Vec<url::Url>>,
disable_socket: Option<bool>, disable_socket: Option<bool>,
port: Option<u16>, port: Option<u16>,
host: Option<IpAddr>,
fastmode: bool, fastmode: bool,
no_cover: bool, no_cover: bool,
nyxd_urls: Option<Vec<url::Url>>, nyxd_urls: Option<Vec<url::Url>>,
@@ -81,6 +83,7 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
.with_base(BaseConfig::with_high_default_traffic_volume, args.fastmode) .with_base(BaseConfig::with_high_default_traffic_volume, args.fastmode)
.with_base(BaseConfig::with_disabled_cover_traffic, args.no_cover) .with_base(BaseConfig::with_disabled_cover_traffic, args.no_cover)
.with_optional(Config::with_port, args.port) .with_optional(Config::with_port, args.port)
.with_optional(Config::with_host, args.host)
.with_optional_custom_env_ext( .with_optional_custom_env_ext(
BaseConfig::with_custom_nym_apis, BaseConfig::with_custom_nym_apis,
args.nym_apis, args.nym_apis,
+7 -1
View File
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use std::error::Error; use std::error::Error;
use std::net::IpAddr;
use crate::{ use crate::{
client::{config::Config, SocketClient}, client::{config::Config, SocketClient},
@@ -43,6 +44,10 @@ pub(crate) struct Run {
#[clap(short, long)] #[clap(short, long)]
port: Option<u16>, port: Option<u16>,
/// Ip for the socket (if applicable) to listen for requests.
#[clap(long)]
host: Option<IpAddr>,
/// Mostly debug-related option to increase default traffic rate so that you would not need to /// Mostly debug-related option to increase default traffic rate so that you would not need to
/// modify config post init /// modify config post init
#[clap(long, hide = true)] #[clap(long, hide = true)]
@@ -64,6 +69,7 @@ impl From<Run> for OverrideConfig {
nym_apis: run_config.nym_apis, nym_apis: run_config.nym_apis,
disable_socket: run_config.disable_socket, disable_socket: run_config.disable_socket,
port: run_config.port, port: run_config.port,
host: run_config.host,
fastmode: run_config.fastmode, fastmode: run_config.fastmode,
no_cover: run_config.no_cover, no_cover: run_config.no_cover,
nyxd_urls: run_config.nyxd_urls, nyxd_urls: run_config.nyxd_urls,
@@ -94,7 +100,7 @@ fn version_check(cfg: &Config) -> bool {
pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn Error + Send + Sync>> { pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn Error + Send + Sync>> {
let id = &args.id; let id = &args.id;
let mut config = match Config::load_from_file(Some(id)) { let mut config = match Config::load_from_file(id) {
Ok(cfg) => cfg, Ok(cfg) => cfg,
Err(err) => { Err(err) => {
error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {err})", id); error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {err})", id);
+1 -1
View File
@@ -131,7 +131,7 @@ pub(crate) fn execute(args: &Upgrade) {
let id = &args.id; let id = &args.id;
let existing_config = Config::load_from_file(Some(id)).unwrap_or_else(|err| { let existing_config = Config::load_from_file(id).unwrap_or_else(|err| {
eprintln!("failed to load existing config file! - {err}"); eprintln!("failed to load existing config file! - {err}");
process::exit(1) process::exit(1)
}); });
+3 -3
View File
@@ -3,6 +3,7 @@
use super::handler::HandlerBuilder; use super::handler::HandlerBuilder;
use log::*; use log::*;
use std::net::IpAddr;
use std::{net::SocketAddr, process, sync::Arc}; use std::{net::SocketAddr, process, sync::Arc};
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
use tokio::{sync::Notify, task::JoinHandle}; use tokio::{sync::Notify, task::JoinHandle};
@@ -24,10 +25,9 @@ pub(crate) struct Listener {
} }
impl Listener { impl Listener {
pub(crate) fn new(port: u16) -> Self { pub(crate) fn new(host: IpAddr, port: u16) -> Self {
Listener { Listener {
// unless we find compelling reason not to, just listen on local only address: SocketAddr::new(host, port),
address: SocketAddr::new("127.0.0.1".parse().unwrap(), port),
state: State::AwaitingConnection, state: State::AwaitingConnection,
} }
} }
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "nym-socks5-client" name = "nym-socks5-client"
version = "1.1.7" version = "1.1.8"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"] authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address" description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021" edition = "2021"
+1 -1
View File
@@ -117,7 +117,7 @@ pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
let id = &args.id; let id = &args.id;
let provider_address = &args.provider; let provider_address = &args.provider;
let already_init = Config::default_config_file_path(Some(id)).exists(); let already_init = Config::default_config_file_path(id).exists();
if already_init { if already_init {
println!("SOCKS5 client \"{id}\" was already initialised before"); println!("SOCKS5 client \"{id}\" was already initialised before");
} }
+1 -1
View File
@@ -108,7 +108,7 @@ fn version_check(cfg: &Config) -> bool {
pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn std::error::Error + Send + Sync>> { pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let id = &args.id; let id = &args.id;
let mut config = match Config::load_from_file(Some(id)) { let mut config = match Config::load_from_file(id) {
Ok(cfg) => cfg, Ok(cfg) => cfg,
Err(err) => { Err(err) => {
error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {err})", id); error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {err})", id);
+1 -1
View File
@@ -144,7 +144,7 @@ pub(crate) fn execute(args: &Upgrade) {
let id = &args.id; let id = &args.id;
let existing_config = Config::load_from_file(Some(id)).unwrap_or_else(|err| { let existing_config = Config::load_from_file(id).unwrap_or_else(|err| {
eprintln!("failed to load existing config file! - {err}"); eprintln!("failed to load existing config file! - {err}");
process::exit(1) process::exit(1)
}); });
@@ -1,10 +1,13 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net> // Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use std::str::FromStr;
use clap::Parser; use clap::Parser;
use log::{debug, info}; use log::{debug, info};
use coconut_bandwidth_contract_common::msg::InstantiateMsg; use coconut_bandwidth_contract_common::msg::InstantiateMsg;
use validator_client::nyxd::AccountId;
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Args { pub struct Args {
@@ -12,7 +15,7 @@ pub struct Args {
pub pool_addr: String, pub pool_addr: String,
#[clap(long)] #[clap(long)]
pub multisig_addr: Option<String>, pub multisig_addr: Option<AccountId>,
#[clap(long)] #[clap(long)]
pub mix_denom: Option<String>, pub mix_denom: Option<String>,
@@ -24,8 +27,10 @@ pub async fn generate(args: Args) {
debug!("Received arguments: {:?}", args); debug!("Received arguments: {:?}", args);
let multisig_addr = args.multisig_addr.unwrap_or_else(|| { let multisig_addr = args.multisig_addr.unwrap_or_else(|| {
std::env::var(network_defaults::var_names::REWARDING_VALIDATOR_ADDRESS) let address = std::env::var(network_defaults::var_names::REWARDING_VALIDATOR_ADDRESS)
.expect("Multisig address has to be set") .expect("Multisig address has to be set");
AccountId::from_str(address.as_str())
.expect("Failed converting multisig address to AccountId")
}); });
let mix_denom = args.mix_denom.unwrap_or_else(|| { let mix_denom = args.mix_denom.unwrap_or_else(|| {
@@ -34,7 +39,7 @@ pub async fn generate(args: Args) {
let instantiate_msg = InstantiateMsg { let instantiate_msg = InstantiateMsg {
pool_addr: args.pool_addr, pool_addr: args.pool_addr,
multisig_addr, multisig_addr: multisig_addr.to_string(),
mix_denom, mix_denom,
}; };
@@ -7,6 +7,7 @@ use std::str::FromStr;
use coconut_dkg_common::msg::InstantiateMsg; use coconut_dkg_common::msg::InstantiateMsg;
use coconut_dkg_common::types::TimeConfiguration; use coconut_dkg_common::types::TimeConfiguration;
use validator_client::nyxd::AccountId;
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Args { pub struct Args {
@@ -14,7 +15,7 @@ pub struct Args {
pub group_addr: String, pub group_addr: String,
#[clap(long)] #[clap(long)]
pub multisig_addr: Option<String>, pub multisig_addr: Option<AccountId>,
#[clap(long)] #[clap(long)]
pub public_key_submission_time_secs: Option<u64>, pub public_key_submission_time_secs: Option<u64>,
@@ -44,8 +45,10 @@ pub async fn generate(args: Args) {
debug!("Received arguments: {:?}", args); debug!("Received arguments: {:?}", args);
let multisig_addr = args.multisig_addr.unwrap_or_else(|| { let multisig_addr = args.multisig_addr.unwrap_or_else(|| {
std::env::var(network_defaults::var_names::REWARDING_VALIDATOR_ADDRESS) let address = std::env::var(network_defaults::var_names::REWARDING_VALIDATOR_ADDRESS)
.expect("Multisig address has to be set") .expect("Multisig address has to be set");
AccountId::from_str(address.as_str())
.expect("Failed converting multisig address to AccountId")
}); });
let mix_denom = args.mix_denom.unwrap_or_else(|| { let mix_denom = args.mix_denom.unwrap_or_else(|| {
@@ -86,7 +89,7 @@ pub async fn generate(args: Args) {
let instantiate_msg = InstantiateMsg { let instantiate_msg = InstantiateMsg {
group_addr: args.group_addr, group_addr: args.group_addr,
multisig_addr, multisig_addr: multisig_addr.to_string(),
time_configuration: Some(time_configuration), time_configuration: Some(time_configuration),
mix_denom, mix_denom,
}; };
@@ -6,15 +6,17 @@ use log::{debug, info};
use cosmwasm_std::Decimal; use cosmwasm_std::Decimal;
use mixnet_contract_common::{InitialRewardingParams, InstantiateMsg, Percent}; use mixnet_contract_common::{InitialRewardingParams, InstantiateMsg, Percent};
use std::str::FromStr;
use std::time::Duration; use std::time::Duration;
use validator_client::nyxd::AccountId;
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Args { pub struct Args {
#[clap(long)] #[clap(long)]
pub rewarding_validator_address: Option<String>, pub rewarding_validator_address: Option<AccountId>,
#[clap(long)] #[clap(long)]
pub vesting_contract_address: Option<String>, pub vesting_contract_address: Option<AccountId>,
#[clap(long)] #[clap(long)]
pub rewarding_denom: Option<String>, pub rewarding_denom: Option<String>,
@@ -77,13 +79,17 @@ pub async fn generate(args: Args) {
debug!("initial_rewarding_params: {:?}", initial_rewarding_params); debug!("initial_rewarding_params: {:?}", initial_rewarding_params);
let rewarding_validator_address = args.rewarding_validator_address.unwrap_or_else(|| { let rewarding_validator_address = args.rewarding_validator_address.unwrap_or_else(|| {
std::env::var(network_defaults::var_names::REWARDING_VALIDATOR_ADDRESS) let address = std::env::var(network_defaults::var_names::REWARDING_VALIDATOR_ADDRESS)
.expect("Rewarding validator address has to be set") .expect("Rewarding validator address has to be set");
AccountId::from_str(address.as_str())
.expect("Failed converting rewarding validator address to AccountId")
}); });
let vesting_contract_address = args.vesting_contract_address.unwrap_or_else(|| { let vesting_contract_address = args.vesting_contract_address.unwrap_or_else(|| {
std::env::var(network_defaults::var_names::VESTING_CONTRACT_ADDRESS) let address = std::env::var(network_defaults::var_names::VESTING_CONTRACT_ADDRESS)
.expect("Vesting contract address has to be set") .expect("Vesting contract address has to be set");
AccountId::from_str(address.as_str())
.expect("Failed converting vesting contract address to AccountId")
}); });
let rewarding_denom = args.rewarding_denom.unwrap_or_else(|| { let rewarding_denom = args.rewarding_denom.unwrap_or_else(|| {
@@ -92,8 +98,8 @@ pub async fn generate(args: Args) {
}); });
let instantiate_msg = InstantiateMsg { let instantiate_msg = InstantiateMsg {
rewarding_validator_address, rewarding_validator_address: rewarding_validator_address.to_string(),
vesting_contract_address, vesting_contract_address: vesting_contract_address.to_string(),
rewarding_denom, rewarding_denom,
epochs_in_interval: args.epochs_in_interval, epochs_in_interval: args.epochs_in_interval,
epoch_duration: Duration::from_secs(args.epoch_duration), epoch_duration: Duration::from_secs(args.epoch_duration),
@@ -1,12 +1,14 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net> // Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use clap::Parser; use std::str::FromStr;
use log::{debug, info};
use clap::Parser;
use cosmwasm_std::Decimal; use cosmwasm_std::Decimal;
use cw_utils::{Duration, Threshold}; use cw_utils::{Duration, Threshold};
use log::{debug, info};
use multisig_contract_common::msg::InstantiateMsg; use multisig_contract_common::msg::InstantiateMsg;
use validator_client::nyxd::AccountId;
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Args { pub struct Args {
@@ -20,10 +22,10 @@ pub struct Args {
pub max_voting_period: u64, pub max_voting_period: u64,
#[clap(long)] #[clap(long)]
pub coconut_bandwidth_contract_address: Option<String>, pub coconut_bandwidth_contract_address: Option<AccountId>,
#[clap(long)] #[clap(long)]
pub coconut_dkg_contract_address: Option<String>, pub coconut_dkg_contract_address: Option<AccountId>,
} }
pub async fn generate(args: Args) { pub async fn generate(args: Args) {
@@ -33,13 +35,18 @@ pub async fn generate(args: Args) {
let coconut_bandwidth_contract_address = let coconut_bandwidth_contract_address =
args.coconut_bandwidth_contract_address.unwrap_or_else(|| { args.coconut_bandwidth_contract_address.unwrap_or_else(|| {
std::env::var(network_defaults::var_names::COCONUT_BANDWIDTH_CONTRACT_ADDRESS) let address =
.expect("Coconut bandwidth contract address has to be set") std::env::var(network_defaults::var_names::COCONUT_BANDWIDTH_CONTRACT_ADDRESS)
.expect("Coconut bandwidth contract address has to be set");
AccountId::from_str(address.as_str())
.expect("Failed converting bandwidth contract address to AccountId")
}); });
let coconut_dkg_contract_address = args.coconut_dkg_contract_address.unwrap_or_else(|| { let coconut_dkg_contract_address = args.coconut_dkg_contract_address.unwrap_or_else(|| {
std::env::var(network_defaults::var_names::COCONUT_DKG_CONTRACT_ADDRESS) let address = std::env::var(network_defaults::var_names::COCONUT_DKG_CONTRACT_ADDRESS)
.expect("Coconut DKG contract address has to be set") .expect("Coconut DKG contract address has to be set");
AccountId::from_str(address.as_str())
.expect("Failed converting DKG contract address to AccountId")
}); });
let instantiate_msg = InstantiateMsg { let instantiate_msg = InstantiateMsg {
@@ -49,8 +56,8 @@ pub async fn generate(args: Args) {
.expect("threshold can't be converted to Decimal"), .expect("threshold can't be converted to Decimal"),
}, },
max_voting_period: Duration::Time(args.max_voting_period), max_voting_period: Duration::Time(args.max_voting_period),
coconut_bandwidth_contract_address, coconut_bandwidth_contract_address: coconut_bandwidth_contract_address.to_string(),
coconut_dkg_contract_address, coconut_dkg_contract_address: coconut_dkg_contract_address.to_string(),
}; };
debug!("instantiate_msg: {:?}", instantiate_msg); debug!("instantiate_msg: {:?}", instantiate_msg);
@@ -1,15 +1,18 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net> // Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use std::str::FromStr;
use clap::Parser; use clap::Parser;
use log::{debug, info}; use log::{debug, info};
use validator_client::nyxd::AccountId;
use vesting_contract_common::InitMsg; use vesting_contract_common::InitMsg;
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Args { pub struct Args {
#[clap(long)] #[clap(long)]
pub mixnet_contract_address: Option<String>, pub mixnet_contract_address: Option<AccountId>,
#[clap(long)] #[clap(long)]
pub mix_denom: Option<String>, pub mix_denom: Option<String>,
@@ -21,8 +24,10 @@ pub async fn generate(args: Args) {
debug!("Received arguments: {:?}", args); debug!("Received arguments: {:?}", args);
let mixnet_contract_address = args.mixnet_contract_address.unwrap_or_else(|| { let mixnet_contract_address = args.mixnet_contract_address.unwrap_or_else(|| {
std::env::var(network_defaults::var_names::MIXNET_CONTRACT_ADDRESS) let address = std::env::var(network_defaults::var_names::MIXNET_CONTRACT_ADDRESS)
.expect("Mixnet contract address has to be set") .expect("Mixnet contract address has to be set");
AccountId::from_str(address.as_str())
.expect("Failed converting mixnet address to AccountId")
}); });
let mix_denom = args.mix_denom.unwrap_or_else(|| { let mix_denom = args.mix_denom.unwrap_or_else(|| {
@@ -30,7 +35,7 @@ pub async fn generate(args: Args) {
}); });
let instantiate_msg = InitMsg { let instantiate_msg = InitMsg {
mixnet_contract_address, mixnet_contract_address: mixnet_contract_address.to_string(),
mix_denom, mix_denom,
}; };
+11 -27
View File
@@ -30,23 +30,15 @@ pub trait NymConfig: Default + Serialize + DeserializeOwned {
fn default_root_directory() -> PathBuf; fn default_root_directory() -> PathBuf;
// default, most probable, implementations; can be easily overridden where required // default, most probable, implementations; can be easily overridden where required
fn default_config_directory(id: Option<&str>) -> PathBuf { fn default_config_directory(id: &str) -> PathBuf {
if let Some(id) = id { Self::default_root_directory().join(id).join(CONFIG_DIR)
Self::default_root_directory().join(id).join(CONFIG_DIR)
} else {
Self::default_root_directory().join(CONFIG_DIR)
}
} }
fn default_data_directory(id: Option<&str>) -> PathBuf { fn default_data_directory(id: &str) -> PathBuf {
if let Some(id) = id { Self::default_root_directory().join(id).join(DATA_DIR)
Self::default_root_directory().join(id).join(DATA_DIR)
} else {
Self::default_root_directory().join(DATA_DIR)
}
} }
fn default_config_file_path(id: Option<&str>) -> PathBuf { fn default_config_file_path(id: &str) -> PathBuf {
Self::default_config_directory(id).join(Self::config_file_name()) Self::default_config_directory(id).join(Self::config_file_name())
} }
@@ -54,23 +46,15 @@ pub trait NymConfig: Default + Serialize + DeserializeOwned {
fn try_default_root_directory() -> Option<PathBuf>; fn try_default_root_directory() -> Option<PathBuf>;
fn try_default_config_directory(id: Option<&str>) -> Option<PathBuf> { fn try_default_config_directory(id: &str) -> Option<PathBuf> {
if let Some(id) = id { Self::try_default_root_directory().map(|d| d.join(id).join(CONFIG_DIR))
Self::try_default_root_directory().map(|d| d.join(id).join(CONFIG_DIR))
} else {
Self::try_default_root_directory().map(|d| d.join(CONFIG_DIR))
}
} }
fn try_default_data_directory(id: Option<&str>) -> Option<PathBuf> { fn try_default_data_directory(id: &str) -> Option<PathBuf> {
if let Some(id) = id { Self::try_default_root_directory().map(|d| d.join(id).join(DATA_DIR))
Self::try_default_root_directory().map(|d| d.join(id).join(DATA_DIR))
} else {
Self::try_default_root_directory().map(|d| d.join(DATA_DIR))
}
} }
fn try_default_config_file_path(id: Option<&str>) -> Option<PathBuf> { fn try_default_config_file_path(id: &str) -> Option<PathBuf> {
Self::try_default_config_directory(id).map(|d| d.join(Self::config_file_name())) Self::try_default_config_directory(id).map(|d| d.join(Self::config_file_name()))
} }
@@ -113,7 +97,7 @@ pub trait NymConfig: Default + Serialize + DeserializeOwned {
Ok(()) Ok(())
} }
fn load_from_file(id: Option<&str>) -> io::Result<Self> { fn load_from_file(id: &str) -> io::Result<Self> {
let file = Self::default_config_file_path(id); let file = Self::default_config_file_path(id);
log::trace!("Loading from file: {:#?}", file); log::trace!("Loading from file: {:#?}", file);
let config_contents = fs::read_to_string(file)?; let config_contents = fs::read_to_string(file)?;
@@ -13,3 +13,4 @@ cw4 = { version = "0.13.4" }
cosmwasm-std = "1.0.0" cosmwasm-std = "1.0.0"
schemars = "0.8" schemars = "0.8"
serde = { version = "1.0.103", default-features = false, features = ["derive"] } serde = { version = "1.0.103", default-features = false, features = ["derive"] }
thiserror = { version = "1.0.23" }
@@ -1,3 +1,6 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::StdError; use cosmwasm_std::StdError;
use cw_utils::ThresholdError; use cw_utils::ThresholdError;
@@ -1 +1,2 @@
pub mod error;
pub mod msg; pub mod msg;
+2 -1
View File
@@ -2,8 +2,9 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::{entry_point, Addr, Coin, DepsMut, Empty, Env, Response}; use cosmwasm_std::{entry_point, Addr, Coin, DepsMut, Empty, Env, Response};
use cw3_flex_multisig::{state::CONFIG, ContractError}; use cw3_flex_multisig::state::CONFIG;
use cw_multi_test::{App, AppBuilder, Contract, ContractWrapper}; use cw_multi_test::{App, AppBuilder, Contract, ContractWrapper};
use multisig_contract_common::error::ContractError;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -26,7 +26,6 @@ cw-storage-plus = { version = "0.13.4" }
cosmwasm-std = { version = "1.0.0" } cosmwasm-std = { version = "1.0.0" }
schemars = "0.8.1" schemars = "0.8.1"
serde = { version = "1.0.103", default-features = false, features = ["derive"] } serde = { version = "1.0.103", default-features = false, features = ["derive"] }
thiserror = { version = "1.0.23" }
group-contract-common = { path = "../../../common/cosmwasm-smart-contracts/group-contract" } group-contract-common = { path = "../../../common/cosmwasm-smart-contracts/group-contract" }
multisig-contract-common = { path= "../../../common/cosmwasm-smart-contracts/multisig-contract" } multisig-contract-common = { path= "../../../common/cosmwasm-smart-contracts/multisig-contract" }
@@ -17,8 +17,8 @@ use cw4::{Cw4Contract, MemberChangedHookMsg, MemberDiff};
use cw_storage_plus::Bound; use cw_storage_plus::Bound;
use cw_utils::{maybe_addr, Expiration, ThresholdResponse}; use cw_utils::{maybe_addr, Expiration, ThresholdResponse};
use crate::error::ContractError;
use crate::state::{Config, CONFIG}; use crate::state::{Config, CONFIG};
use multisig_contract_common::error::ContractError;
use multisig_contract_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; use multisig_contract_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
// version info for migration info // version info for migration info
@@ -1,5 +1,2 @@
pub mod contract; pub mod contract;
pub mod error;
pub mod state; pub mod state;
pub use crate::error::ContractError;
+4 -4
View File
@@ -12,10 +12,10 @@ DENOMS_EXPONENT=6
MIXNET_CONTRACT_ADDRESS=n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g MIXNET_CONTRACT_ADDRESS=n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g
VESTING_CONTRACT_ADDRESS=n1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq73f2nw VESTING_CONTRACT_ADDRESS=n1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq73f2nw
BANDWIDTH_CLAIM_CONTRACT_ADDRESS=n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0 BANDWIDTH_CLAIM_CONTRACT_ADDRESS=n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0
COCONUT_BANDWIDTH_CONTRACT_ADDRESS=n12ckdkm3q7eytefs7rwu4ue3t9hxgvl9v08jddmtwgct2ve0pv50q0t8dlt COCONUT_BANDWIDTH_CONTRACT_ADDRESS=n19d2nwj7fdhxqmyvgy8lf3ad49a6vmww4shryhrkj2mqk36att66s6xzszw
GROUP_CONTRACT_ADDRESS=n1rw8fw2mpcpzzq3jpa4e52ufawnmj5a4u68p35umvgskewuw0nlzsaa5w4m GROUP_CONTRACT_ADDRESS=n1fqquzw4mk0pkamgr2ywt2v7h2j9nuyjjn4gvpy8zlpp6xn0uyuzqfm28l5
MULTISIG_CONTRACT_ADDRESS=n14krxe8ukzagwhvec0rmteexu62w8k9kp9sra9ww6em2hnmzcukqsa0utc8 MULTISIG_CONTRACT_ADDRESS=n1gaq3666chd5348apj8cka8t2mckv7azp9espyr7wgpxyuzur5d0sazpysy
COCONUT_DKG_CONTRACT_ADDRESS=n1rl5n6cxuz2hdy3f7d9hsnw8zn0zwwwr0r4dxfz7tktgpgkcnz9zshmvksc COCONUT_DKG_CONTRACT_ADDRESS=n18yadscxw8v35dds7ksv3j0svmjh3h6e7tmxpadk96mvgz27zygkshuf4vs
REWARDING_VALIDATOR_ADDRESS=n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy REWARDING_VALIDATOR_ADDRESS=n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy
STATISTICS_SERVICE_DOMAIN_ADDRESS="https://mainnet-stats.nymte.ch:8090" STATISTICS_SERVICE_DOMAIN_ADDRESS="https://mainnet-stats.nymte.ch:8090"
NYXD="https://qwerty-validator.qa.nymte.ch/" NYXD="https://qwerty-validator.qa.nymte.ch/"
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "explorer-api" name = "explorer-api"
version = "1.1.7" version = "1.1.8"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+10
View File
@@ -1,5 +1,15 @@
## UNRELEASED ## UNRELEASED
## [nym-explorer-v1.0.4](https://github.com/nymtech/nym/tree/nym-explorer-v1.0.4) (2023-01-31)
- Add routing score on gateway list ([#2913])
- Add gateway's last Routing Score to the gateways list page ([#2186])
- Upgrade Sandbox and make below changes: ([#2332])
[#2913]: https://github.com/nymtech/nym/pull/2913
[#2186]: https://github.com/nymtech/nym/issues/2186
[#2332]: https://github.com/nymtech/nym/issues/2332
## [nym-explorer-v1.0.3](https://github.com/nymtech/nym/tree/nym-explorer-v1.0.3) (2023-01-24) ## [nym-explorer-v1.0.3](https://github.com/nymtech/nym/tree/nym-explorer-v1.0.3) (2023-01-24)
- Stake Saturation tooltip on node list and node pages updated ([#2877]) - Stake Saturation tooltip on node list and node pages updated ([#2877])
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@nym/network-explorer", "name": "@nym/network-explorer",
"version": "1.0.3", "version": "1.0.4",
"private": true, "private": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
+1 -1
View File
@@ -9,7 +9,7 @@ export const OVERVIEW_API = `${API_BASE_URL}/overview`;
export const MIXNODE_PING = `${API_BASE_URL}/ping`; export const MIXNODE_PING = `${API_BASE_URL}/ping`;
export const MIXNODES_API = `${API_BASE_URL}/mix-nodes`; export const MIXNODES_API = `${API_BASE_URL}/mix-nodes`;
export const MIXNODE_API = `${API_BASE_URL}/mix-node`; export const MIXNODE_API = `${API_BASE_URL}/mix-node`;
export const GATEWAYS_API = `${NYM_API_BASE_URL}/api/v1/gateways`; export const GATEWAYS_API = `${NYM_API_BASE_URL}/api/v1/status/gateways/detailed`;
export const VALIDATORS_API = `${VALIDATOR_BASE_URL}/validators`; export const VALIDATORS_API = `${VALIDATOR_BASE_URL}/validators`;
export const BLOCK_API = `${NYM_API_BASE_URL}/block`; export const BLOCK_API = `${NYM_API_BASE_URL}/block`;
export const COUNTRY_DATA_API = `${API_BASE_URL}/countries`; export const COUNTRY_DATA_API = `${API_BASE_URL}/countries`;
+9 -3
View File
@@ -15,7 +15,6 @@ import {
CountryDataResponse, CountryDataResponse,
DelegationsResponse, DelegationsResponse,
UniqDelegationsResponse, UniqDelegationsResponse,
GatewayResponse,
GatewayReportResponse, GatewayReportResponse,
UptimeStoryResponse, UptimeStoryResponse,
MixNodeDescriptionResponse, MixNodeDescriptionResponse,
@@ -27,7 +26,10 @@ import {
StatusResponse, StatusResponse,
SummaryOverviewResponse, SummaryOverviewResponse,
ValidatorsResponse, ValidatorsResponse,
GatewayBondAnnotated,
GatewayBond,
} from '../typeDefs/explorer-api'; } from '../typeDefs/explorer-api';
import { toPercentIntegerString } from '../utils';
function getFromCache(key: string) { function getFromCache(key: string) {
const ts = Number(localStorage.getItem('ts')); const ts = Number(localStorage.getItem('ts'));
@@ -89,9 +91,13 @@ export class Api {
return response.json(); return response.json();
}; };
static fetchGateways = async (): Promise<GatewayResponse> => { static fetchGateways = async (): Promise<GatewayBond[]> => {
const res = await fetch(GATEWAYS_API); const res = await fetch(GATEWAYS_API);
return res.json(); const gatewaysAnnotated: GatewayBondAnnotated[] = await res.json();
return gatewaysAnnotated.map(({ gateway_bond, performance }) => ({
...gateway_bond,
performance: toPercentIntegerString(performance),
}));
}; };
static fetchGatewayUptimeStoryById = async (id: string): Promise<UptimeStoryResponse> => static fetchGatewayUptimeStoryById = async (id: string): Promise<UptimeStoryResponse> =>
+5 -5
View File
@@ -1,4 +1,4 @@
import { GatewayResponse, GatewayResponseItem, GatewayReportResponse } from '../typeDefs/explorer-api'; import { GatewayResponse, GatewayBond, GatewayReportResponse } from '../typeDefs/explorer-api';
export type GatewayRowType = { export type GatewayRowType = {
id: string; id: string;
@@ -8,6 +8,7 @@ export type GatewayRowType = {
host: string; host: string;
location: string; location: string;
version: string; version: string;
performance: string;
}; };
export type GatewayEnrichedRowType = GatewayRowType & { export type GatewayEnrichedRowType = GatewayRowType & {
@@ -28,13 +29,11 @@ export function gatewayToGridRow(arrayOfGateways: GatewayResponse): GatewayRowTy
bond: gw.pledge_amount.amount || 0, bond: gw.pledge_amount.amount || 0,
host: gw.gateway.host || '', host: gw.gateway.host || '',
version: gw.gateway.version || '', version: gw.gateway.version || '',
performance: gw.performance,
})); }));
} }
export function gatewayEnrichedToGridRow( export function gatewayEnrichedToGridRow(gateway: GatewayBond, report: GatewayReportResponse): GatewayEnrichedRowType {
gateway: GatewayResponseItem,
report: GatewayReportResponse,
): GatewayEnrichedRowType {
return { return {
id: gateway.owner, id: gateway.owner,
owner: gateway.owner, owner: gateway.owner,
@@ -47,5 +46,6 @@ export function gatewayEnrichedToGridRow(
mixPort: gateway.gateway.mix_port || 0, mixPort: gateway.gateway.mix_port || 0,
routingScore: `${report.most_recent}%`, routingScore: `${report.most_recent}%`,
avgUptime: `${report.last_day || report.last_hour}%`, avgUptime: `${report.last_day || report.last_hour}%`,
performance: gateway.performance,
}; };
} }
+3 -3
View File
@@ -1,7 +1,7 @@
import * as React from 'react'; import * as React from 'react';
import { Alert, AlertTitle, Box, CircularProgress, Grid } from '@mui/material'; import { Alert, AlertTitle, Box, CircularProgress, Grid } from '@mui/material';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { GatewayResponseItem } from '../../typeDefs/explorer-api'; import { GatewayBond } from '../../typeDefs/explorer-api';
import { ColumnsType, DetailTable } from '../../components/DetailTable'; import { ColumnsType, DetailTable } from '../../components/DetailTable';
import { gatewayEnrichedToGridRow, GatewayEnrichedRowType } from '../../components/Gateways'; import { gatewayEnrichedToGridRow, GatewayEnrichedRowType } from '../../components/Gateways';
import { ComponentError } from '../../components/ComponentError'; import { ComponentError } from '../../components/ComponentError';
@@ -69,7 +69,7 @@ const columns: ColumnsType[] = [
/** /**
* Shows gateway details * Shows gateway details
*/ */
const PageGatewayDetailsWithState = ({ selectedGateway }: { selectedGateway: GatewayResponseItem | undefined }) => { const PageGatewayDetailsWithState = ({ selectedGateway }: { selectedGateway: GatewayBond | undefined }) => {
const [enrichGateway, setEnrichGateway] = React.useState<GatewayEnrichedRowType>(); const [enrichGateway, setEnrichGateway] = React.useState<GatewayEnrichedRowType>();
const [status, setStatus] = React.useState<number[] | undefined>(); const [status, setStatus] = React.useState<number[] | undefined>();
const { uptimeReport, uptimeStory } = useGatewayContext(); const { uptimeReport, uptimeStory } = useGatewayContext();
@@ -130,7 +130,7 @@ const PageGatewayDetailsWithState = ({ selectedGateway }: { selectedGateway: Gat
* Guard component to handle loading and not found states * Guard component to handle loading and not found states
*/ */
const PageGatewayDetailGuard: FCWithChildren = () => { const PageGatewayDetailGuard: FCWithChildren = () => {
const [selectedGateway, setSelectedGateway] = React.useState<GatewayResponseItem | undefined>(); const [selectedGateway, setSelectedGateway] = React.useState<GatewayBond | undefined>();
const { gateways } = useMainContext(); const { gateways } = useMainContext();
const { id } = useParams<{ id: string | undefined }>(); const { id } = useParams<{ id: string | undefined }>();
+18
View File
@@ -81,6 +81,24 @@ export const PageGateways: FCWithChildren = () => {
</MuiLink> </MuiLink>
), ),
}, },
{
field: 'performance',
headerName: 'Routing Score',
renderHeader: () => <CustomColumnHeading headingTitle="Routing Score" />,
width: 150,
headerAlign: 'left',
headerClassName: 'MuiDataGrid-header-override',
renderCell: (params: GridRenderCellParams) => (
<MuiLink
sx={{ ...cellStyles }}
component={RRDLink}
to={`/network-components/gateway/${params.row.identityKey}`}
data-testid="pledge-amount"
>
{`${params.value}%`}
</MuiLink>
),
},
{ {
field: 'host', field: 'host',
renderHeader: () => <CustomColumnHeading headingTitle="IP:Port" />, renderHeader: () => <CustomColumnHeading headingTitle="IP:Port" />,
+8 -2
View File
@@ -116,15 +116,21 @@ export interface StatsResponse {
export type MixNodeHistoryResponse = StatsResponse; export type MixNodeHistoryResponse = StatsResponse;
export interface GatewayResponseItem { export interface GatewayBond {
block_height: number; block_height: number;
pledge_amount: Amount; pledge_amount: Amount;
total_delegation: Amount; total_delegation: Amount;
owner: string; owner: string;
gateway: Gateway; gateway: Gateway;
performance: string;
} }
export type GatewayResponse = GatewayResponseItem[]; export interface GatewayBondAnnotated {
gateway_bond: GatewayBond;
performance: string;
}
export type GatewayResponse = GatewayBond[];
export interface GatewayReportResponse { export interface GatewayReportResponse {
identity: string; identity: string;
+1 -1
View File
@@ -3,7 +3,7 @@
[package] [package]
name = "nym-gateway" name = "nym-gateway"
version = "1.1.7" version = "1.1.8"
authors = [ authors = [
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
"Jędrzej Stuczyński <andrew@nymtech.net>", "Jędrzej Stuczyński <andrew@nymtech.net>",
+1 -1
View File
@@ -102,7 +102,7 @@ impl From<Init> for OverrideConfig {
pub async fn execute(args: Init, output: OutputFormat) -> Result<(), Box<dyn Error + Send + Sync>> { pub async fn execute(args: Init, output: OutputFormat) -> Result<(), Box<dyn Error + Send + Sync>> {
println!("Initialising gateway {}...", args.id); println!("Initialising gateway {}...", args.id);
let already_init = if Config::default_config_file_path(Some(&args.id)).exists() { let already_init = if Config::default_config_file_path(&args.id).exists() {
eprintln!( eprintln!(
"Gateway \"{}\" was already initialised before! Config information will be \ "Gateway \"{}\" was already initialised before! Config information will be \
overwritten (but keys will be kept)!", overwritten (but keys will be kept)!",
+1 -1
View File
@@ -139,7 +139,7 @@ fn do_upgrade(mut config: Config, args: &Upgrade, package_version: Version) {
pub async fn execute(args: &Upgrade) { pub async fn execute(args: &Upgrade) {
let package_version = parse_package_version(); let package_version = parse_package_version();
let existing_config = Config::load_from_file(Some(&args.id)).unwrap_or_else(|err| { let existing_config = Config::load_from_file(&args.id).unwrap_or_else(|err| {
eprintln!("failed to load existing config file! - {err}"); eprintln!("failed to load existing config file! - {err}");
process::exit(1) process::exit(1)
}); });
+5 -5
View File
@@ -374,23 +374,23 @@ pub struct Gateway {
impl Gateway { impl Gateway {
fn default_private_sphinx_key_file(id: &str) -> PathBuf { fn default_private_sphinx_key_file(id: &str) -> PathBuf {
Config::default_data_directory(Some(id)).join("private_sphinx.pem") Config::default_data_directory(id).join("private_sphinx.pem")
} }
fn default_public_sphinx_key_file(id: &str) -> PathBuf { fn default_public_sphinx_key_file(id: &str) -> PathBuf {
Config::default_data_directory(Some(id)).join("public_sphinx.pem") Config::default_data_directory(id).join("public_sphinx.pem")
} }
fn default_private_identity_key_file(id: &str) -> PathBuf { fn default_private_identity_key_file(id: &str) -> PathBuf {
Config::default_data_directory(Some(id)).join("private_identity.pem") Config::default_data_directory(id).join("private_identity.pem")
} }
fn default_public_identity_key_file(id: &str) -> PathBuf { fn default_public_identity_key_file(id: &str) -> PathBuf {
Config::default_data_directory(Some(id)).join("public_identity.pem") Config::default_data_directory(id).join("public_identity.pem")
} }
fn default_database_path(id: &str) -> PathBuf { fn default_database_path(id: &str) -> PathBuf {
Config::default_data_directory(Some(id)).join("db.sqlite") Config::default_data_directory(id).join("db.sqlite")
} }
} }
+2 -2
View File
@@ -11,14 +11,14 @@ pub(crate) fn build_config<O: Into<OverrideConfig>>(
id: String, id: String,
override_args: O, override_args: O,
) -> Result<Config, GatewayError> { ) -> Result<Config, GatewayError> {
let config = match Config::load_from_file(Some(&id)) { let config = match Config::load_from_file(&id) {
Ok(cfg) => cfg, Ok(cfg) => cfg,
Err(err) => { Err(err) => {
error!( error!(
"Failed to load config for {id}. Are you sure you have run `init` before? (Error was: {err})", "Failed to load config for {id}. Are you sure you have run `init` before? (Error was: {err})",
); );
return Err(GatewayError::ConfigLoadFailure { return Err(GatewayError::ConfigLoadFailure {
path: Config::default_config_file_path(Some(&id)), path: Config::default_config_file_path(&id),
id, id,
source: err, source: err,
}); });
+1 -1
View File
@@ -3,7 +3,7 @@
[package] [package]
name = "nym-mixnode" name = "nym-mixnode"
version = "1.1.8" version = "1.1.9"
authors = [ authors = [
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
"Jędrzej Stuczyński <andrew@nymtech.net>", "Jędrzej Stuczyński <andrew@nymtech.net>",
+2 -2
View File
@@ -41,7 +41,7 @@ fn read_user_input() -> String {
pub(crate) fn execute(args: Describe) { pub(crate) fn execute(args: Describe) {
// ensure that the mixnode has in fact been initialized // ensure that the mixnode has in fact been initialized
match Config::load_from_file(Some(&args.id)) { match Config::load_from_file(&args.id) {
Ok(cfg) => cfg, Ok(cfg) => cfg,
Err(err) => { Err(err) => {
error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {err})", &args.id); error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {err})", &args.id);
@@ -83,7 +83,7 @@ pub(crate) fn execute(args: Describe) {
// save the struct // save the struct
NodeDescription::save_to_file( NodeDescription::save_to_file(
&node_description, &node_description,
Config::default_config_directory(Some(&args.id)), Config::default_config_directory(&args.id),
) )
.unwrap() .unwrap()
} }
+1 -1
View File
@@ -68,7 +68,7 @@ pub(crate) fn execute(args: &Init, output: OutputFormat) {
let id = &override_config_fields.id; let id = &override_config_fields.id;
eprintln!("Initialising mixnode {id}..."); eprintln!("Initialising mixnode {id}...");
let already_init = if Config::default_config_file_path(Some(id)).exists() { let already_init = if Config::default_config_file_path(id).exists() {
eprintln!("Mixnode \"{id}\" was already initialised before! Config information will be overwritten (but keys will be kept)!"); eprintln!("Mixnode \"{id}\" was already initialised before! Config information will be overwritten (but keys will be kept)!");
true true
} else { } else {
+1 -1
View File
@@ -15,7 +15,7 @@ pub(crate) struct NodeDetails {
} }
pub(crate) fn execute(args: &NodeDetails, output: OutputFormat) { pub(crate) fn execute(args: &NodeDetails, output: OutputFormat) {
let config = match Config::load_from_file(Some(&args.id)) { let config = match Config::load_from_file(&args.id) {
Ok(cfg) => cfg, Ok(cfg) => cfg,
Err(err) => { Err(err) => {
error!( error!(
+1 -1
View File
@@ -79,7 +79,7 @@ fn special_addresses() -> Vec<&'static str> {
pub(crate) async fn execute(args: &Run, output: OutputFormat) { pub(crate) async fn execute(args: &Run, output: OutputFormat) {
eprintln!("Starting mixnode {}...", args.id); eprintln!("Starting mixnode {}...", args.id);
let mut config = match Config::load_from_file(Some(&args.id)) { let mut config = match Config::load_from_file(&args.id) {
Ok(cfg) => cfg, Ok(cfg) => cfg,
Err(err) => { Err(err) => {
error!( error!(
+1 -1
View File
@@ -71,7 +71,7 @@ fn print_signed_text(private_key: &identity::PrivateKey, text: &str) {
} }
pub(crate) fn execute(args: &Sign) { pub(crate) fn execute(args: &Sign) {
let config = match Config::load_from_file(Some(&args.id)) { let config = match Config::load_from_file(&args.id) {
Ok(cfg) => cfg, Ok(cfg) => cfg,
Err(err) => { Err(err) => {
error!( error!(
+1 -1
View File
@@ -125,7 +125,7 @@ fn do_upgrade(mut config: Config, args: &Upgrade, package_version: Version) {
pub(crate) fn execute(args: &Upgrade) { pub(crate) fn execute(args: &Upgrade) {
let package_version = parse_package_version(); let package_version = parse_package_version();
let existing_config = Config::load_from_file(Some(&args.id)).unwrap_or_else(|err| { let existing_config = Config::load_from_file(&args.id).unwrap_or_else(|err| {
eprintln!("failed to load existing config file! - {err}"); eprintln!("failed to load existing config file! - {err}");
process::exit(1) process::exit(1)
}); });
+4 -4
View File
@@ -376,19 +376,19 @@ struct MixNode {
impl MixNode { impl MixNode {
fn default_private_identity_key_file(id: &str) -> PathBuf { fn default_private_identity_key_file(id: &str) -> PathBuf {
Config::default_data_directory(Some(id)).join("private_identity.pem") Config::default_data_directory(id).join("private_identity.pem")
} }
fn default_public_identity_key_file(id: &str) -> PathBuf { fn default_public_identity_key_file(id: &str) -> PathBuf {
Config::default_data_directory(Some(id)).join("public_identity.pem") Config::default_data_directory(id).join("public_identity.pem")
} }
fn default_private_sphinx_key_file(id: &str) -> PathBuf { fn default_private_sphinx_key_file(id: &str) -> PathBuf {
Config::default_data_directory(Some(id)).join("private_sphinx.pem") Config::default_data_directory(id).join("private_sphinx.pem")
} }
fn default_public_sphinx_key_file(id: &str) -> PathBuf { fn default_public_sphinx_key_file(id: &str) -> PathBuf {
Config::default_data_directory(Some(id)).join("public_sphinx.pem") Config::default_data_directory(id).join("public_sphinx.pem")
} }
} }
+1 -1
View File
@@ -58,7 +58,7 @@ impl MixNode {
} }
fn load_node_description(config: &Config) -> NodeDescription { fn load_node_description(config: &Config) -> NodeDescription {
NodeDescription::load_from_file(Config::default_config_directory(Some(&config.get_id()))) NodeDescription::load_from_file(Config::default_config_directory(&config.get_id()))
.unwrap_or_default() .unwrap_or_default()
} }
+1 -1
View File
@@ -3,7 +3,7 @@
[package] [package]
name = "nym-api" name = "nym-api"
version = "1.1.7" version = "1.1.8"
authors = [ authors = [
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
"Jędrzej Stuczyński <andrew@nymtech.net>", "Jędrzej Stuczyński <andrew@nymtech.net>",
+1 -1
View File
@@ -291,7 +291,7 @@ pub struct GatewayUptimeHistoryResponse {
#[derive(Clone, Serialize, Deserialize, schemars::JsonSchema)] #[derive(Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct CirculatingSupplyResponse { pub struct CirculatingSupplyResponse {
pub initial_supply: Coin, pub total_supply: Coin,
pub mixmining_reserve: Coin, pub mixmining_reserve: Coin,
pub vesting_tokens: Coin, pub vesting_tokens: Coin,
pub circulating_supply: Coin, pub circulating_supply: Coin,
+3 -3
View File
@@ -7,7 +7,7 @@ use validator_client::nyxd::Coin;
pub(crate) struct CirculatingSupplyCacheData { pub(crate) struct CirculatingSupplyCacheData {
// no need to cache that one as it's constant, but let's put it here for consistency sake // no need to cache that one as it's constant, but let's put it here for consistency sake
pub(crate) initial_supply: Coin, pub(crate) total_supply: Coin,
pub(crate) mixmining_reserve: Cache<Coin>, pub(crate) mixmining_reserve: Cache<Coin>,
pub(crate) vesting_tokens: Cache<Coin>, pub(crate) vesting_tokens: Cache<Coin>,
pub(crate) circulating_supply: Cache<Coin>, pub(crate) circulating_supply: Cache<Coin>,
@@ -18,7 +18,7 @@ impl CirculatingSupplyCacheData {
let zero_coin = Coin::new(0, &mix_denom); let zero_coin = Coin::new(0, &mix_denom);
CirculatingSupplyCacheData { CirculatingSupplyCacheData {
initial_supply: Coin::new(1_000_000_000_000_000, mix_denom), total_supply: Coin::new(1_000_000_000_000_000, mix_denom),
mixmining_reserve: Cache::new(zero_coin.clone()), mixmining_reserve: Cache::new(zero_coin.clone()),
vesting_tokens: Cache::new(zero_coin.clone()), vesting_tokens: Cache::new(zero_coin.clone()),
circulating_supply: Cache::new(zero_coin), circulating_supply: Cache::new(zero_coin),
@@ -29,7 +29,7 @@ impl CirculatingSupplyCacheData {
impl<'a> From<&'a CirculatingSupplyCacheData> for CirculatingSupplyResponse { impl<'a> From<&'a CirculatingSupplyCacheData> for CirculatingSupplyResponse {
fn from(value: &'a CirculatingSupplyCacheData) -> Self { fn from(value: &'a CirculatingSupplyCacheData) -> Self {
CirculatingSupplyResponse { CirculatingSupplyResponse {
initial_supply: value.initial_supply.clone().into(), total_supply: value.total_supply.clone().into(),
mixmining_reserve: value.mixmining_reserve.clone().into_inner().into(), mixmining_reserve: value.mixmining_reserve.clone().into_inner().into(),
vesting_tokens: value.vesting_tokens.clone().into_inner().into(), vesting_tokens: value.vesting_tokens.clone().into_inner().into(),
circulating_supply: value.circulating_supply.clone().into_inner().into(), circulating_supply: value.circulating_supply.clone().into_inner().into(),
+1 -1
View File
@@ -76,7 +76,7 @@ impl CirculatingSupplyCache {
pub(crate) async fn update(&self, mixmining_reserve: Coin, vesting_tokens: Coin) { pub(crate) async fn update(&self, mixmining_reserve: Coin, vesting_tokens: Coin) {
let mut cache = self.data.write().await; let mut cache = self.data.write().await;
let mut circulating_supply = cache.initial_supply.clone(); let mut circulating_supply = cache.total_supply.clone();
circulating_supply.amount -= mixmining_reserve.amount; circulating_supply.amount -= mixmining_reserve.amount;
circulating_supply.amount -= vesting_tokens.amount; circulating_supply.amount -= vesting_tokens.amount;
+13 -3
View File
@@ -59,7 +59,7 @@ pub(crate) mod tests {
use coconut_dkg_common::dealer::DealerDetails; use coconut_dkg_common::dealer::DealerDetails;
use cosmwasm_std::Addr; use cosmwasm_std::Addr;
use dkg::bte::keys::KeyPair as DkgKeyPair; use dkg::bte::keys::KeyPair as DkgKeyPair;
use dkg::bte::Params; use dkg::bte::{Params, PublicKeyWithProof};
use rand::rngs::OsRng; use rand::rngs::OsRng;
use std::collections::HashMap; use std::collections::HashMap;
use std::path::PathBuf; use std::path::PathBuf;
@@ -186,8 +186,18 @@ pub(crate) mod tests {
let mut bytes = bs58::decode(details.bte_public_key_with_proof.clone()) let mut bytes = bs58::decode(details.bte_public_key_with_proof.clone())
.into_vec() .into_vec()
.unwrap(); .unwrap();
let last_byte = bytes.last_mut().unwrap(); // Find another value for last byte that still deserializes to a public key with proof
*last_byte += 1; let initial_byte = *bytes.last_mut().unwrap();
loop {
let last_byte = bytes.last_mut().unwrap();
let (ret, _) = last_byte.overflowing_add(1);
*last_byte = ret;
// stop when we find that value, or if we do a full round trip of u8 values
// and can't find one, in which case this test is invalid
if PublicKeyWithProof::try_from_bytes(&bytes).is_ok() || ret == initial_byte {
break;
}
}
details.bte_public_key_with_proof = bs58::encode(&bytes).into_string(); details.bte_public_key_with_proof = bs58::encode(&bytes).into_string();
}); });
+9 -6
View File
@@ -5,6 +5,7 @@ use crate::coconut::dkg::client::DkgClient;
use crate::coconut::dkg::complaints::ComplaintReason; use crate::coconut::dkg::complaints::ComplaintReason;
use crate::coconut::dkg::state::{ConsistentState, State}; use crate::coconut::dkg::state::{ConsistentState, State};
use crate::coconut::error::CoconutError; use crate::coconut::error::CoconutError;
use crate::coconut::helpers::accepted_vote_err;
use coconut_dkg_common::event_attributes::DKG_PROPOSAL_ID; use coconut_dkg_common::event_attributes::DKG_PROPOSAL_ID;
use coconut_dkg_common::types::{NodeIndex, TOTAL_DEALINGS}; use coconut_dkg_common::types::{NodeIndex, TOTAL_DEALINGS};
use coconut_dkg_common::verification_key::owner_from_cosmos_msgs; use coconut_dkg_common::verification_key::owner_from_cosmos_msgs;
@@ -203,21 +204,23 @@ pub(crate) async fn verification_key_validation(
.iter() .iter()
.position(|node_index| contract_share.node_index == *node_index) .position(|node_index| contract_share.node_index == *node_index)
{ {
if !check_vk_pairing(&params, &recovered_partials[idx], &vk) { let ret = if !check_vk_pairing(&params, &recovered_partials[idx], &vk) {
dkg_client dkg_client
.vote_verification_key_share(proposal_id, false) .vote_verification_key_share(proposal_id, false)
.await?; .await
} else { } else {
dkg_client dkg_client
.vote_verification_key_share(proposal_id, true) .vote_verification_key_share(proposal_id, true)
.await?; .await
} };
accepted_vote_err(ret)?;
} }
} }
Err(_) => { Err(_) => {
dkg_client let ret = dkg_client
.vote_verification_key_share(proposal_id, false) .vote_verification_key_share(proposal_id, false)
.await? .await;
accepted_vote_err(ret)?;
} }
} }
} }
+18
View File
@@ -0,0 +1,18 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::coconut::error::CoconutError;
use validator_client::nyxd::error::NyxdError::AbciError;
// If the result is already established, the vote might be redundant and
// thus the transaction might fail
pub(crate) fn accepted_vote_err(ret: Result<(), CoconutError>) -> Result<(), CoconutError> {
if let Err(CoconutError::NyxdError(AbciError { ref log, .. })) = ret {
let accepted_err = multisig_contract_common::error::ContractError::NotOpen {}.to_string();
// If redundant voting is not the case, error out on all other error variants
if !log.value().contains(&accepted_err) {
ret?;
}
}
Ok(())
}
+5 -2
View File
@@ -5,6 +5,7 @@ use self::comm::APICommunicationChannel;
use crate::coconut::client::Client as LocalClient; use crate::coconut::client::Client as LocalClient;
use crate::coconut::deposit::extract_encryption_key; use crate::coconut::deposit::extract_encryption_key;
use crate::coconut::error::{CoconutError, Result}; use crate::coconut::error::{CoconutError, Result};
use crate::coconut::helpers::accepted_vote_err;
use crate::support::storage::NymApiStorage; use crate::support::storage::NymApiStorage;
use coconut_bandwidth_contract_common::spend_credential::{ use coconut_bandwidth_contract_common::spend_credential::{
funds_from_cosmos_msgs, SpendCredentialStatus, funds_from_cosmos_msgs, SpendCredentialStatus,
@@ -40,6 +41,7 @@ pub(crate) mod comm;
mod deposit; mod deposit;
pub(crate) mod dkg; pub(crate) mod dkg;
pub(crate) mod error; pub(crate) mod error;
pub(crate) mod helpers;
pub(crate) mod keypair; pub(crate) mod keypair;
#[cfg(test)] #[cfg(test)]
pub(crate) mod tests; pub(crate) mod tests;
@@ -301,7 +303,7 @@ pub async fn verify_bandwidth_credential(
); );
// Vote yes or no on the proposal based on the verification result // Vote yes or no on the proposal based on the verification result
state let ret = state
.client .client
.vote_proposal( .vote_proposal(
proposal_id, proposal_id,
@@ -312,7 +314,8 @@ pub async fn verify_bandwidth_credential(
Some(verify_credential_body.gateway_cosmos_addr().to_owned()), Some(verify_credential_body.gateway_cosmos_addr().to_owned()),
)), )),
) )
.await?; .await;
accepted_vote_err(ret)?;
Ok(Json(VerifyCredentialResponse::new(vote_yes))) Ok(Json(VerifyCredentialResponse::new(vote_yes)))
} }
+12 -14
View File
@@ -44,7 +44,7 @@ pub(crate) struct CliArgs {
/// Id of the nym-api we want to run /// Id of the nym-api we want to run
#[clap(long)] #[clap(long)]
pub(crate) id: Option<String>, pub(crate) id: String,
/// Specifies whether network monitoring is enabled on this API /// Specifies whether network monitoring is enabled on this API
#[clap(short = 'm', long)] #[clap(short = 'm', long)]
@@ -102,12 +102,13 @@ pub(crate) struct CliArgs {
} }
pub(crate) fn build_config(args: CliArgs) -> Result<Config> { pub(crate) fn build_config(args: CliArgs) -> Result<Config> {
let id = args.id.clone();
// try to load config from the file, if it doesn't exist, use default values // try to load config from the file, if it doesn't exist, use default values
let id = args.id.as_deref(); let (config_from_file, already_initialized) = match Config::load_from_file(&id) {
let (config_from_file, _already_initialized) = match Config::load_from_file(id) {
Ok(cfg) => (cfg, true), Ok(cfg) => (cfg, true),
Err(_) => { Err(_) => {
let config_path = Config::default_config_file_path(id) let config_path = Config::default_config_file_path(&id)
.into_os_string() .into_os_string()
.into_string() .into_string()
.unwrap(); .unwrap();
@@ -121,23 +122,20 @@ pub(crate) fn build_config(args: CliArgs) -> Result<Config> {
let config = override_config(config_from_file, args); let config = override_config(config_from_file, args);
if !_already_initialized { if !already_initialized {
fs::create_dir_all(Config::default_config_directory(&id))
.expect("Could not create config directory");
fs::create_dir_all(Config::default_data_directory(&id))
.expect("Could not create data directory");
crate::coconut::dkg::controller::init_keypair(&config)?; crate::coconut::dkg::controller::init_keypair(&config)?;
} }
Ok(config) Ok(config)
} }
pub(crate) fn override_config(mut config: Config, args: CliArgs) -> Config { pub(crate) fn override_config(config: Config, args: CliArgs) -> Config {
if let Some(id) = args.id {
fs::create_dir_all(Config::default_config_directory(Some(&id)))
.expect("Could not create config directory");
fs::create_dir_all(Config::default_data_directory(Some(&id)))
.expect("Could not create data directory");
config = config.with_id(&id);
}
config config
.with_id(&args.id)
.with_optional(Config::with_custom_nyxd_validator, args.nyxd_validator) .with_optional(Config::with_custom_nyxd_validator, args.nyxd_validator)
.with_optional_env( .with_optional_env(
Config::with_custom_mixnet_contract, Config::with_custom_mixnet_contract,
+30 -32
View File
@@ -201,8 +201,8 @@ pub struct NetworkMonitor {
impl NetworkMonitor { impl NetworkMonitor {
pub const DB_FILE: &'static str = "credentials_database.db"; pub const DB_FILE: &'static str = "credentials_database.db";
fn default_credentials_database_path() -> PathBuf { fn default_credentials_database_path(id: &str) -> PathBuf {
Config::default_data_directory(None).join(Self::DB_FILE) Config::default_data_directory(id).join(Self::DB_FILE)
} }
} }
@@ -220,7 +220,7 @@ impl Default for NetworkMonitor {
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT, gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
gateway_connection_timeout: DEFAULT_GATEWAY_CONNECTION_TIMEOUT, gateway_connection_timeout: DEFAULT_GATEWAY_CONNECTION_TIMEOUT,
packet_delivery_timeout: DEFAULT_PACKET_DELIVERY_TIMEOUT, packet_delivery_timeout: DEFAULT_PACKET_DELIVERY_TIMEOUT,
credentials_database_path: Self::default_credentials_database_path(), credentials_database_path: Default::default(),
test_routes: DEFAULT_TEST_ROUTES, test_routes: DEFAULT_TEST_ROUTES,
minimum_test_routes: DEFAULT_MINIMUM_TEST_ROUTES, minimum_test_routes: DEFAULT_MINIMUM_TEST_ROUTES,
route_test_packets: DEFAULT_ROUTE_TEST_PACKETS, route_test_packets: DEFAULT_ROUTE_TEST_PACKETS,
@@ -242,15 +242,15 @@ pub struct NodeStatusAPI {
impl NodeStatusAPI { impl NodeStatusAPI {
pub const DB_FILE: &'static str = "db.sqlite"; pub const DB_FILE: &'static str = "db.sqlite";
fn default_database_path() -> PathBuf { fn default_database_path(id: &str) -> PathBuf {
Config::default_data_directory(None).join(Self::DB_FILE) Config::default_data_directory(id).join(Self::DB_FILE)
} }
} }
impl Default for NodeStatusAPI { impl Default for NodeStatusAPI {
fn default() -> Self { fn default() -> Self {
NodeStatusAPI { NodeStatusAPI {
database_path: Self::default_database_path(), database_path: Default::default(),
caching_interval: DEFAULT_NODE_STATUS_CACHE_INTERVAL, caching_interval: DEFAULT_NODE_STATUS_CACHE_INTERVAL,
} }
} }
@@ -342,24 +342,24 @@ impl CoconutSigner {
pub const COCONUT_VERIFICATION_KEY_FILE: &'static str = "coconut_verification_key.pem"; pub const COCONUT_VERIFICATION_KEY_FILE: &'static str = "coconut_verification_key.pem";
pub const COCONUT_SECRET_KEY_FILE: &'static str = "coconut_secret_key.pem"; pub const COCONUT_SECRET_KEY_FILE: &'static str = "coconut_secret_key.pem";
fn default_coconut_verification_key_path() -> PathBuf { fn default_coconut_verification_key_path(id: &str) -> PathBuf {
Config::default_data_directory(None).join(Self::COCONUT_VERIFICATION_KEY_FILE) Config::default_data_directory(id).join(Self::COCONUT_VERIFICATION_KEY_FILE)
} }
fn default_coconut_secret_key_path() -> PathBuf { fn default_coconut_secret_key_path(id: &str) -> PathBuf {
Config::default_data_directory(None).join(Self::COCONUT_SECRET_KEY_FILE) Config::default_data_directory(id).join(Self::COCONUT_SECRET_KEY_FILE)
} }
fn default_dkg_persistent_state_path() -> PathBuf { fn default_dkg_persistent_state_path(id: &str) -> PathBuf {
Config::default_data_directory(None).join(Self::DKG_PERSISTENT_STATE_FILE) Config::default_data_directory(id).join(Self::DKG_PERSISTENT_STATE_FILE)
} }
fn default_dkg_decryption_key_path() -> PathBuf { fn default_dkg_decryption_key_path(id: &str) -> PathBuf {
Config::default_data_directory(None).join(Self::DKG_DECRYPTION_KEY_FILE) Config::default_data_directory(id).join(Self::DKG_DECRYPTION_KEY_FILE)
} }
fn default_dkg_public_key_with_proof_path() -> PathBuf { fn default_dkg_public_key_with_proof_path(id: &str) -> PathBuf {
Config::default_data_directory(None).join(Self::DKG_PUBLIC_KEY_WITH_PROOF_FILE) Config::default_data_directory(id).join(Self::DKG_PUBLIC_KEY_WITH_PROOF_FILE)
} }
} }
@@ -367,11 +367,11 @@ impl Default for CoconutSigner {
fn default() -> Self { fn default() -> Self {
Self { Self {
enabled: Default::default(), enabled: Default::default(),
dkg_persistent_state_path: CoconutSigner::default_dkg_persistent_state_path(), dkg_persistent_state_path: Default::default(),
verification_key_path: CoconutSigner::default_coconut_verification_key_path(), verification_key_path: Default::default(),
secret_key_path: CoconutSigner::default_coconut_secret_key_path(), secret_key_path: Default::default(),
decryption_key_path: CoconutSigner::default_dkg_decryption_key_path(), decryption_key_path: Default::default(),
public_key_with_proof_path: CoconutSigner::default_dkg_public_key_with_proof_path(), public_key_with_proof_path: Default::default(),
dkg_contract_polling_rate: DEFAULT_DKG_CONTRACT_POLLING_RATE, dkg_contract_polling_rate: DEFAULT_DKG_CONTRACT_POLLING_RATE,
} }
} }
@@ -384,20 +384,18 @@ impl Config {
pub fn with_id(mut self, id: &str) -> Self { pub fn with_id(mut self, id: &str) -> Self {
self.base.id = id.to_string(); self.base.id = id.to_string();
self.node_status_api.database_path = self.node_status_api.database_path = NodeStatusAPI::default_database_path(id);
Config::default_data_directory(Some(id)).join(NodeStatusAPI::DB_FILE);
self.network_monitor.credentials_database_path = self.network_monitor.credentials_database_path =
Config::default_data_directory(Some(id)).join(NetworkMonitor::DB_FILE); NetworkMonitor::default_credentials_database_path(id);
self.coconut_signer.dkg_persistent_state_path = self.coconut_signer.dkg_persistent_state_path =
Config::default_data_directory(Some(id)).join(CoconutSigner::DKG_PERSISTENT_STATE_FILE); CoconutSigner::default_dkg_persistent_state_path(id);
self.coconut_signer.verification_key_path = Config::default_data_directory(Some(id)) self.coconut_signer.verification_key_path =
.join(CoconutSigner::COCONUT_VERIFICATION_KEY_FILE); CoconutSigner::default_coconut_verification_key_path(id);
self.coconut_signer.secret_key_path = self.coconut_signer.secret_key_path = CoconutSigner::default_coconut_secret_key_path(id);
Config::default_data_directory(Some(id)).join(CoconutSigner::COCONUT_SECRET_KEY_FILE);
self.coconut_signer.decryption_key_path = self.coconut_signer.decryption_key_path =
Config::default_data_directory(Some(id)).join(CoconutSigner::DKG_DECRYPTION_KEY_FILE); CoconutSigner::default_dkg_decryption_key_path(id);
self.coconut_signer.public_key_with_proof_path = Config::default_data_directory(Some(id)) self.coconut_signer.public_key_with_proof_path =
.join(CoconutSigner::DKG_PUBLIC_KEY_WITH_PROOF_FILE); CoconutSigner::default_dkg_public_key_with_proof_path(id);
self self
} }
+783
View File
File diff suppressed because one or more lines are too long
@@ -12,12 +12,22 @@ describe("Get circulating supply", (): void => {
it("Get circulating supply amounts", async (): Promise<void> => { it("Get circulating supply amounts", async (): Promise<void> => {
const response = await contract.getCirculatingSupply(); const response = await contract.getCirculatingSupply();
let initial: number = +response.initial_supply.amount; const initial: number = +response.total_supply.amount;
let mixmining: number = +response.mixmining_reserve.amount; const mixmining: number = +response.mixmining_reserve.amount;
let vest: number = +response.vesting_tokens.amount; const vest: number = +response.vesting_tokens.amount;
let circsupply: number = +response.circulating_supply.amount; const circsupply: number = +response.circulating_supply.amount;
expect(typeof response.vesting_tokens.amount).toBe("string"); expect(typeof response.vesting_tokens.amount).toBe("string");
expect(initial - mixmining - vest).toStrictEqual(circsupply); expect(initial - mixmining - vest).toStrictEqual(circsupply);
});
}); });
it("Get total supply value", async (): Promise<void> => {
const response = await contract.getTotalSupplyValue();
expect(typeof response).toBe("number");
});
it("Get circulating supply value", async (): Promise<void> => {
const response = await contract.getCirculatingSupplyValue();
expect(typeof response).toBe("number");
});
});
@@ -17,8 +17,12 @@ describe("Get mixnode data", (): void => {
//bond information overview //bond information overview
expect(typeof mixnode.bond_information.mix_id).toBe("number"); expect(typeof mixnode.bond_information.mix_id).toBe("number");
expect(typeof mixnode.bond_information.owner).toBe("string"); expect(typeof mixnode.bond_information.owner).toBe("string");
expect(typeof mixnode.bond_information.original_pledge.amount).toBe("string"); expect(typeof mixnode.bond_information.original_pledge.amount).toBe(
expect(typeof mixnode.bond_information.original_pledge.denom).toBe("string"); "string"
);
expect(typeof mixnode.bond_information.original_pledge.denom).toBe(
"string"
);
expect(typeof mixnode.bond_information.layer).toBe("number"); expect(typeof mixnode.bond_information.layer).toBe("number");
expect(typeof mixnode.bond_information.bonding_height).toBe("number"); expect(typeof mixnode.bond_information.bonding_height).toBe("number");
expect(typeof mixnode.bond_information.is_unbonding).toBe("boolean"); expect(typeof mixnode.bond_information.is_unbonding).toBe("boolean");
@@ -31,8 +35,12 @@ describe("Get mixnode data", (): void => {
//mixnode //mixnode
expect(typeof mixnode.bond_information.mix_node.host).toBe("string"); expect(typeof mixnode.bond_information.mix_node.host).toBe("string");
expect(mixnode.bond_information.mix_node.http_api_port).toStrictEqual(8000); expect(mixnode.bond_information.mix_node.http_api_port).toStrictEqual(
expect(typeof mixnode.bond_information.mix_node.verloc_port).toBe("number"); 8000
);
expect(typeof mixnode.bond_information.mix_node.verloc_port).toBe(
"number"
);
expect(typeof mixnode.bond_information.mix_node.mix_port).toBe("number"); expect(typeof mixnode.bond_information.mix_node.mix_port).toBe("number");
expect(mixnode.bond_information.mix_node.mix_port).toStrictEqual(1789); expect(mixnode.bond_information.mix_node.mix_port).toStrictEqual(1789);
expect(mixnode.bond_information.mix_node.verloc_port).toStrictEqual(1790); expect(mixnode.bond_information.mix_node.verloc_port).toStrictEqual(1790);
@@ -40,30 +48,39 @@ describe("Get mixnode data", (): void => {
const identitykey = mixnode.bond_information.mix_node.identity_key; const identitykey = mixnode.bond_information.mix_node.identity_key;
if (typeof identitykey === "string") { if (typeof identitykey === "string") {
if (identitykey.length === 43) { if (identitykey.length === 43) {
return true return true;
} } else expect(identitykey).toHaveLength(44);
else expect(identitykey).toHaveLength(44);
} }
const sphinx = mixnode.bond_information.mix_node.sphinx_key const sphinx = mixnode.bond_information.mix_node.sphinx_key;
if (typeof sphinx === "string") { if (typeof sphinx === "string") {
if (sphinx.length === 43) { if (sphinx.length === 43) {
return true return true;
} } else expect(sphinx).toHaveLength(44);
else expect(sphinx).toHaveLength(44);
} }
//rewarding details //rewarding details
expect(typeof mixnode.rewarding_details.cost_params.profit_margin_percent).toBe("string"); expect(
expect(typeof mixnode.rewarding_details.cost_params.interval_operating_cost.denom).toBe("string"); typeof mixnode.rewarding_details.cost_params.profit_margin_percent
expect(typeof mixnode.rewarding_details.cost_params.interval_operating_cost.amount).toBe("string"); ).toBe("string");
expect(
typeof mixnode.rewarding_details.cost_params.interval_operating_cost
.denom
).toBe("string");
expect(
typeof mixnode.rewarding_details.cost_params.interval_operating_cost
.amount
).toBe("string");
expect(typeof mixnode.rewarding_details.operator).toBe("string"); expect(typeof mixnode.rewarding_details.operator).toBe("string");
expect(typeof mixnode.rewarding_details.delegates).toBe("string"); expect(typeof mixnode.rewarding_details.delegates).toBe("string");
expect(typeof mixnode.rewarding_details.total_unit_reward).toBe("string"); expect(typeof mixnode.rewarding_details.total_unit_reward).toBe("string");
expect(typeof mixnode.rewarding_details.unit_delegation).toBe("string"); expect(typeof mixnode.rewarding_details.unit_delegation).toBe("string");
expect(typeof mixnode.rewarding_details.last_rewarded_epoch).toBe("number"); expect(typeof mixnode.rewarding_details.last_rewarded_epoch).toBe(
expect(typeof mixnode.rewarding_details.unique_delegations).toBe("number"); "number"
);
expect(typeof mixnode.rewarding_details.unique_delegations).toBe(
"number"
);
}); });
}); });
@@ -79,85 +96,139 @@ describe("Get mixnode data", (): void => {
expect(typeof mixnode.family).toBe("string"); expect(typeof mixnode.family).toBe("string");
//mixnode details bond info //mixnode details bond info
expect(typeof mixnode.mixnode_details.bond_information.mix_id).toBe("number") expect(typeof mixnode.mixnode_details.bond_information.mix_id).toBe(
expect(typeof mixnode.mixnode_details.bond_information.owner).toBe("string"); "number"
expect(typeof mixnode.mixnode_details.bond_information.original_pledge.amount).toBe("string"); );
expect(typeof mixnode.mixnode_details.bond_information.original_pledge.denom).toBe("string"); expect(typeof mixnode.mixnode_details.bond_information.owner).toBe(
expect(typeof mixnode.mixnode_details.bond_information.layer).toBe("number"); "string"
expect(typeof mixnode.mixnode_details.bond_information.bonding_height).toBe("number"); );
expect(typeof mixnode.mixnode_details.bond_information.is_unbonding).toBe("boolean"); expect(
typeof mixnode.mixnode_details.bond_information.original_pledge.amount
).toBe("string");
expect(
typeof mixnode.mixnode_details.bond_information.original_pledge.denom
).toBe("string");
expect(typeof mixnode.mixnode_details.bond_information.layer).toBe(
"number"
);
expect(
typeof mixnode.mixnode_details.bond_information.bonding_height
).toBe("number");
expect(typeof mixnode.mixnode_details.bond_information.is_unbonding).toBe(
"boolean"
);
if (mixnode.mixnode_details.bond_information.proxy === null) { if (mixnode.mixnode_details.bond_information.proxy === null) {
return true; return true;
} } else {
else { expect(typeof mixnode.mixnode_details.bond_information.proxy).toBe(
expect(typeof mixnode.mixnode_details.bond_information.proxy).toBe("string"); "string"
);
} }
//mixnode //mixnode
expect(typeof mixnode.mixnode_details.bond_information.mix_node.host).toBe("string") expect(
expect(mixnode.mixnode_details.bond_information.mix_node.http_api_port).toStrictEqual(8000); typeof mixnode.mixnode_details.bond_information.mix_node.host
expect(typeof mixnode.mixnode_details.bond_information.mix_node.verloc_port).toBe("number") ).toBe("string");
expect(typeof mixnode.mixnode_details.bond_information.mix_node.mix_port).toBe("number") expect(
expect(mixnode.mixnode_details.bond_information.mix_node.mix_port).toStrictEqual(1789); mixnode.mixnode_details.bond_information.mix_node.http_api_port
expect(mixnode.mixnode_details.bond_information.mix_node.verloc_port).toStrictEqual(1790) ).toStrictEqual(8000);
expect(
typeof mixnode.mixnode_details.bond_information.mix_node.verloc_port
).toBe("number");
expect(
typeof mixnode.mixnode_details.bond_information.mix_node.mix_port
).toBe("number");
expect(
mixnode.mixnode_details.bond_information.mix_node.mix_port
).toStrictEqual(1789);
expect(
mixnode.mixnode_details.bond_information.mix_node.verloc_port
).toStrictEqual(1790);
let identitykey2 = mixnode.mixnode_details.bond_information.mix_node.identity_key const identitykey2 =
mixnode.mixnode_details.bond_information.mix_node.identity_key;
if (typeof identitykey2 === "string") { if (typeof identitykey2 === "string") {
if (identitykey2.length === 43) { if (identitykey2.length === 43) {
return true return true;
} } else expect(identitykey2).toHaveLength(44);
else expect(identitykey2).toHaveLength(44);
} }
let sphinx2 = mixnode.mixnode_details.bond_information.mix_node.sphinx_key const sphinx2 =
mixnode.mixnode_details.bond_information.mix_node.sphinx_key;
if (typeof sphinx2 === "string") { if (typeof sphinx2 === "string") {
if (sphinx2.length === 43) { if (sphinx2.length === 43) {
return true return true;
} } else expect(sphinx2).toHaveLength(44);
else expect(sphinx2).toHaveLength(44);
} }
//mixnode rewarding info //mixnode rewarding info
expect(typeof mixnode.mixnode_details.rewarding_details.cost_params.profit_margin_percent).toBe("string") expect(
expect(typeof mixnode.mixnode_details.rewarding_details.cost_params.interval_operating_cost.denom).toBe("string") typeof mixnode.mixnode_details.rewarding_details.cost_params
expect(typeof mixnode.mixnode_details.rewarding_details.cost_params.interval_operating_cost.amount).toBe("string") .profit_margin_percent
expect(typeof mixnode.mixnode_details.rewarding_details.operator).toBe("string") ).toBe("string");
expect(typeof mixnode.mixnode_details.rewarding_details.delegates).toBe("string") expect(
expect(typeof mixnode.mixnode_details.rewarding_details.total_unit_reward).toBe("string") typeof mixnode.mixnode_details.rewarding_details.cost_params
expect(typeof mixnode.mixnode_details.rewarding_details.unit_delegation).toBe("string") .interval_operating_cost.denom
expect(typeof mixnode.mixnode_details.rewarding_details.last_rewarded_epoch).toBe("number") ).toBe("string");
expect(typeof mixnode.mixnode_details.rewarding_details.unique_delegations).toBe("number") expect(
typeof mixnode.mixnode_details.rewarding_details.cost_params
.interval_operating_cost.amount
).toBe("string");
expect(typeof mixnode.mixnode_details.rewarding_details.operator).toBe(
"string"
);
expect(typeof mixnode.mixnode_details.rewarding_details.delegates).toBe(
"string"
);
expect(
typeof mixnode.mixnode_details.rewarding_details.total_unit_reward
).toBe("string");
expect(
typeof mixnode.mixnode_details.rewarding_details.unit_delegation
).toBe("string");
expect(
typeof mixnode.mixnode_details.rewarding_details.last_rewarded_epoch
).toBe("number");
expect(
typeof mixnode.mixnode_details.rewarding_details.unique_delegations
).toBe("number");
}); });
}); });
it("Get active mixnodes", async (): Promise<void> => { it("Get active mixnodes", async (): Promise<void> => {
const response = await contract.getActiveMixnodes(); const response = await contract.getActiveMixnodes();
response.forEach(function (mixnode) { response.forEach(function (mixnode) {
expect(mixnode.rewarding_details.cost_params.profit_margin_percent).toBeTruthy() expect(
expect(typeof mixnode.bond_information.layer).toBe("number") mixnode.rewarding_details.cost_params.profit_margin_percent
).toBeTruthy();
expect(typeof mixnode.bond_information.layer).toBe("number");
}); });
}); });
it("Get active mixnodes detailed", async (): Promise<void> => { it("Get active mixnodes detailed", async (): Promise<void> => {
const response = await contract.getActiveMixnodesDetailed(); const response = await contract.getActiveMixnodesDetailed();
response.forEach(function (mixnode) { response.forEach(function (mixnode) {
expect(mixnode.mixnode_details.rewarding_details.cost_params.profit_margin_percent).toBeTruthy() expect(
mixnode.mixnode_details.rewarding_details.cost_params
.profit_margin_percent
).toBeTruthy();
}); });
}); });
it("Get rewarded mixnodes", async (): Promise<void> => { it("Get rewarded mixnodes", async (): Promise<void> => {
const response = await contract.getRewardedMixnodes(); const response = await contract.getRewardedMixnodes();
response.forEach(function (mixnode) { response.forEach(function (mixnode) {
expect(mixnode.rewarding_details.last_rewarded_epoch).toBeTruthy() expect(mixnode.rewarding_details.last_rewarded_epoch).toBeTruthy();
}); });
}); });
it("Get rewarded mixnodes detailed", async (): Promise<void> => { it("Get rewarded mixnodes detailed", async (): Promise<void> => {
const response = await contract.getRewardedMixnodesDetailed(); const response = await contract.getRewardedMixnodesDetailed();
response.forEach(function (mixnode) { response.forEach(function (mixnode) {
expect(mixnode.mixnode_details.rewarding_details.last_rewarded_epoch).toBeTruthy() expect(
mixnode.mixnode_details.rewarding_details.last_rewarded_epoch
).toBeTruthy();
}); });
}); });
@@ -167,5 +238,4 @@ describe("Get mixnode data", (): void => {
expect(typeof value).toBe("number"); expect(typeof value).toBe("number");
}); });
}); });
}); });
@@ -46,5 +46,4 @@ describe("Get gateway data", (): void => {
expect(typeof response.last_hour).toBe("number"); expect(typeof response.last_hour).toBe("number");
expect(typeof response.last_day).toBe("number"); expect(typeof response.last_day).toBe("number");
}); });
}); });
@@ -40,9 +40,9 @@ describe("Get mixnode data", (): void => {
const response = await status.getMixnodeHistory(identity_key); const response = await status.getMixnodeHistory(identity_key);
response.history.forEach((x) => { response.history.forEach((x) => {
console.log(x.date); expect(typeof x.date).toBe("string");
console.log(x.uptime); expect(typeof x.uptime).toBe("number");
}) });
expect(identity_key).toStrictEqual(response.mix_id); expect(identity_key).toStrictEqual(response.mix_id);
expect(typeof response.owner).toBe("string"); expect(typeof response.owner).toBe("string");
@@ -67,7 +67,9 @@ describe("Get mixnode data", (): void => {
const identity_key = config.environmnetConfig.mix_id; const identity_key = config.environmnetConfig.mix_id;
const response = await status.getMixnodeRewardComputation(identity_key); const response = await status.getMixnodeRewardComputation(identity_key);
expect(response.reward_params.interval.sybil_resistance).toStrictEqual("0.3"); expect(response.reward_params.interval.sybil_resistance).toStrictEqual(
"0.3"
);
expect(response.reward_params.active_set_size).toStrictEqual(240); expect(response.reward_params.active_set_size).toStrictEqual(240);
expect(typeof response.reward_params.interval.reward_pool).toBe("string"); expect(typeof response.reward_params.interval.reward_pool).toBe("string");
}); });
@@ -79,30 +81,42 @@ describe("Get mixnode data", (): void => {
expect(typeof response.in_active).toBe("string"); expect(typeof response.in_active).toBe("string");
}); });
it("Get all mixnodes inclusion probability", async (): Promise<void> => { it("Get all mixnodes inclusion probabilities", async (): Promise<void> => {
const response = await status.getAllMixnodeInclusionProbability(); const response = await status.getAllMixnodeInclusionProbability();
const array = response.inclusion_probabilities;
expect(response.inclusion_probabilities).toBeTruthy(); array.forEach((x) => {
expect(typeof x.in_reserve).toBe("number");
expect(typeof x.mix_id).toBe("number");
});
expect(typeof response.elapsed.nanos).toBe("number");
}); });
it("Get all mixnodes", async (): Promise<void> => { it("Get all mixnodes", async (): Promise<void> => {
const response = await status.getDetailedMixnodes(); const response = await status.getDetailedMixnodes();
response.forEach((x) => {
expect(typeof response.stake_saturation).toBe("string"); expect(typeof x.mixnode_details.bond_information.mix_id).toBe("number");
expect(typeof x.mixnode_details.bond_information.layer).toBe("number");
expect(typeof x.stake_saturation).toBe("string");
});
}); });
it("Get all rewarded mixnodes", async (): Promise<void> => { it("Get all rewarded mixnodes", async (): Promise<void> => {
const response = await status.getDetailedRewardedMixnodes(); const response = await status.getDetailedRewardedMixnodes();
response.forEach((x) => {
expect(typeof response.mixnode_details.rewarding_details.last_rewarded_epoch).toBe("number"); expect(typeof x.mixnode_details.bond_information.mix_id).toBe("number");
expect(typeof x.mixnode_details.bond_information.layer).toBe("number");
expect(typeof x.stake_saturation).toBe("string");
});
}); });
it("Get all active mixnodes", async (): Promise<void> => { it("Get all active mixnodes", async (): Promise<void> => {
const response = await status.getDetailedActiveMixnodes(); const response = await status.getDetailedActiveMixnodes();
response.forEach((x) => {
expect(typeof response.mixnode_details.bond_information.layer).toBe("number"); expect(typeof x.mixnode_details.bond_information.mix_id).toBe("number");
expect(typeof x.mixnode_details.bond_information.layer).toBe("number");
expect(typeof x.stake_saturation).toBe("string");
});
}); });
}); });
describe("Compute mixnode reward estimation", (): void => { describe("Compute mixnode reward estimation", (): void => {
@@ -110,11 +124,11 @@ describe("Compute mixnode reward estimation", (): void => {
status = new Status(); status = new Status();
config = ConfigHandler.getInstance(); config = ConfigHandler.getInstance();
}); });
it("with correct data", async (): Promise<void> => { // TODO Fix this test
it.skip("with correct data", async (): Promise<void> => {
const response = await status.sendMixnodeRewardEstimatedComputation(8); const response = await status.sendMixnodeRewardEstimatedComputation(8);
const body = const body = expect(typeof response.estimation.total_node_reward).toBe(
"string"
expect(typeof response.estimation.total_node_reward).toBe("string"); );
}); });
}); });
@@ -12,4 +12,18 @@ export default class ContractCache extends APIClient {
}); });
return response.data; return response.data;
} }
public async getTotalSupplyValue(): Promise<number> {
const response = await this.restClient.sendGet({
route: `circulating-supply/total-supply-value`,
});
return response.data;
}
public async getCirculatingSupplyValue(): Promise<number> {
const response = await this.restClient.sendGet({
route: `circulating-supply/circulating-supply-value`,
});
return response.data;
}
} }
+4 -2
View File
@@ -3,6 +3,8 @@ import {
AllGateways, AllGateways,
AllMixnodes, AllMixnodes,
EpochRewardParams, EpochRewardParams,
BlacklistedGateways,
BlacklistedMixnodes,
CurrentEpoch, CurrentEpoch,
} from "../types/ContractCacheTypes"; } from "../types/ContractCacheTypes";
import { APIClient } from "./abstracts/APIClient"; import { APIClient } from "./abstracts/APIClient";
@@ -62,14 +64,14 @@ export default class ContractCache extends APIClient {
return response.data; return response.data;
} }
public async getBlacklistedMixnodes(): Promise<[]> { public async getBlacklistedMixnodes(): Promise<BlacklistedMixnodes[]> {
const response = await this.restClient.sendGet({ const response = await this.restClient.sendGet({
route: `mixnodes/blacklisted`, route: `mixnodes/blacklisted`,
}); });
return response.data; return response.data;
} }
public async getBlacklistedGateways(): Promise<[]> { public async getBlacklistedGateways(): Promise<BlacklistedGateways[]> {
const response = await this.restClient.sendGet({ const response = await this.restClient.sendGet({
route: `gateways/blacklisted`, route: `gateways/blacklisted`,
}); });
+4 -4
View File
@@ -147,13 +147,13 @@ export default class Status extends APIClient {
public async getAllMixnodeInclusionProbability(): Promise<InclusionProbabilities> { public async getAllMixnodeInclusionProbability(): Promise<InclusionProbabilities> {
const response = await this.restClient.sendGet({ const response = await this.restClient.sendGet({
route: `/mixnodes/inclusion-probability`, route: `/mixnodes/inclusion_probability`,
}); });
return response.data; return response.data;
} }
public async getDetailedMixnodes(): Promise<DetailedMixnodes> { public async getDetailedMixnodes(): Promise<DetailedMixnodes[]> {
const response = await this.restClient.sendGet({ const response = await this.restClient.sendGet({
route: `/mixnodes/detailed`, route: `/mixnodes/detailed`,
}); });
@@ -161,7 +161,7 @@ export default class Status extends APIClient {
return response.data; return response.data;
} }
public async getDetailedRewardedMixnodes(): Promise<DetailedMixnodes> { public async getDetailedRewardedMixnodes(): Promise<DetailedMixnodes[]> {
const response = await this.restClient.sendGet({ const response = await this.restClient.sendGet({
route: `/mixnodes/rewarded/detailed`, route: `/mixnodes/rewarded/detailed`,
}); });
@@ -169,7 +169,7 @@ export default class Status extends APIClient {
return response.data; return response.data;
} }
public async getDetailedActiveMixnodes(): Promise<DetailedMixnodes> { public async getDetailedActiveMixnodes(): Promise<DetailedMixnodes[]> {
const response = await this.restClient.sendGet({ const response = await this.restClient.sendGet({
route: `/mixnodes/active/detailed`, route: `/mixnodes/active/detailed`,
}); });
@@ -1,11 +1,11 @@
export type Detailed = { export type Detailed = {
initial_supply: InitialSupply; total_supply: TotalSupply;
mixmining_reserve: MixminingReserve; mixmining_reserve: MixminingReserve;
vesting_tokens: VestingTokens; vesting_tokens: VestingTokens;
circulating_supply: CirculatingSupply; circulating_supply: CirculatingSupply;
}; };
export type InitialSupply = { export type TotalSupply = {
demon: "unym"; demon: "unym";
amount: string; amount: string;
}; };
+32 -28
View File
@@ -1,9 +1,9 @@
export interface AllMixnodes { export type AllMixnodes = {
bond_information: BondInformation; bond_information: BondInformation;
rewarding_details: RewardingDetails; rewarding_details: RewardingDetails;
} };
export interface BondInformation { export type BondInformation = {
mix_id: number; mix_id: number;
owner: string; owner: string;
original_pledge: OriginalPledge; original_pledge: OriginalPledge;
@@ -12,9 +12,9 @@ export interface BondInformation {
proxy: string; proxy: string;
bonding_height: number; bonding_height: number;
is_unbonding: boolean; is_unbonding: boolean;
} };
export interface RewardingDetails { export type RewardingDetails = {
cost_params: CostParams; cost_params: CostParams;
operator: string; operator: string;
delegates: string; delegates: string;
@@ -22,29 +22,29 @@ export interface RewardingDetails {
unit_delegation: string; unit_delegation: string;
last_rewarded_epoch: number; last_rewarded_epoch: number;
unique_delegations: number; unique_delegations: number;
} };
export interface CostParams { export type CostParams = {
profit_margin_percent: string; profit_margin_percent: string;
interval_operating_cost: IntervalOperatingCost; interval_operating_cost: IntervalOperatingCost;
} };
export interface IntervalOperatingCost { export type IntervalOperatingCost = {
denom: string; denom: string;
amount: string; amount: string;
} };
export interface OriginalPledge { export type OriginalPledge = {
denom: string; denom: string;
amount: string; amount: string;
} };
export interface TotalDelegation { export type TotalDelegation = {
denom: string; denom: string;
amount: string; amount: string;
} };
export interface Mixnode { export type Mixnode = {
host: string; host: string;
mix_port: number; mix_port: number;
verloc_port: number; verloc_port: number;
@@ -52,9 +52,9 @@ export interface Mixnode {
sphinx_key: string; sphinx_key: string;
identity_key: string; identity_key: string;
version: string; version: string;
} };
export interface MixnodeBond { export type MixnodeBond = {
pledge_amount: OriginalPledge; pledge_amount: OriginalPledge;
total_delegation: TotalDelegation; total_delegation: TotalDelegation;
owner: string; owner: string;
@@ -63,9 +63,9 @@ export interface MixnodeBond {
mix_node: Mixnode; mix_node: Mixnode;
proxy: string; proxy: string;
accumulated_rewards: string; accumulated_rewards: string;
} };
export interface MixnodesDetailed { export type MixnodesDetailed = {
mixnode_details: AllMixnodes; mixnode_details: AllMixnodes;
stake_saturation: string; stake_saturation: string;
uncapped_stake_saturation: string; uncapped_stake_saturation: string;
@@ -73,7 +73,11 @@ export interface MixnodesDetailed {
estimated_operator_apy: string; estimated_operator_apy: string;
estimated_delegators_apy: string; estimated_delegators_apy: string;
family: string; family: string;
} };
export type BlacklistedMixnodes = {};
export type BlacklistedGateways = {};
export interface Gateway { export interface Gateway {
host: string; host: string;
@@ -93,13 +97,13 @@ export interface AllGateways {
proxy: string; proxy: string;
} }
export interface EpochRewardParams { export type EpochRewardParams = {
interval: Interval; interval: Interval;
rewarded_set_size: number; rewarded_set_size: number;
active_set_size: number; active_set_size: number;
} };
export interface Interval { export type Interval = {
reward_pool: string; reward_pool: string;
staking_supply: string; staking_supply: string;
staking_supply_scale_factor: string; staking_supply_scale_factor: string;
@@ -108,18 +112,18 @@ export interface Interval {
sybil_resistance: string; sybil_resistance: string;
active_set_work_factor: string; active_set_work_factor: string;
interval_pool_emission: string; interval_pool_emission: string;
} };
export interface CurrentEpoch { export type CurrentEpoch = {
id: number; id: number;
epochs_in_interval: number; epochs_in_interval: number;
current_epoch_start: string; current_epoch_start: string;
current_epoch_id: number; current_epoch_id: number;
epoch_length: EpochLength; epoch_length: EpochLength;
total_elapsed_epochs: number; total_elapsed_epochs: number;
} };
export interface EpochLength { export type EpochLength = {
secs: number; secs: number;
nanos: number; nanos: number;
} };
+1 -1
View File
@@ -20,6 +20,6 @@
"typeRoots": ["node_modules/@types"], "typeRoots": ["node_modules/@types"],
"alwaysStrict": true "alwaysStrict": true
}, },
"include": ["src/**/*", "tests/functional_test/*/*"], "include": ["src/**/*", "functional_test/*/*"],
"exclude": ["unit_test/**/*"] "exclude": ["unit_test/**/*"]
} }
+23
View File
@@ -0,0 +1,23 @@
[package]
name = "nym-api-requests"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bs58 = "0.4.0"
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support" }
cosmwasm-std = { version = "1.0.0", default-features = false }
getset = "0.1.1"
schemars = { version = "0.8", features = ["preserve_order"] }
serde = { version = "1.0", features = ["derive"] }
ts-rs = { version = "6.1.2", optional = true }
coconut-interface = { path = "../../common/coconut-interface", optional = true }
mixnet-contract-common = { path= "../../common/cosmwasm-smart-contracts/mixnet-contract" }
[features]
default = []
coconut = ["coconut-interface"]
generate-ts = ["ts-rs"]
@@ -0,0 +1,158 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmrs::AccountId;
use getset::{CopyGetters, Getters};
use serde::{Deserialize, Serialize};
use coconut_interface::{
error::CoconutInterfaceError, Attribute, Base58, BlindSignRequest, Credential, VerificationKey,
};
#[derive(Serialize, Deserialize, Getters, CopyGetters)]
pub struct VerifyCredentialBody {
#[getset(get = "pub")]
credential: Credential,
#[getset(get = "pub")]
proposal_id: u64,
#[getset(get = "pub")]
gateway_cosmos_addr: AccountId,
}
impl VerifyCredentialBody {
pub fn new(
credential: Credential,
proposal_id: u64,
gateway_cosmos_addr: AccountId,
) -> VerifyCredentialBody {
VerifyCredentialBody {
credential,
proposal_id,
gateway_cosmos_addr,
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct VerifyCredentialResponse {
pub verification_result: bool,
}
impl VerifyCredentialResponse {
pub fn new(verification_result: bool) -> Self {
VerifyCredentialResponse {
verification_result,
}
}
}
// All strings are base58 encoded representations of structs
#[derive(Clone, Serialize, Deserialize, Debug, Getters, CopyGetters)]
pub struct BlindSignRequestBody {
#[getset(get = "pub")]
blind_sign_request: BlindSignRequest,
#[getset(get = "pub")]
tx_hash: String,
#[getset(get = "pub")]
signature: String,
public_attributes: Vec<String>,
#[getset(get = "pub")]
public_attributes_plain: Vec<String>,
#[getset(get = "pub")]
total_params: u32,
}
impl BlindSignRequestBody {
pub fn new(
blind_sign_request: &BlindSignRequest,
tx_hash: String,
signature: String,
public_attributes: &[Attribute],
public_attributes_plain: Vec<String>,
total_params: u32,
) -> BlindSignRequestBody {
BlindSignRequestBody {
blind_sign_request: blind_sign_request.clone(),
tx_hash,
signature,
public_attributes: public_attributes
.iter()
.map(|attr| attr.to_bs58())
.collect(),
public_attributes_plain,
total_params,
}
}
pub fn public_attributes(&self) -> Vec<Attribute> {
self.public_attributes
.iter()
.map(|x| Attribute::try_from_bs58(x).unwrap())
.collect()
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct BlindedSignatureResponse {
pub remote_key: [u8; 32],
pub encrypted_signature: Vec<u8>,
}
impl BlindedSignatureResponse {
pub fn new(encrypted_signature: Vec<u8>, remote_key: [u8; 32]) -> BlindedSignatureResponse {
BlindedSignatureResponse {
encrypted_signature,
remote_key,
}
}
pub fn to_base58_string(&self) -> String {
bs58::encode(&self.to_bytes()).into_string()
}
pub fn from_base58_string<I: AsRef<[u8]>>(val: I) -> Result<Self, CoconutInterfaceError> {
let bytes = bs58::decode(val).into_vec()?;
Self::from_bytes(&bytes)
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = self.remote_key.to_vec();
bytes.extend_from_slice(&self.encrypted_signature);
bytes
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, CoconutInterfaceError> {
if bytes.len() < 32 {
return Err(CoconutInterfaceError::InvalidByteLength(bytes.len(), 32));
}
let mut remote_key = [0u8; 32];
remote_key.copy_from_slice(&bytes[..32]);
let encrypted_signature = bytes[32..].to_vec();
Ok(BlindedSignatureResponse {
remote_key,
encrypted_signature,
})
}
}
#[derive(Serialize, Deserialize)]
pub struct VerificationKeyResponse {
pub key: VerificationKey,
}
impl VerificationKeyResponse {
pub fn new(key: VerificationKey) -> VerificationKeyResponse {
VerificationKeyResponse { key }
}
}
#[derive(Serialize, Deserialize)]
pub struct CosmosAddressResponse {
pub addr: AccountId,
}
impl CosmosAddressResponse {
pub fn new(addr: AccountId) -> CosmosAddressResponse {
CosmosAddressResponse { addr }
}
}
+36
View File
@@ -0,0 +1,36 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[cfg(feature = "coconut")]
pub mod coconut;
pub mod models;
pub trait Deprecatable {
fn deprecate(self) -> Deprecated<Self>
where
Self: Sized,
{
self.into()
}
}
impl<T> Deprecatable for T {}
#[derive(Serialize, Deserialize, JsonSchema)]
pub struct Deprecated<T> {
pub deprecated: bool,
#[serde(flatten)]
pub response: T,
}
impl<T> From<T> for Deprecated<T> {
fn from(response: T) -> Self {
Deprecated {
deprecated: true,
response,
}
}
}
@@ -0,0 +1,284 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::{Coin, Decimal};
use mixnet_contract_common::families::FamilyHead;
use mixnet_contract_common::mixnode::MixNodeDetails;
use mixnet_contract_common::reward_params::{Performance, RewardingParams};
use mixnet_contract_common::rewarding::RewardEstimate;
use mixnet_contract_common::{
IdentityKey, Interval, MixId, MixNode, Percent, RewardedSetNodeStatus,
};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::{fmt, time::Duration};
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
pub struct RequestError {
message: String,
}
impl RequestError {
pub fn new<S: Into<String>>(msg: S) -> Self {
RequestError {
message: msg.into(),
}
}
pub fn message(&self) -> &str {
&self.message
}
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr(
feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/MixnodeStatus.ts")
)]
#[serde(rename_all = "snake_case")]
pub enum MixnodeStatus {
Active, // in both the active set and the rewarded set
Standby, // only in the rewarded set
Inactive, // in neither the rewarded set nor the active set, but is bonded
NotFound, // doesn't even exist in the bonded set
}
impl From<MixnodeStatus> for Option<RewardedSetNodeStatus> {
fn from(status: MixnodeStatus) -> Self {
match status {
MixnodeStatus::Active => Some(RewardedSetNodeStatus::Active),
MixnodeStatus::Standby => Some(RewardedSetNodeStatus::Standby),
MixnodeStatus::Inactive => None,
MixnodeStatus::NotFound => None,
}
}
}
impl MixnodeStatus {
pub fn is_active(&self) -> bool {
*self == MixnodeStatus::Active
}
}
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr(
feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/MixnodeCoreStatusResponse.ts")
)]
pub struct MixnodeCoreStatusResponse {
pub mix_id: MixId,
pub count: i32,
}
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr(
feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/GatewayCoreStatusResponse.ts")
)]
pub struct GatewayCoreStatusResponse {
pub identity: String,
pub count: i32,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema)]
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr(
feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/MixnodeStatusResponse.ts")
)]
pub struct MixnodeStatusResponse {
pub status: MixnodeStatus,
}
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
pub struct MixNodeBondAnnotated {
pub mixnode_details: MixNodeDetails,
pub stake_saturation: StakeSaturation,
pub uncapped_stake_saturation: StakeSaturation,
pub performance: Performance,
pub estimated_operator_apy: Decimal,
pub estimated_delegators_apy: Decimal,
pub family: Option<FamilyHead>,
}
impl MixNodeBondAnnotated {
pub fn mix_node(&self) -> &MixNode {
&self.mixnode_details.bond_information.mix_node
}
pub fn mix_id(&self) -> MixId {
self.mixnode_details.mix_id()
}
}
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct ComputeRewardEstParam {
pub performance: Option<Performance>,
pub active_in_rewarded_set: Option<bool>,
pub pledge_amount: Option<u64>,
pub total_delegation: Option<u64>,
pub interval_operating_cost: Option<Coin>,
pub profit_margin_percent: Option<Percent>,
}
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr(
feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/RewardEstimationResponse.ts")
)]
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema)]
pub struct RewardEstimationResponse {
pub estimation: RewardEstimate,
pub reward_params: RewardingParams,
pub epoch: Interval,
#[cfg_attr(feature = "generate-ts", ts(type = "number"))]
pub as_at: i64,
}
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
pub struct UptimeResponse {
pub mix_id: MixId,
pub avg_uptime: u8,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema)]
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr(
feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/StakeSaturationResponse.ts")
)]
pub struct StakeSaturationResponse {
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
pub saturation: StakeSaturation,
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
pub uncapped_saturation: StakeSaturation,
pub as_at: i64,
}
pub type StakeSaturation = Decimal;
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr(
feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/SelectionChance.ts")
)]
pub enum SelectionChance {
High,
Good,
Low,
}
impl From<f64> for SelectionChance {
fn from(p: f64) -> SelectionChance {
match p {
p if p >= 0.7 => SelectionChance::High,
p if p >= 0.3 => SelectionChance::Good,
_ => SelectionChance::Low,
}
}
}
impl From<Decimal> for SelectionChance {
fn from(p: Decimal) -> Self {
match p {
p if p >= Decimal::from_ratio(70u32, 100u32) => SelectionChance::High,
p if p >= Decimal::from_ratio(30u32, 100u32) => SelectionChance::Good,
_ => SelectionChance::Low,
}
}
}
impl fmt::Display for SelectionChance {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SelectionChance::High => write!(f, "High"),
SelectionChance::Good => write!(f, "Good"),
SelectionChance::Low => write!(f, "Low"),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr(
feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/InclusionProbabilityResponse.ts")
)]
pub struct InclusionProbabilityResponse {
pub in_active: SelectionChance,
pub in_reserve: SelectionChance,
}
impl fmt::Display for InclusionProbabilityResponse {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"in_active: {}, in_reserve: {}",
self.in_active, self.in_reserve
)
}
}
#[derive(Clone, Serialize, schemars::JsonSchema)]
pub struct AllInclusionProbabilitiesResponse {
pub inclusion_probabilities: Vec<InclusionProbability>,
pub samples: u64,
pub elapsed: Duration,
pub delta_max: f64,
pub delta_l2: f64,
pub as_at: i64,
}
#[derive(Clone, Serialize, schemars::JsonSchema)]
pub struct InclusionProbability {
pub mix_id: MixId,
pub in_active: f64,
pub in_reserve: f64,
}
type Uptime = u8;
#[derive(Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct MixnodeStatusReportResponse {
pub mix_id: MixId,
pub identity: IdentityKey,
pub owner: String,
pub most_recent: Uptime,
pub last_hour: Uptime,
pub last_day: Uptime,
}
#[derive(Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct GatewayStatusReportResponse {
pub identity: String,
pub owner: String,
pub most_recent: Uptime,
pub last_hour: Uptime,
pub last_day: Uptime,
}
#[derive(Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct HistoricalUptimeResponse {
pub date: String,
pub uptime: Uptime,
}
#[derive(Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct MixnodeUptimeHistoryResponse {
pub mix_id: MixId,
pub identity: String,
pub owner: String,
pub history: Vec<HistoricalUptimeResponse>,
}
#[derive(Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct GatewayUptimeHistoryResponse {
pub identity: String,
pub owner: String,
pub history: Vec<HistoricalUptimeResponse>,
}
@@ -1,11 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Nym Connect</title>
</head>
<body style="background: rgb(29, 33, 37);">
<div id="root-growth"></div>
</body>
</html>
-11
View File
@@ -1,11 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Nym Wallet Logs</title>
</head>
<body>
<div id="root-log"></div>
</body>
</html>
+8 -2
View File
@@ -41,8 +41,8 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
serde_repr = "0.1" serde_repr = "0.1"
tap = "1.0.1" tap = "1.0.1"
tauri = { git = "https://github.com/tauri-apps/tauri", branch = "next", features = ["clipboard-write-text", "native-tls-vendored", "notification-all", "shell-open", "system-tray", "window-close", "window-minimize", "window-start-dragging"] } # TODO swithing to `rfd101` temporarily, untill https://github.com/tauri-apps/tauri/pull/6174 is merged
# tauri = { version = "2.0.0-alpha.0", features = ["clipboard-write-text", "native-tls-vendored", "notification-all", "shell-open", "system-tray", "window-close", "window-minimize", "window-start-dragging"] } tauri = { git = "https://github.com/tauri-apps/tauri", branch = "rfd101", features = ["clipboard-write-text", "native-tls-vendored", "notification-all", "shell-open", "system-tray", "window-close", "window-minimize", "window-start-dragging"] }
tendermint-rpc = "0.23.0" tendermint-rpc = "0.23.0"
thiserror = "1.0" thiserror = "1.0"
tokio = { version = "1.24.1", features = ["sync", "time"] } tokio = { version = "1.24.1", features = ["sync", "time"] }
@@ -64,3 +64,9 @@ tempfile = "3.3.0"
[features] [features]
default = ["custom-protocol"] default = ["custom-protocol"]
custom-protocol = ["tauri/custom-protocol"] custom-protocol = ["tauri/custom-protocol"]
# [profile.dev]
# strip = true
# opt-level = "s"
# lto = true
@@ -1,111 +1,112 @@
plugins { plugins {
id("com.android.application") id("com.android.application")
id("org.jetbrains.kotlin.android") id("org.jetbrains.kotlin.android")
id("rustPlugin") id("rustPlugin")
} }
android { android {
compileSdk = 33 compileSdk = 33
defaultConfig { defaultConfig {
manifestPlaceholders["usesCleartextTraffic"] = "false" manifestPlaceholders["usesCleartextTraffic"] = "false"
applicationId = "net.nymtech.nym_connect_android" applicationId = "net.nymtech.nym_connect_android"
minSdk = 24 minSdk = 24
targetSdk = 33 targetSdk = 33
versionCode = 1 versionCode = 1
versionName = "1.0" versionName = "1.0"
}
sourceSets.getByName("main") {
// Vulkan validation layers
val ndkHome = System.getenv("NDK_HOME")
jniLibs.srcDir("${ndkHome}/sources/third_party/vulkan/src/build-android/jniLibs")
}
buildTypes {
getByName("debug") {
manifestPlaceholders["usesCleartextTraffic"] = "true"
isDebuggable = true
isJniDebuggable = true
isMinifyEnabled = false
packagingOptions {
jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so")
jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so")
jniLibs.keepDebugSymbols.add("*/x86/*.so")
jniLibs.keepDebugSymbols.add("*/x86_64/*.so")
}
} }
sourceSets.getByName("main") { getByName("release") {
// Vulkan validation layers isMinifyEnabled = false
val ndkHome = System.getenv("NDK_HOME") // proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
jniLibs.srcDir("${ndkHome}/sources/third_party/vulkan/src/build-android/jniLibs")
} }
buildTypes { }
getByName("debug") { flavorDimensions.add("abi")
manifestPlaceholders["usesCleartextTraffic"] = "true" productFlavors {
isDebuggable = true create("universal") {
isJniDebuggable = true val abiList = findProperty("abiList") as? String
isMinifyEnabled = false
packagingOptions {
jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so")
jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so") dimension = "abi"
ndk {
jniLibs.keepDebugSymbols.add("*/x86/*.so") abiFilters += abiList?.split(",")?.map { it.trim() } ?: listOf(
"arm64-v8a", "armeabi-v7a", "x86", "x86_64",
jniLibs.keepDebugSymbols.add("*/x86_64/*.so") )
} }
}
getByName("release") {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
}
} }
flavorDimensions.add("abi") create("arm64") {
productFlavors { dimension = "abi"
create("universal") { ndk {
val abiList = findProperty("abiList") as? String abiFilters += listOf("arm64-v8a")
}
dimension = "abi"
ndk {
abiFilters += abiList?.split(",")?.map { it.trim() } ?: listOf( "arm64-v8a", "armeabi-v7a", "x86", "x86_64",
)
}
}
create("arm64") {
dimension = "abi"
ndk {
abiFilters += listOf("arm64-v8a")
}
}
create("arm") {
dimension = "abi"
ndk {
abiFilters += listOf("armeabi-v7a")
}
}
create("x86") {
dimension = "abi"
ndk {
abiFilters += listOf("x86")
}
}
create("x86_64") {
dimension = "abi"
ndk {
abiFilters += listOf("x86_64")
}
}
} }
assetPacks += mutableSetOf() create("arm") {
namespace = "net.nymtech.nym_connect_android" dimension = "abi"
ndk {
abiFilters += listOf("armeabi-v7a")
}
}
create("x86") {
dimension = "abi"
ndk {
abiFilters += listOf("x86")
}
}
create("x86_64") {
dimension = "abi"
ndk {
abiFilters += listOf("x86_64")
}
}
}
assetPacks += mutableSetOf()
namespace = "net.nymtech.nym_connect_android"
} }
rust { rust {
rootDirRel = "../../../../" rootDirRel = "../../../../"
targets = listOf("aarch64", "armv7", "i686", "x86_64") targets = listOf("aarch64", "armv7", "i686", "x86_64")
arches = listOf("arm64", "arm", "x86", "x86_64") arches = listOf("arm64", "arm", "x86", "x86_64")
} }
dependencies { dependencies {
implementation("androidx.webkit:webkit:1.5.0") implementation("androidx.webkit:webkit:1.5.0")
implementation("androidx.appcompat:appcompat:1.5.1") implementation("androidx.appcompat:appcompat:1.5.1")
implementation("com.google.android.material:material:1.7.0") implementation("com.google.android.material:material:1.7.0")
testImplementation("junit:junit:4.13.2") testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.4") androidTestImplementation("androidx.test.ext:junit:1.1.4")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
} }
afterEvaluate { afterEvaluate {
android.applicationVariants.all { android.applicationVariants.all {
tasks["mergeUniversalReleaseJniLibFolders"].dependsOn(tasks["rustBuildRelease"]) tasks["mergeUniversalReleaseJniLibFolders"].dependsOn(tasks["rustBuildRelease"])
tasks["mergeUniversalDebugJniLibFolders"].dependsOn(tasks["rustBuildDebug"]) tasks["mergeUniversalDebugJniLibFolders"].dependsOn(tasks["rustBuildDebug"])
productFlavors.filter{ it.name != "universal" }.forEach { _ -> productFlavors.filter { it.name != "universal" }.forEach { _ ->
val archAndBuildType = name.capitalize() val archAndBuildType = name.capitalize()
tasks["merge${archAndBuildType}JniLibFolders"].dependsOn(tasks["rustBuild${archAndBuildType}"]) tasks["merge${archAndBuildType}JniLibFolders"].dependsOn(tasks["rustBuild${archAndBuildType}"])
}
} }
}
} }
@@ -0,0 +1 @@
/home/pierre/Documents/nym/nym/nym-connect-android/src-tauri/target/aarch64-linux-android/debug/libnym_connect_android.so
@@ -0,0 +1 @@
/home/pierre/Documents/nym/nym/nym-connect-android/src-tauri/target/armv7-linux-androideabi/debug/libnym_connect_android.so
@@ -0,0 +1 @@
/home/pierre/Documents/nym/nym/nym-connect-android/src-tauri/target/i686-linux-android/debug/libnym_connect_android.so
@@ -2,12 +2,12 @@
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="Theme.nym_connect_android" parent="Theme.MaterialComponents.DayNight.DarkActionBar"> <style name="Theme.nym_connect_android" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. --> <!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item> <item name="colorPrimary">@color/grey_800</item>
<item name="colorPrimaryVariant">@color/purple_700</item> <item name="colorPrimaryVariant">@color/grey_900</item>
<item name="colorOnPrimary">@color/black</item> <item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. --> <!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item> <item name="colorSecondary">@color/green_500</item>
<item name="colorSecondaryVariant">@color/teal_200</item> <item name="colorSecondaryVariant">@color/green_900</item>
<item name="colorOnSecondary">@color/black</item> <item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. --> <!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item> <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
@@ -1,10 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="purple_200">#FFBB86FC</color> <color name="grey_900">#212121</color>
<color name="purple_500">#FF6200EE</color> <color name="grey_800">#424242</color>
<color name="purple_700">#FF3700B3</color> <color name="green_500">#4caf50</color>
<color name="teal_200">#FF03DAC5</color> <color name="green_900">#1b5e20</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color> <color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color> <color name="white">#FFFFFFFF</color>
</resources> </resources>
@@ -1,3 +1,3 @@
<resources> <resources>
<string name="app_name">nym-connect-android</string> <string name="app_name">Nym Connect</string>
</resources> </resources>
@@ -2,12 +2,12 @@
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="Theme.nym_connect_android" parent="Theme.MaterialComponents.DayNight.DarkActionBar"> <style name="Theme.nym_connect_android" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. --> <!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item> <item name="colorPrimary">@color/grey_800</item>
<item name="colorPrimaryVariant">@color/purple_700</item> <item name="colorPrimaryVariant">@color/grey_900</item>
<item name="colorOnPrimary">@color/white</item> <item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. --> <!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item> <item name="colorSecondary">@color/green_500</item>
<item name="colorSecondaryVariant">@color/teal_700</item> <item name="colorSecondaryVariant">@color/green_900</item>
<item name="colorOnSecondary">@color/black</item> <item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. --> <!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item> <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
@@ -40,11 +40,6 @@ pub enum BackendError {
#[from] #[from]
source: ClientCoreError, source: ClientCoreError,
}, },
#[error("{source}")]
ApiClientError {
#[from]
source: crate::operations::growth::api_client::ApiClientError,
},
#[error("could not send disconnect signal to the SOCKS5 client")] #[error("could not send disconnect signal to the SOCKS5 client")]
CoundNotSendDisconnectSignal, CoundNotSendDisconnectSignal,
@@ -1,270 +0,0 @@
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use thiserror::Error;
#[allow(unused)]
#[derive(Error, Debug)]
pub enum ApiClientError {
#[error("{source}")]
Reqwest {
#[from]
source: reqwest::Error,
},
#[error("{source}")]
SerdeJson {
#[from]
source: serde_json::Error,
},
#[error("{0}")]
Status(String),
}
const API_BASE_URL: &str = "https://growth-api.nymtech.net";
// For development mode, switch to this
// const API_BASE_URL: &str = "http://localhost:8000";
#[derive(Debug, Clone)]
pub struct GrowthApiClient {
base_url: String,
}
impl GrowthApiClient {
pub fn new(resource_base: &str) -> Self {
let base_url = std::env::var("API_BASE_URL").unwrap_or_else(|_| API_BASE_URL.to_string());
GrowthApiClient {
base_url: format!("{base_url}{resource_base}"),
}
}
pub fn registrations() -> Registrations {
Registrations::new(GrowthApiClient::new("/v1/tne"))
}
pub fn daily_draws() -> DailyDraws {
DailyDraws::new(GrowthApiClient::new("/v1/tne/daily_draw"))
}
pub(crate) async fn get<T: DeserializeOwned>(&self, url: &str) -> Result<T, ApiClientError> {
log::info!(">>> GET {}", url);
let proxy = reqwest::Proxy::all("socks5h://127.0.0.1:1080")?;
let client = reqwest::Client::builder()
.proxy(proxy)
.timeout(std::time::Duration::from_secs(10))
.build()?;
match client.get(format!("{}{}", self.base_url, url)).send().await {
Ok(res) => {
if res.status().is_client_error() || res.status().is_server_error() {
log::error!("<<< {}", res.status());
return Err(ApiClientError::Status(res.status().to_string()));
}
match res.text().await {
Ok(response_body) => {
log::info!("<<< {}", response_body);
match serde_json::from_str(&response_body) {
Ok(res) => Ok(res),
Err(e) => {
log::error!("<<< JSON parsing error: {}", e);
Err(e.into())
}
}
}
Err(e) => {
log::error!("<<< Request error: {}", e);
Err(e.into())
}
}
}
Err(e) => {
log::error!("<<< Response parsing error: {}", e);
Err(e.into())
}
}
}
// TODO: use the method in `operations::http` instead
pub(crate) async fn post<REQ: Serialize + ?Sized, RESP: DeserializeOwned>(
&self,
url: &str,
body: &REQ,
) -> Result<RESP, ApiClientError> {
log::info!(">>> POST {}", url);
let proxy = reqwest::Proxy::all("socks5h://127.0.0.1:1080")?;
let client = reqwest::Client::builder()
.proxy(proxy)
.timeout(std::time::Duration::from_secs(10))
.build()?;
match client
.post(format!("{}{}", self.base_url, url))
.json(body)
.send()
.await
{
Ok(res) => {
if res.status().is_client_error() || res.status().is_server_error() {
log::error!("<<< {}", res.status());
return Err(ApiClientError::Status(res.status().to_string()));
}
match res.text().await {
Ok(response_body) => {
log::info!("<<< {}", response_body);
match serde_json::from_str(&response_body) {
Ok(res) => Ok(res),
Err(e) => {
log::error!("<<< JSON parsing error: {}", e);
Err(e.into())
}
}
}
Err(e) => {
log::error!("<<< Request error: {}", e);
Err(e.into())
}
}
}
Err(e) => {
log::error!("<<< Response parsing error: {}", e);
Err(e.into())
}
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ClientIdPartial {
pub client_id: String,
pub client_id_signature: String,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Registration {
pub id: String,
pub client_id: String,
pub timestamp: String,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Ping {
pub client_id: String,
pub timestamp: String,
}
pub struct Registrations {
client: GrowthApiClient,
}
impl Registrations {
pub fn new(client: GrowthApiClient) -> Self {
Registrations { client }
}
pub async fn register(
&self,
registration: &ClientIdPartial,
) -> Result<Registration, ApiClientError> {
self.client.post("/register", &registration).await
}
#[allow(dead_code)]
pub async fn unregister(&self, registration: &ClientIdPartial) -> Result<(), ApiClientError> {
self.client.post("/unregister", &registration).await
}
#[allow(dead_code)]
pub async fn status(&self, registration: &ClientIdPartial) -> Result<(), ApiClientError> {
self.client.post("/status", &registration).await
}
pub async fn ping(&self, registration: &ClientIdPartial) -> Result<(), ApiClientError> {
self.client.post("/ping", &registration).await
}
#[allow(dead_code)]
pub async fn health(&self) -> Result<(), ApiClientError> {
self.client.get("/health").await
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct DrawEntryPartial {
pub draw_id: String,
pub client_id: String,
pub client_id_signature: String,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct DrawEntry {
pub id: String,
pub draw_id: String,
pub timestamp: String,
pub status: Option<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct DrawWithWordOfTheDay {
pub id: String,
pub start_utc: String,
pub end_utc: String,
pub word_of_the_day: Option<String>,
pub last_modified: String,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ClaimPartial {
pub draw_id: String,
pub registration_id: String,
pub client_id: String,
pub client_id_signature: String,
pub wallet_address: String,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Winner {
pub id: String,
pub client_id: String,
pub draw_id: String,
pub timestamp: String,
pub winner_reg_id: String,
pub winner_wallet_address: Option<String>,
pub winner_claim_timestamp: Option<String>,
}
pub struct DailyDraws {
client: GrowthApiClient,
}
impl DailyDraws {
pub fn new(client: GrowthApiClient) -> Self {
DailyDraws { client }
}
pub async fn current(&self) -> Result<DrawWithWordOfTheDay, ApiClientError> {
self.client.get("/current").await
}
pub async fn next(&self) -> Result<DrawWithWordOfTheDay, ApiClientError> {
self.client.get("/next").await
}
#[allow(dead_code)]
pub async fn status(&self, draw_id: &str) -> Result<DrawWithWordOfTheDay, ApiClientError> {
self.client.get(format!("/status/{draw_id}").as_str()).await
}
pub async fn enter(&self, entry: &DrawEntryPartial) -> Result<DrawEntry, ApiClientError> {
self.client.post("/enter", entry).await
}
pub async fn entries(
&self,
client_id: &ClientIdPartial,
) -> Result<Vec<DrawEntry>, ApiClientError> {
self.client.post("/entries", client_id).await
}
pub async fn claim(&self, claim: &ClaimPartial) -> Result<Winner, ApiClientError> {
self.client.post("/claim", claim).await
}
}
@@ -1,57 +0,0 @@
use rust_embed::RustEmbed;
extern crate yaml_rust;
use yaml_rust::YamlLoader;
#[derive(RustEmbed)]
#[folder = "../src/components/Growth/content/"]
#[include = "*.yaml"]
#[exclude = "*.mdx"]
struct Asset;
#[derive(Debug)]
pub struct NotificationContent {
pub title: String,
pub body: String,
}
#[derive(Debug)]
pub struct Notifications {
pub you_are_in_draw: NotificationContent,
pub take_part: NotificationContent,
}
pub struct Content {}
const RESOURCE_ERROR: &str = "❌ RESOURCE ERROR";
fn get_as_string_or_error_message(value: &yaml_rust::Yaml) -> String {
value.as_str().unwrap_or(RESOURCE_ERROR).to_string()
}
impl Content {
pub fn get_notifications() -> Notifications {
let content = Asset::get("en.yaml").unwrap();
let s = std::str::from_utf8(content.data.as_ref()).unwrap();
let content = YamlLoader::load_from_str(s).unwrap();
let content = &content[0];
Notifications {
you_are_in_draw: NotificationContent {
title: get_as_string_or_error_message(
&content["testAndEarn"]["notifications"]["youAreInDraw"]["title"],
),
body: get_as_string_or_error_message(
&content["testAndEarn"]["notifications"]["youAreInDraw"]["body"],
),
},
take_part: NotificationContent {
title: get_as_string_or_error_message(
&content["testAndEarn"]["notifications"]["takePart"]["title"],
),
body: get_as_string_or_error_message(
&content["testAndEarn"]["notifications"]["takePart"]["body"],
),
},
}
}
}
@@ -1,3 +0,0 @@
pub mod api_client;
pub mod assets;
pub mod test_and_earn;
@@ -1,159 +0,0 @@
use crate::error::BackendError;
use crate::operations::export::get_identity_key;
use crate::operations::growth::api_client::{
ClaimPartial, ClientIdPartial, DrawEntry, DrawEntryPartial, DrawWithWordOfTheDay,
GrowthApiClient, Registration, Winner,
};
use crate::State;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[cfg(desktop)]
use tauri::api::notification::Notification;
use tauri::Manager;
use tokio::sync::RwLock;
async fn get_client_id(
state: &tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<ClientIdPartial, BackendError> {
let keypair = get_identity_key(state).await?;
let client_id = keypair.public_key().to_base58_string();
let client_id_signature = keypair
.private_key()
.sign(client_id.as_bytes())
.to_base58_string();
Ok(ClientIdPartial {
client_id,
client_id_signature,
})
}
#[tauri::command]
pub async fn growth_tne_get_client_id(
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<ClientIdPartial, BackendError> {
get_client_id(&state).await
}
#[tauri::command]
pub async fn growth_tne_take_part(
app_handle: tauri::AppHandle,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Registration, BackendError> {
let notifications = super::assets::Content::get_notifications();
let client_id = get_client_id(&state).await?;
let registration = GrowthApiClient::registrations()
.register(&client_id)
.await?;
log::info!("<<< Test&Earn: registration details: {:?}", registration);
#[cfg(desktop)]
if let Err(e) = Notification::new(&app_handle.config().tauri.bundle.identifier)
.title(notifications.take_part.title)
.body(notifications.take_part.body)
.show()
{
log::error!("Could not show notification. Error = {:?}", e);
}
Ok(registration)
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Draws {
pub current: Option<DrawWithWordOfTheDay>,
pub next: Option<DrawWithWordOfTheDay>,
pub draws: Vec<DrawEntry>,
}
#[tauri::command]
pub async fn growth_tne_get_draws(client_details: ClientIdPartial) -> Result<Draws, BackendError> {
let draws_api = GrowthApiClient::daily_draws();
let current = draws_api.current().await.ok();
let next = draws_api.next().await.ok();
let draws = draws_api.entries(&client_details).await?;
Ok(Draws {
current,
next,
draws,
})
}
#[tauri::command]
pub async fn growth_tne_enter_draw(
client_details: ClientIdPartial,
draw_id: String,
) -> Result<DrawEntry, BackendError> {
Ok(GrowthApiClient::daily_draws()
.enter(&DrawEntryPartial {
draw_id,
client_id: client_details.client_id,
client_id_signature: client_details.client_id_signature,
})
.await?)
}
#[tauri::command]
pub async fn growth_tne_submit_wallet_address(
client_details: ClientIdPartial,
draw_id: String,
wallet_address: String,
registration_id: String,
) -> Result<Winner, BackendError> {
Ok(GrowthApiClient::daily_draws()
.claim(&ClaimPartial {
draw_id,
client_id: client_details.client_id,
client_id_signature: client_details.client_id_signature,
wallet_address,
registration_id,
})
.await?)
}
#[tauri::command]
pub async fn growth_tne_ping(client_details: ClientIdPartial) -> Result<(), BackendError> {
log::info!("Test&Earn is sending a ping...");
Ok(GrowthApiClient::registrations()
.ping(&client_details)
.await?)
}
#[cfg(desktop)]
#[tauri::command]
pub async fn growth_tne_toggle_window(
app_handle: tauri::AppHandle,
window_title: Option<String>,
) -> Result<(), BackendError> {
if let Some(window) = app_handle.windows().get("growth") {
log::info!("Closing growth window...");
if let Err(e) = window.close() {
log::error!("Unable to close growth window: {:?}", e);
}
return Ok(());
}
log::info!("Creating growth window...");
match tauri::WindowBuilder::new(
&app_handle,
"growth",
tauri::WindowUrl::App("growth.html".into()),
)
.title(window_title.unwrap_or_else(|| "NymConnect Test&Earn".to_string()))
.build()
{
Ok(window) => {
if let Err(e) = window.set_focus() {
log::error!("Unable to focus growth window: {:?}", e);
}
Ok(())
}
Err(e) => {
log::error!("Unable to create growth window: {:?}", e);
Err(BackendError::NewWindowError)
}
}
}
@@ -1,7 +1,6 @@
pub mod connection; pub mod connection;
pub mod directory; pub mod directory;
pub mod export; pub mod export;
pub mod growth;
pub mod help; pub mod help;
pub mod http; pub mod http;
#[cfg(desktop)] #[cfg(desktop)]

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