Compare commits

...

49 Commits

Author SHA1 Message Date
benedetta davico ad59892b3c Revert "Update Cargo.toml"
This reverts commit d8a95d3810.
2023-08-08 15:37:27 +01:00
benedetta davico d8a95d3810 Update Cargo.toml 2023-08-08 15:42:05 +02:00
benedetta davico 191aa149df Update Cargo.toml 2023-08-08 15:37:16 +02:00
benedettadavico f4df1a9168 Merge branch 'release/v1.1.26' of https://github.com/nymtech/nym into release/v1.1.26 2023-08-08 15:22:49 +02:00
benedettadavico 62316244d9 Revert package.json changes needed temporary build 2023-08-08 15:16:22 +02:00
benedettadavico a26c6d7a29 Temporary update to fix windows build 2023-08-08 15:16:22 +02:00
benedettadavico 8fda246a3c Update changelog and versions for release v1.1.26 2023-08-08 15:16:22 +02:00
Bogdan-Ștefan Neacșu 5620fd7009 Set sphinx as default packet type 2023-08-08 15:16:22 +02:00
Bogdan-Ștefan Neacşu 122612fa03 Apply fix from feature/ephemera to develop too (#3698) (#3742) 2023-08-08 15:16:22 +02:00
mfahampshire 53db18df2c rephrased intro 2023-08-08 15:14:20 +02:00
Jon Häggblad e00910bcb8 Add geo-aware mixnet topology provider (#3713)
* WIP: initial work

* wupwup

* WIP: experiments

* Move topology provider and requests to own crate

* Make sure we use the new crate everywhere

* Sort Cargo.toml

* Extract out some functions in geo_aware_provider

* rustfmt

* Add CountryGroup type

* Assign unknown as well

* wipwip

* Add command line flag to socks5-client

* Use geo-aware mixnode selection in nym-connect when in medium mode

* rustfmt

* clippy

* Fix nym-connect build

* wasm fix

* Spelling
2023-08-08 15:14:13 +02:00
benedettadavico 0af9b3c6c8 Revert package.json changes needed temporary build 2023-08-08 14:17:55 +02:00
benedettadavico 2d60a9da3f Temporary update to fix windows build 2023-08-08 11:24:08 +02:00
benedettadavico 795efb9f0b Update changelog and versions for release v1.1.26 2023-08-08 11:15:30 +02:00
Tommy Verrall 695d34735c Merge pull request #3748 from nymtech/feature/fix_default_packet_type 2023-08-07 15:36:31 +02:00
Bogdan-Ștefan Neacșu 314d7a7526 Set sphinx as default packet type 2023-08-07 15:52:03 +03:00
Tommy Verrall a86c1a6a60 Merge pull request #3745 from nymtech/feature/explorer-api-build-info
added --version command to explorer-api
2023-08-07 11:40:04 +02:00
Bogdan-Ștefan Neacşu 7ad2865250 Add empty migration to group contract (#3740) 2023-08-07 12:32:20 +03:00
Bogdan-Ștefan Neacşu 49440bf60e Apply fix from feature/ephemera to develop too (#3698) (#3742) 2023-08-07 12:27:31 +03:00
Jędrzej Stuczyński b3b43b56be added --version command to explorer-api 2023-08-07 10:15:15 +01:00
Mark Sinclair 4a23729a6a Add GitHub Action to build Typescript SDK docs 2023-08-04 16:31:21 +01:00
pierre 5711bbd0c1 feat(nc-android): add runtime permission request 2023-08-04 17:15:01 +02:00
pierre 1b1f0293ec fix(nc-android): text colors 2023-08-04 15:36:06 +02:00
Jędrzej Stuczyński 9285aaf487 Generate json schema for all used contracts (#3693)
* removed sealed impl of serde for tx::Fee

* further upgraded cosmwasm to 1.3.0

* wip

* created schema for mixnet contract

* updated return type of 'GetBondedMixnodeDetailsByIdentity' query

* fixed imported version of serde_json_wasm

* updated return type of 'GetFamilyByHead' query

* updated return type of 'GetFamilyByLabel' query

* updated return type of 'GetFamilyMembersByHead' and 'GetFamilyMembersByLabel' queries

* fixed broken tests due to type changes

* added support for GetFamilyMembersByLabel and GetFamilyMembersByHead queries in 'mixnet_query_client'

* moved 'Account' and 'VestingContractError' to common crate

* created schema for vesting contract

* Added documentation for all query messages in the vesting contract

* improved mixnet contract schema by adding documentation to all query types

* feature-locking cw2 import

* created schema for the name service contract

* created schema for the service provider directory contract

* created schema for the coconut bandwidth contract

* created schema for the coconut dkg contract

* created schema for the coconut cw4 group contract

* created schema for the coconut cw3 multisig contract

* fixed missing import and adjusted makefile

* cargo fmt

* clippy

* adjusted contract CI to build with --lib flag

* missing --lib flag in the makefile

* updated lock files

* makefile for generating the schemas

* added github action to check for schema difference

* adding missing step to checkout the repo
2023-08-03 15:09:07 +01:00
Bogdan-Ștefan Neacşu 55bd7f8a61 Fix doubling the data dir in nym-api (#3739) 2023-08-03 17:07:59 +03:00
Jędrzej Stuczyński b66c4cf0bb removed dependency on wasm-timer fork (#3733) 2023-08-03 11:01:03 +01:00
mfahampshire 4696470b19 rephrased intro 2023-08-02 16:26:41 +02:00
Tommy Verrall 5dacf0c8f8 Merge pull request #3730 from nymtech/qa/fix-api-tests
fix config for prod runs on api tests
2023-08-02 15:05:27 +02:00
Tommy Verrall cbafd37102 fix config 2023-08-02 13:22:02 +02:00
Tommy Verrall e537359c73 Merge pull request #3728 from nymtech/qa/fix-api-tests
fix api tests for no blacklisted nodes
2023-08-02 13:21:00 +02:00
Tommy Verrall 2ed3e646be linting and removing unused imports 2023-08-02 13:02:29 +02:00
Tommy Verrall c725ae4e2b remove console 2023-08-02 12:55:46 +02:00
Tommy Verrall 5ab2c738df fix api tests for no blacklisted nodes 2023-08-02 12:54:09 +02:00
pierre cd70b0de75 build(nc-android): disable sentry upload proguard mapping files 2023-08-02 11:18:30 +02:00
Tommy Verrall 6359b38a5d Merge pull request #3660 from nymtech/dependabot/npm_and_yarn/nym-wallet/webdriver/semver-5.7.2
Bump semver from 5.7.1 to 5.7.2 in /nym-wallet/webdriver
2023-08-02 10:36:36 +02:00
dependabot[bot] 00b5a46cbc Bump semver from 5.7.1 to 5.7.2 in /nym-wallet/webdriver
Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-01 15:22:00 +00:00
Fouad e97a068bf0 Type documentation for NymSDK (#3701)
* set up development process for docs

* set up development process for docs

* Add local installs for Typedoc on gitignore

* Add Typedoc comments on types.ts file

* add typedoc config file

* update types and add annotations

* Add updates on types file

* add examples + manage sort order for doc items

* update client methods with examples

* add description of NymMixnetClientOptions

* add description of NymMixnetClientOptions

* fix linting

---------

Co-authored-by: Lorexia <alexia.lorenza.martinel@protonmail.com>
2023-08-01 16:21:12 +01:00
Lorexia c7147ebfb2 Add updates to community list projects 2023-08-01 10:50:49 +02:00
mfahampshire a344cda916 removed old wallet address flag again 2023-08-01 10:50:46 +02:00
Lorexia 15a6af49f0 Add updates to community list projects 2023-08-01 10:49:02 +02:00
mfahampshire 97956afdf6 removed old wallet address flag again 2023-08-01 10:48:52 +02:00
Jon Häggblad 7b71775e08 Add geo-aware mixnet topology provider (#3713)
* WIP: initial work

* wupwup

* WIP: experiments

* Move topology provider and requests to own crate

* Make sure we use the new crate everywhere

* Sort Cargo.toml

* Extract out some functions in geo_aware_provider

* rustfmt

* Add CountryGroup type

* Assign unknown as well

* wipwip

* Add command line flag to socks5-client

* Use geo-aware mixnode selection in nym-connect when in medium mode

* rustfmt

* clippy

* Fix nym-connect build

* wasm fix

* Spelling
2023-07-28 14:48:33 +02:00
pierre 5fbccc3406 build(nc-android): moving build config to kotlin 2023-07-27 19:11:33 +02:00
pierre ac8afe133f fix(nc-desktop): typo 2023-07-27 15:53:55 +02:00
Bogdan-Ștefan Neacşu 19736b1204 Fix develop after bad automerge (#3712) 2023-07-27 13:25:34 +03:00
pierre 6e5f6bf0df ci: fix release strapi actions 2023-07-27 11:42:42 +02:00
Jędrzej Stuczyński 67435e9cdf Feature/simplify cli parsing (#3699)
* added a global flag to disable the printed out banner inside tty

* added a 'build-info' command to our binaries

* added binary name to BinaryBuildInformation

* clippy
2023-07-27 10:20:07 +01:00
Bogdan-Ștefan Neacşu a47899aa77 Apply fix from feature/ephemera to develop too (#3698) 2023-07-27 12:18:08 +03:00
pierre 44fa52a7a7 ci: fix release strapi actions 2023-07-27 11:08:24 +02:00
417 changed files with 44516 additions and 5316 deletions
@@ -0,0 +1,25 @@
name: Check Contract Schema
on:
push:
paths:
- 'contracts/**'
- 'common/**'
pull_request:
paths:
- 'contracts/**'
- 'common/**'
jobs:
check-schema:
name: Generate and check schema
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v2
- name: Generate the schema
run: make contract-schema
- name: Check for diff
run: git diff --exit-code
+3 -3
View File
@@ -48,12 +48,12 @@ jobs:
RUSTFLAGS: '-C link-arg=-s' RUSTFLAGS: '-C link-arg=-s'
with: with:
command: build command: build
args: --manifest-path contracts/Cargo.toml --workspace --target wasm32-unknown-unknown args: --manifest-path contracts/Cargo.toml --workspace --lib --target wasm32-unknown-unknown
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
command: test command: test
args: --manifest-path contracts/Cargo.toml args: --lib --manifest-path contracts/Cargo.toml
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
@@ -64,4 +64,4 @@ jobs:
if: ${{ matrix.rust != 'nightly' }} if: ${{ matrix.rust != 'nightly' }}
with: with:
command: clippy command: clippy
args: --manifest-path contracts/Cargo.toml --workspace --all-targets -- -D warnings args: --lib --manifest-path contracts/Cargo.toml --workspace --all-targets -- -D warnings
+50
View File
@@ -0,0 +1,50 @@
name: Typescript SDK docs
on:
push:
paths:
- "sdk/typescript/**"
pull_request:
paths:
- "sdk/typescript/**"
jobs:
build:
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v2
- name: Install rsync
run: sudo apt-get install rsync
continue-on-error: true
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Setup yarn
run: npm install -g yarn
- name: Install
run: yarn
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
env:
NYM_NOTIFICATION_KIND: ts-packages
NYM_PROJECT_NAME: "ts-packages"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "ts-${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
IS_SUCCESS: "${{ job.status == 'success' }}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
+22
View File
@@ -4,6 +4,28 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased] ## [Unreleased]
## [v1.1.24] (2023-08-08)
- Latency based gateway selection is serial and slow ([#3710])
- Network-requester: strip comments from allow lists ([#3625])
- Remove (or start maintaining) `upgrade` commands from all binaries ([#3600])
- Set sphinx as default packet type ([#3748])
- Apply fix from feature/ephemera to develop too (#3698) ([#3742])
- Feature/coco demos ([#3732])
- Add updates to community list projects ([#3722])
- Add geo-aware mixnet topology provider ([#3713])
- Add updates to community list projects ([#3711])
[#3710]: https://github.com/nymtech/nym/issues/3710
[#3625]: https://github.com/nymtech/nym/issues/3625
[#3600]: https://github.com/nymtech/nym/issues/3600
[#3748]: https://github.com/nymtech/nym/pull/3748
[#3742]: https://github.com/nymtech/nym/pull/3742
[#3732]: https://github.com/nymtech/nym/pull/3732
[#3722]: https://github.com/nymtech/nym/pull/3722
[#3713]: https://github.com/nymtech/nym/pull/3713
[#3711]: https://github.com/nymtech/nym/pull/3711
## [v1.1.23] (2023-07-04) ## [v1.1.23] (2023-07-04)
- nym-cli: add client identity key signing support ([#3576]) - nym-cli: add client identity key signing support ([#3576])
Generated
+96 -122
View File
@@ -541,6 +541,12 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "bnum"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "845141a4fade3f790628b7daaaa298a25b204fb28907eb54febe5142db6ce653"
[[package]] [[package]]
name = "bs58" name = "bs58"
version = "0.4.0" version = "0.4.0"
@@ -969,9 +975,9 @@ dependencies = [
[[package]] [[package]]
name = "cosmwasm-crypto" name = "cosmwasm-crypto"
version = "1.2.5" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75836a10cb9654c54e77ee56da94d592923092a10b369cdb0dbd56acefc16340" checksum = "0d076a08ec01ed23c4396aca98ec73a38fa1fee5f310465add52b4108181c7a8"
dependencies = [ dependencies = [
"digest 0.10.7", "digest 0.10.7",
"ed25519-zebra", "ed25519-zebra",
@@ -982,18 +988,18 @@ dependencies = [
[[package]] [[package]]
name = "cosmwasm-derive" name = "cosmwasm-derive"
version = "1.2.5" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c9f7f0e51bfc7295f7b2664fe8513c966428642aa765dad8a74acdab5e0c773" checksum = "dec361f3c09d7b41221948fc17be9b3c96cb58e55a02f82da36f888a651f2584"
dependencies = [ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]] [[package]]
name = "cosmwasm-schema" name = "cosmwasm-schema"
version = "1.2.5" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f00b363610218eea83f24bbab09e1a7c3920b79f068334fdfcc62f6129ef9fc" checksum = "bb6b2fb76758ef59cddc77f2e2ae91c22f77da49037e9f182e9c2833f0e959b1"
dependencies = [ dependencies = [
"cosmwasm-schema-derive", "cosmwasm-schema-derive",
"schemars", "schemars",
@@ -1004,9 +1010,9 @@ dependencies = [
[[package]] [[package]]
name = "cosmwasm-schema-derive" name = "cosmwasm-schema-derive"
version = "1.2.5" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae38f909b2822d32b275c9e2db9728497aa33ffe67dd463bc67c6a3b7092785c" checksum = "2bfa39422f0d9f1c9a6fd3711573258495314dfa3aae738ea825ecd9964bc659"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1015,11 +1021,12 @@ dependencies = [
[[package]] [[package]]
name = "cosmwasm-std" name = "cosmwasm-std"
version = "1.2.5" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a49b85345e811c8e80ec55d0d091e4fcb4f00f97ab058f9be5f614c444a730cb" checksum = "1f6dc2ee23313add5ecacc3ccac217b9967ad9d2d11bd56e5da6aa65a9da6138"
dependencies = [ dependencies = [
"base64 0.13.1", "base64 0.13.1",
"bnum",
"cosmwasm-crypto", "cosmwasm-crypto",
"cosmwasm-derive", "cosmwasm-derive",
"derivative", "derivative",
@@ -1027,10 +1034,9 @@ dependencies = [
"hex", "hex",
"schemars", "schemars",
"serde", "serde",
"serde-json-wasm 0.5.1", "serde-json-wasm",
"sha2 0.10.6", "sha2 0.10.6",
"thiserror", "thiserror",
"uint",
] ]
[[package]] [[package]]
@@ -1203,12 +1209,6 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]] [[package]]
name = "crypto-bigint" name = "crypto-bigint"
version = "0.4.9" version = "0.4.9"
@@ -1370,9 +1370,9 @@ dependencies = [
[[package]] [[package]]
name = "cw-controllers" name = "cw-controllers"
version = "1.0.1" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91440ce8ec4f0642798bc8c8cb6b9b53c1926c6dadaf0eed267a5145cd529071" checksum = "d5d8edce4b78785f36413f67387e4be7d0cb7d032b5d4164bcc024f9c3f3f2ea"
dependencies = [ dependencies = [
"cosmwasm-schema", "cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
@@ -1385,9 +1385,9 @@ dependencies = [
[[package]] [[package]]
name = "cw-storage-plus" name = "cw-storage-plus"
version = "1.0.1" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053a5083c258acd68386734f428a5a171b29f7d733151ae83090c6fcc9417ffa" checksum = "3f0e92a069d62067f3472c62e30adedb4cab1754725c0f2a682b3128d2bf3c79"
dependencies = [ dependencies = [
"cosmwasm-std", "cosmwasm-std",
"schemars", "schemars",
@@ -1411,22 +1411,23 @@ dependencies = [
[[package]] [[package]]
name = "cw2" name = "cw2"
version = "1.0.1" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fb70cee2cf0b4a8ff7253e6bc6647107905e8eb37208f87d54f67810faa62f8" checksum = "29ac2dc7a55ad64173ca1e0a46697c31b7a5c51342f55a1e84a724da4eb99908"
dependencies = [ dependencies = [
"cosmwasm-schema", "cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"cw-storage-plus", "cw-storage-plus",
"schemars", "schemars",
"serde", "serde",
"thiserror",
] ]
[[package]] [[package]]
name = "cw20" name = "cw20"
version = "1.0.1" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91666da6c7b40c8dd5ff94df655a28114efc10c79b70b4d06f13c31e37d60609" checksum = "011c45920f8200bd5d32d4fe52502506f64f2f75651ab408054d4cfc75ca3a9b"
dependencies = [ dependencies = [
"cosmwasm-schema", "cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
@@ -1437,9 +1438,9 @@ dependencies = [
[[package]] [[package]]
name = "cw3" name = "cw3"
version = "1.0.1" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fe0b587008aa221cd2a2579a21990a28c4347dc53ad43167c68ad765f5b6efa" checksum = "171af3d9127de6805a7dd819fb070c7d2f6c3ea85f4193f42cef259f0a7f33d5"
dependencies = [ dependencies = [
"cosmwasm-schema", "cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
@@ -1452,9 +1453,9 @@ dependencies = [
[[package]] [[package]]
name = "cw4" name = "cw4"
version = "1.0.1" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c236e0bae02ce97e89235a681dd0e07d099524b369f1ef908d704db3e6b049b" checksum = "a398696307efadaaa2d0850076f865fa706c959d493cb4203314f72be6b77a64"
dependencies = [ dependencies = [
"cosmwasm-schema", "cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
@@ -1895,7 +1896,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]] [[package]]
name = "explorer-api" name = "explorer-api"
version = "1.1.23" version = "1.1.24"
dependencies = [ dependencies = [
"chrono", "chrono",
"clap 4.2.7", "clap 4.2.7",
@@ -1903,10 +1904,12 @@ dependencies = [
"humantime-serde", "humantime-serde",
"isocountry", "isocountry",
"itertools", "itertools",
"lazy_static",
"log", "log",
"maxminddb", "maxminddb",
"nym-bin-common", "nym-bin-common",
"nym-contracts-common", "nym-contracts-common",
"nym-explorer-api-requests",
"nym-mixnet-contract-common", "nym-mixnet-contract-common",
"nym-network-defaults", "nym-network-defaults",
"nym-task", "nym-task",
@@ -2924,9 +2927,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
] ]
[[package]] [[package]]
@@ -3530,7 +3530,7 @@ dependencies = [
[[package]] [[package]]
name = "nym-api" name = "nym-api"
version = "1.1.24" version = "1.1.25"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@@ -3667,7 +3667,7 @@ dependencies = [
[[package]] [[package]]
name = "nym-cli" name = "nym-cli"
version = "1.1.23" version = "1.1.24"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base64 0.13.1", "base64 0.13.1",
@@ -3733,7 +3733,7 @@ dependencies = [
[[package]] [[package]]
name = "nym-client" name = "nym-client"
version = "1.1.23" version = "1.1.24"
dependencies = [ dependencies = [
"clap 4.2.7", "clap 4.2.7",
"dirs 4.0.0", "dirs 4.0.0",
@@ -3783,6 +3783,7 @@ dependencies = [
"nym-config", "nym-config",
"nym-credential-storage", "nym-credential-storage",
"nym-crypto", "nym-crypto",
"nym-explorer-api-requests",
"nym-gateway-client", "nym-gateway-client",
"nym-gateway-requests", "nym-gateway-requests",
"nym-network-defaults", "nym-network-defaults",
@@ -3793,6 +3794,7 @@ dependencies = [
"nym-topology", "nym-topology",
"nym-validator-client", "nym-validator-client",
"rand 0.7.3", "rand 0.7.3",
"reqwest",
"serde", "serde",
"serde_json", "serde_json",
"sha2 0.10.6", "sha2 0.10.6",
@@ -3808,8 +3810,8 @@ dependencies = [
"url", "url",
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"wasm-timer",
"wasm-utils", "wasm-utils",
"wasmtimer",
"zeroize", "zeroize",
] ]
@@ -3849,22 +3851,21 @@ dependencies = [
name = "nym-coconut-bandwidth-contract-common" name = "nym-coconut-bandwidth-contract-common"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"cw2",
"nym-multisig-contract-common", "nym-multisig-contract-common",
"schemars",
"serde",
] ]
[[package]] [[package]]
name = "nym-coconut-dkg-common" name = "nym-coconut-dkg-common"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"cw-utils", "cw-utils",
"nym-contracts-common", "nym-contracts-common",
"nym-multisig-contract-common", "nym-multisig-contract-common",
"schemars",
"serde",
] ]
[[package]] [[package]]
@@ -3896,6 +3897,7 @@ name = "nym-contracts-common"
version = "0.5.0" version = "0.5.0"
dependencies = [ dependencies = [
"bs58 0.4.0", "bs58 0.4.0",
"cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"schemars", "schemars",
"serde", "serde",
@@ -4005,9 +4007,21 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "nym-explorer-api-requests"
version = "0.1.0"
dependencies = [
"nym-contracts-common",
"nym-mixnet-contract-common",
"nym-validator-client",
"schemars",
"serde",
"ts-rs",
]
[[package]] [[package]]
name = "nym-gateway" name = "nym-gateway"
version = "1.1.23" version = "1.1.24"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@@ -4082,8 +4096,8 @@ dependencies = [
"url", "url",
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"wasm-timer",
"wasm-utils", "wasm-utils",
"wasmtimer",
] ]
[[package]] [[package]]
@@ -4144,14 +4158,16 @@ name = "nym-mixnet-contract-common"
version = "0.6.0" version = "0.6.0"
dependencies = [ dependencies = [
"bs58 0.4.0", "bs58 0.4.0",
"cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"cw2",
"humantime-serde", "humantime-serde",
"log", "log",
"nym-contracts-common", "nym-contracts-common",
"rand_chacha 0.3.1", "rand_chacha 0.3.1",
"schemars", "schemars",
"serde", "serde",
"serde-json-wasm 0.4.1", "serde-json-wasm",
"serde_repr", "serde_repr",
"thiserror", "thiserror",
"time 0.3.21", "time 0.3.21",
@@ -4160,7 +4176,7 @@ dependencies = [
[[package]] [[package]]
name = "nym-mixnode" name = "nym-mixnode"
version = "1.1.24" version = "1.1.25"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bs58 0.4.0", "bs58 0.4.0",
@@ -4252,11 +4268,12 @@ dependencies = [
name = "nym-name-service-common" name = "nym-name-service-common"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"cw-controllers", "cw-controllers",
"cw-utils", "cw-utils",
"cw2",
"nym-contracts-common", "nym-contracts-common",
"schemars",
"serde", "serde",
"thiserror", "thiserror",
] ]
@@ -4276,7 +4293,7 @@ dependencies = [
[[package]] [[package]]
name = "nym-network-requester" name = "nym-network-requester"
version = "1.1.23" version = "1.1.24"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-file-watcher", "async-file-watcher",
@@ -4323,7 +4340,7 @@ dependencies = [
[[package]] [[package]]
name = "nym-network-statistics" name = "nym-network-statistics"
version = "1.1.23" version = "1.1.24"
dependencies = [ dependencies = [
"dirs 4.0.0", "dirs 4.0.0",
"log", "log",
@@ -4361,12 +4378,10 @@ dependencies = [
name = "nym-nonexhaustive-delayqueue" name = "nym-nonexhaustive-delayqueue"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"futures-core",
"slab",
"tokio", "tokio",
"tokio-stream", "tokio-stream",
"tokio-util", "tokio-util",
"wasm-timer", "wasmtimer",
] ]
[[package]] [[package]]
@@ -4454,12 +4469,12 @@ dependencies = [
name = "nym-service-provider-directory-common" name = "nym-service-provider-directory-common"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"cw-controllers", "cw-controllers",
"cw-utils", "cw-utils",
"cw2",
"nym-contracts-common", "nym-contracts-common",
"schemars",
"serde",
"thiserror", "thiserror",
] ]
@@ -4482,7 +4497,7 @@ dependencies = [
[[package]] [[package]]
name = "nym-socks5-client" name = "nym-socks5-client"
version = "1.1.23" version = "1.1.24"
dependencies = [ dependencies = [
"clap 4.2.7", "clap 4.2.7",
"lazy_static", "lazy_static",
@@ -4520,7 +4535,9 @@ dependencies = [
"nym-bandwidth-controller", "nym-bandwidth-controller",
"nym-client-core", "nym-client-core",
"nym-config", "nym-config",
"nym-contracts-common",
"nym-credential-storage", "nym-credential-storage",
"nym-mixnet-contract-common",
"nym-network-defaults", "nym-network-defaults",
"nym-service-providers-common", "nym-service-providers-common",
"nym-socks5-proxy-helpers", "nym-socks5-proxy-helpers",
@@ -4530,10 +4547,13 @@ dependencies = [
"nym-validator-client", "nym-validator-client",
"pin-project", "pin-project",
"rand 0.7.3", "rand 0.7.3",
"reqwest",
"schemars",
"serde", "serde",
"tap", "tap",
"thiserror", "thiserror",
"tokio", "tokio",
"url",
] ]
[[package]] [[package]]
@@ -4809,7 +4829,6 @@ dependencies = [
"nym-config", "nym-config",
"nym-mixnet-contract-common", "nym-mixnet-contract-common",
"nym-validator-client", "nym-validator-client",
"nym-vesting-contract",
"nym-vesting-contract-common", "nym-vesting-contract-common",
"reqwest", "reqwest",
"schemars", "schemars",
@@ -4851,7 +4870,6 @@ dependencies = [
"nym-name-service-common", "nym-name-service-common",
"nym-network-defaults", "nym-network-defaults",
"nym-service-provider-directory-common", "nym-service-provider-directory-common",
"nym-vesting-contract",
"nym-vesting-contract-common", "nym-vesting-contract-common",
"openssl", "openssl",
"prost", "prost",
@@ -4867,33 +4885,17 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "nym-vesting-contract"
version = "1.4.0"
dependencies = [
"cosmwasm-derive",
"cosmwasm-std",
"cw-storage-plus",
"cw2",
"nym-contracts-common",
"nym-mixnet-contract-common",
"nym-vesting-contract-common",
"schemars",
"semver 1.0.17",
"serde",
"thiserror",
"vergen",
]
[[package]] [[package]]
name = "nym-vesting-contract-common" name = "nym-vesting-contract-common"
version = "0.7.0" version = "0.7.0"
dependencies = [ dependencies = [
"cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"cw2",
"nym-contracts-common", "nym-contracts-common",
"nym-mixnet-contract-common", "nym-mixnet-contract-common",
"schemars",
"serde", "serde",
"thiserror",
"ts-rs", "ts-rs",
] ]
@@ -4909,7 +4911,6 @@ dependencies = [
"nym-network-defaults", "nym-network-defaults",
"nym-types", "nym-types",
"nym-validator-client", "nym-validator-client",
"nym-vesting-contract",
"nym-vesting-contract-common", "nym-vesting-contract-common",
"serde", "serde",
"serde_json", "serde_json",
@@ -6436,18 +6437,9 @@ dependencies = [
[[package]] [[package]]
name = "serde-json-wasm" name = "serde-json-wasm"
version = "0.4.1" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479b4dbc401ca13ee8ce902851b834893251404c4f3c65370a49e047a6be09a5" checksum = "a15bee9b04dd165c3f4e142628982ddde884c2022a89e8ddf99c4829bf2c3a58"
dependencies = [
"serde",
]
[[package]]
name = "serde-json-wasm"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16a62a1fad1e1828b24acac8f2b468971dade7b8c3c2e672bcadefefb1f8c137"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@@ -6985,12 +6977,6 @@ dependencies = [
"loom", "loom",
] ]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]] [[package]]
name = "stringprep" name = "stringprep"
version = "0.1.2" version = "0.1.2"
@@ -7202,9 +7188,9 @@ dependencies = [
[[package]] [[package]]
name = "tendermint-rpc" name = "tendermint-rpc"
version = "0.32.0" version = "0.32.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd2cc789170db5a35d4e0bb2490035c03ef96df08f119bee25fd8dab5a09aa25" checksum = "d119d83a130537fc4a98c3c9eb6899ebe857fea4860400a61675bfb5f0b35129"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"bytes", "bytes",
@@ -7823,18 +7809,6 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
[[package]]
name = "uint"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52"
dependencies = [
"byteorder",
"crunchy",
"hex",
"static_assertions",
]
[[package]] [[package]]
name = "uncased" name = "uncased"
version = "0.9.9" version = "0.9.9"
@@ -8131,20 +8105,6 @@ version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
[[package]]
name = "wasm-timer"
version = "0.2.5"
source = "git+https://github.com/mmsinclair/wasm-timer?rev=b9d1a54ad514c2f230a026afe0dde341e98cd7b6#b9d1a54ad514c2f230a026afe0dde341e98cd7b6"
dependencies = [
"futures",
"js-sys",
"parking_lot 0.11.2",
"pin-utils",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]] [[package]]
name = "wasm-utils" name = "wasm-utils"
version = "0.1.0" version = "0.1.0"
@@ -8163,6 +8123,20 @@ dependencies = [
"web-sys", "web-sys",
] ]
[[package]]
name = "wasmtimer"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f656cd8858a5164932d8a90f936700860976ec21eb00e0fe2aa8cab13f6b4cf"
dependencies = [
"futures",
"js-sys",
"parking_lot 0.12.1",
"pin-utils",
"slab",
"wasm-bindgen",
]
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.60" version = "0.3.60"
+19 -11
View File
@@ -74,6 +74,7 @@ members = [
"common/types", "common/types",
"common/wasm-utils", "common/wasm-utils",
"explorer-api", "explorer-api",
"explorer-api/explorer-api-requests",
"gateway", "gateway",
"gateway/gateway-requests", "gateway/gateway-requests",
"integrations/bity", "integrations/bity",
@@ -117,32 +118,39 @@ anyhow = "1.0.71"
async-trait = "0.1.64" async-trait = "0.1.64"
bip39 = { version = "2.0.0", features = ["zeroize"] } bip39 = { version = "2.0.0", features = ["zeroize"] }
cfg-if = "1.0.0" cfg-if = "1.0.0"
cosmwasm-derive = "=1.2.5" cosmwasm-derive = "=1.3.0"
cosmwasm-schema = "=1.2.5" cosmwasm-schema = "=1.3.0"
cosmwasm-std = "=1.2.5" cosmwasm-std = "=1.3.0"
cosmwasm-storage = "=1.2.5" # use 0.5.0 as that's the version used by cosmwasm-std 1.3.0
# (and ideally we don't want to pull the same dependency twice)
serde-json-wasm = "=0.5.0"
cosmwasm-storage = "=1.3.0"
cosmrs = "=0.14.0" cosmrs = "=0.14.0"
# same version as used by cosmrs # same version as used by cosmrs
tendermint-rpc = "=0.32" tendermint-rpc = "=0.32"
cw-utils = "=1.0.1" cw-utils = "=1.0.1"
cw-storage-plus = "=1.0.1" cw-storage-plus = "=1.1.0"
cw2 = { version = "=1.0.1" } cw2 = { version = "=1.1.0" }
cw3 = { version = "=1.0.1" } cw3 = { version = "=1.1.0" }
cw3-fixed-multisig = { version = "=1.0.1" } cw4 = { version = "=1.1.0" }
cw4 = { version = "=1.0.1" } cw-controllers = { version = "=1.1.0" }
cw-controllers = { version = "=1.0.1" }
dotenvy = "0.15.6" dotenvy = "0.15.6"
generic-array = "0.14.7" generic-array = "0.14.7"
k256 = "0.13"
getrandom = "0.2.10" getrandom = "0.2.10"
k256 = "0.13"
lazy_static = "1.4.0" lazy_static = "1.4.0"
log = "0.4" log = "0.4"
once_cell = "1.7.2" once_cell = "1.7.2"
rand = "0.8.5" rand = "0.8.5"
reqwest = "0.11.18"
serde = "1.0.152" serde = "1.0.152"
serde_json = "1.0.91" serde_json = "1.0.91"
tap = "1.0.1" tap = "1.0.1"
tendermint-rpc = "0.32" # same version as used by cosmrs
thiserror = "1.0.38" thiserror = "1.0.38"
tokio = "1.24.1" tokio = "1.24.1"
url = "2.2" url = "2.2"
zeroize = "1.6.0" zeroize = "1.6.0"
# wasm-related dependencies
wasmtimer = "0.2.0"
+5 -2
View File
@@ -73,7 +73,7 @@ endef
# Generate targets for the various cargo workspaces # Generate targets for the various cargo workspaces
$(eval $(call add_cargo_workspace,main,.)) $(eval $(call add_cargo_workspace,main,.))
$(eval $(call add_cargo_workspace,contracts,contracts,--target wasm32-unknown-unknown)) $(eval $(call add_cargo_workspace,contracts,contracts,--lib --target wasm32-unknown-unknown))
$(eval $(call add_cargo_workspace,wasm-client,clients/webassembly,--target wasm32-unknown-unknown)) $(eval $(call add_cargo_workspace,wasm-client,clients/webassembly,--target wasm32-unknown-unknown))
$(eval $(call add_cargo_workspace,wallet,nym-wallet,)) $(eval $(call add_cargo_workspace,wallet,nym-wallet,))
$(eval $(call add_cargo_workspace,connect,nym-connect/desktop)) $(eval $(call add_cargo_workspace,connect,nym-connect/desktop))
@@ -104,7 +104,7 @@ NAME_SERVICE_CONTRACT=$(CONTRACTS_OUT_DIR)/nym_name_service.wasm
wasm: wasm-build wasm-opt wasm: wasm-build wasm-opt
wasm-build: wasm-build:
RUSTFLAGS='-C link-arg=-s' cargo build --manifest-path contracts/Cargo.toml --release --target wasm32-unknown-unknown RUSTFLAGS='-C link-arg=-s' cargo build --lib --manifest-path contracts/Cargo.toml --release --target wasm32-unknown-unknown
wasm-opt: wasm-opt:
wasm-opt --disable-sign-ext -Os $(VESTING_CONTRACT) -o $(VESTING_CONTRACT) wasm-opt --disable-sign-ext -Os $(VESTING_CONTRACT) -o $(VESTING_CONTRACT)
@@ -112,6 +112,9 @@ wasm-opt:
wasm-opt --disable-sign-ext -Os $(SERVICE_PROVIDER_DIRECTORY_CONTRACT) -o $(SERVICE_PROVIDER_DIRECTORY_CONTRACT) wasm-opt --disable-sign-ext -Os $(SERVICE_PROVIDER_DIRECTORY_CONTRACT) -o $(SERVICE_PROVIDER_DIRECTORY_CONTRACT)
wasm-opt --disable-sign-ext -Os $(NAME_SERVICE_CONTRACT) -o $(NAME_SERVICE_CONTRACT) wasm-opt --disable-sign-ext -Os $(NAME_SERVICE_CONTRACT) -o $(NAME_SERVICE_CONTRACT)
contract-schema:
$(MAKE) -C contracts schema
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Misc # Misc
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "nym-client" name = "nym-client"
version = "1.1.23" version = "1.1.24"
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"
+16
View File
@@ -0,0 +1,16 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Args;
use nym_bin_common::bin_info_owned;
use nym_bin_common::output_format::OutputFormat;
#[derive(Args)]
pub(crate) struct BuildInfo {
#[clap(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
pub(crate) fn execute(args: BuildInfo) {
println!("{}", args.output.format(&bin_info_owned!()))
}
+15 -7
View File
@@ -10,7 +10,7 @@ use clap::CommandFactory;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use log::{error, info}; use log::{error, info};
use nym_bin_common::build_information::BinaryBuildInformation; use nym_bin_common::bin_info;
use nym_bin_common::completions::{fig_generate, ArgShell}; use nym_bin_common::completions::{fig_generate, ArgShell};
use nym_client_core::client::base_client::storage::gateway_details::{ use nym_client_core::client::base_client::storage::gateway_details::{
OnDiskGatewayDetails, PersistedGatewayDetails, OnDiskGatewayDetails, PersistedGatewayDetails,
@@ -22,12 +22,12 @@ use nym_config::OptionalSet;
use std::error::Error; use std::error::Error;
use std::net::IpAddr; use std::net::IpAddr;
pub(crate) mod build_info;
pub(crate) mod init; pub(crate) mod init;
pub(crate) mod run; pub(crate) mod run;
lazy_static! { lazy_static! {
pub static ref PRETTY_BUILD_INFORMATION: String = pub static ref PRETTY_BUILD_INFORMATION: String = bin_info!().pretty_print();
BinaryBuildInformation::new(env!("CARGO_PKG_VERSION")).pretty_print();
} }
// Helper for passing LONG_VERSION to clap // Helper for passing LONG_VERSION to clap
@@ -42,6 +42,10 @@ pub(crate) struct Cli {
#[clap(short, long)] #[clap(short, long)]
pub(crate) config_env_file: Option<std::path::PathBuf>, pub(crate) config_env_file: Option<std::path::PathBuf>,
/// Flag used for disabling the printed banner in tty.
#[clap(long)]
pub(crate) no_banner: bool,
#[clap(subcommand)] #[clap(subcommand)]
command: Commands, command: Commands,
} }
@@ -54,6 +58,9 @@ pub(crate) enum Commands {
/// Run the Nym client with provided configuration client optionally overriding set parameters /// Run the Nym client with provided configuration client optionally overriding set parameters
Run(run::Run), Run(run::Run),
/// Show build information of this binary
BuildInfo(build_info::BuildInfo),
/// Generate shell completions /// Generate shell completions
Completions(ArgShell), Completions(ArgShell),
@@ -73,12 +80,13 @@ pub(crate) struct OverrideConfig {
enabled_credentials_mode: Option<bool>, enabled_credentials_mode: Option<bool>,
} }
pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Sync>> { pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync>> {
let bin_name = "nym-native-client"; let bin_name = "nym-native-client";
match &args.command { match args.command {
Commands::Init(m) => init::execute(m).await?, Commands::Init(m) => init::execute(&m).await?,
Commands::Run(m) => run::execute(m).await?, Commands::Run(m) => run::execute(&m).await?,
Commands::BuildInfo(m) => build_info::execute(m),
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name), Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name), Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
} }
+7 -4
View File
@@ -14,10 +14,13 @@ pub mod websocket;
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> { async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
setup_logging();
maybe_print_banner(crate_name!(), crate_version!());
let args = commands::Cli::parse(); let args = commands::Cli::parse();
setup_env(args.config_env_file.as_ref()); setup_env(args.config_env_file.as_ref());
commands::execute(&args).await
if !args.no_banner {
maybe_print_banner(crate_name!(), crate_version!());
}
setup_logging();
commands::execute(args).await
} }
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "nym-socks5-client" name = "nym-socks5-client"
version = "1.1.23" version = "1.1.24"
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"
+16
View File
@@ -0,0 +1,16 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Args;
use nym_bin_common::bin_info_owned;
use nym_bin_common::output_format::OutputFormat;
#[derive(Args)]
pub(crate) struct BuildInfo {
#[clap(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
pub(crate) fn execute(args: BuildInfo) {
println!("{}", args.output.format(&bin_info_owned!()))
}
+1
View File
@@ -94,6 +94,7 @@ impl From<Init> for OverrideConfig {
use_anonymous_replies: init_config.use_reply_surbs, use_anonymous_replies: init_config.use_reply_surbs,
fastmode: init_config.fastmode, fastmode: init_config.fastmode,
no_cover: init_config.no_cover, no_cover: init_config.no_cover,
geo_routing: None,
medium_toggle: false, medium_toggle: false,
nyxd_urls: init_config.nyxd_urls, nyxd_urls: init_config.nyxd_urls,
enabled_credentials_mode: init_config.enabled_credentials_mode, enabled_credentials_mode: init_config.enabled_credentials_mode,
+29 -8
View File
@@ -10,24 +10,25 @@ use clap::CommandFactory;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use log::{error, info}; use log::{error, info};
use nym_bin_common::build_information::BinaryBuildInformation; use nym_bin_common::bin_info;
use nym_bin_common::completions::{fig_generate, ArgShell}; use nym_bin_common::completions::{fig_generate, ArgShell};
use nym_client_core::client::base_client::storage::gateway_details::{ use nym_client_core::client::base_client::storage::gateway_details::{
OnDiskGatewayDetails, PersistedGatewayDetails, OnDiskGatewayDetails, PersistedGatewayDetails,
}; };
use nym_client_core::client::key_manager::persistence::OnDiskKeys; use nym_client_core::client::key_manager::persistence::OnDiskKeys;
use nym_client_core::config::GatewayEndpointConfig; use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup;
use nym_client_core::config::{GatewayEndpointConfig, TopologyStructure};
use nym_client_core::error::ClientCoreError; use nym_client_core::error::ClientCoreError;
use nym_config::OptionalSet; use nym_config::OptionalSet;
use nym_sphinx::params::{PacketSize, PacketType}; use nym_sphinx::params::{PacketSize, PacketType};
use std::error::Error; use std::error::Error;
pub(crate) mod build_info;
pub mod init; pub mod init;
pub(crate) mod run; pub(crate) mod run;
lazy_static! { lazy_static! {
pub static ref PRETTY_BUILD_INFORMATION: String = pub static ref PRETTY_BUILD_INFORMATION: String = bin_info!().pretty_print();
BinaryBuildInformation::new(env!("CARGO_PKG_VERSION")).pretty_print();
} }
// Helper for passing LONG_VERSION to clap // Helper for passing LONG_VERSION to clap
@@ -42,6 +43,10 @@ pub(crate) struct Cli {
#[clap(short, long)] #[clap(short, long)]
pub(crate) config_env_file: Option<std::path::PathBuf>, pub(crate) config_env_file: Option<std::path::PathBuf>,
/// Flag used for disabling the printed banner in tty.
#[clap(long)]
pub(crate) no_banner: bool,
#[clap(subcommand)] #[clap(subcommand)]
command: Commands, command: Commands,
} }
@@ -54,6 +59,9 @@ pub(crate) enum Commands {
/// Run the Nym client with provided configuration client optionally overriding set parameters /// Run the Nym client with provided configuration client optionally overriding set parameters
Run(run::Run), Run(run::Run),
/// Show build information of this binary
BuildInfo(build_info::BuildInfo),
/// Generate shell completions /// Generate shell completions
Completions(ArgShell), Completions(ArgShell),
@@ -68,18 +76,20 @@ pub(crate) struct OverrideConfig {
use_anonymous_replies: Option<bool>, use_anonymous_replies: Option<bool>,
fastmode: bool, fastmode: bool,
no_cover: bool, no_cover: bool,
geo_routing: Option<CountryGroup>,
medium_toggle: bool, medium_toggle: bool,
nyxd_urls: Option<Vec<url::Url>>, nyxd_urls: Option<Vec<url::Url>>,
enabled_credentials_mode: Option<bool>, enabled_credentials_mode: Option<bool>,
outfox: bool, outfox: bool,
} }
pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Sync>> { pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync>> {
let bin_name = "nym-socks5-client"; let bin_name = "nym-socks5-client";
match &args.command { match args.command {
Commands::Init(m) => init::execute(m).await?, Commands::Init(m) => init::execute(&m).await?,
Commands::Run(m) => run::execute(m).await?, Commands::Run(m) => run::execute(&m).await?,
Commands::BuildInfo(m) => build_info::execute(m),
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name), Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name), Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
} }
@@ -91,6 +101,13 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
let secondary_packet_size = args.medium_toggle.then_some(PacketSize::ExtendedPacket16); let secondary_packet_size = args.medium_toggle.then_some(PacketSize::ExtendedPacket16);
let no_per_hop_delays = args.medium_toggle; let no_per_hop_delays = args.medium_toggle;
let topology_structure = if args.medium_toggle || args.geo_routing.is_some() {
// TODO: rethink the default group. I just picked one for now.
TopologyStructure::GeoAware(args.geo_routing.unwrap_or(CountryGroup::Europe))
} else {
TopologyStructure::default()
};
let packet_type = if args.outfox { let packet_type = if args.outfox {
PacketType::Outfox PacketType::Outfox
} else { } else {
@@ -114,6 +131,10 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
// NOTE: see comment above about the order of the other disble cover traffic config // NOTE: see comment above about the order of the other disble cover traffic config
.with_base(BaseClientConfig::with_disabled_cover_traffic, args.no_cover) .with_base(BaseClientConfig::with_disabled_cover_traffic, args.no_cover)
.with_base(BaseClientConfig::with_packet_type, packet_type) .with_base(BaseClientConfig::with_packet_type, packet_type)
.with_base(
BaseClientConfig::with_topology_structure,
topology_structure,
)
.with_optional(Config::with_anonymous_replies, args.use_anonymous_replies) .with_optional(Config::with_anonymous_replies, args.use_anonymous_replies)
.with_optional(Config::with_port, args.port) .with_optional(Config::with_port, args.port)
.with_optional_base_custom_env( .with_optional_base_custom_env(
+13
View File
@@ -11,6 +11,7 @@ use clap::Args;
use log::*; use log::*;
use nym_bin_common::version_checker::is_minor_version_compatible; use nym_bin_common::version_checker::is_minor_version_compatible;
use nym_client_core::client::base_client::storage::OnDiskPersistent; use nym_client_core::client::base_client::storage::OnDiskPersistent;
use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup;
use nym_crypto::asymmetric::identity; use nym_crypto::asymmetric::identity;
use nym_socks5_client_core::NymClient; use nym_socks5_client_core::NymClient;
use nym_sphinx::addressing::clients::Recipient; use nym_sphinx::addressing::clients::Recipient;
@@ -60,6 +61,10 @@ pub(crate) struct Run {
#[clap(long, hide = true)] #[clap(long, hide = true)]
no_cover: bool, no_cover: bool,
/// Set geo-aware mixnode selection when sending mixnet traffic, for experiments only.
#[clap(long, hide = true, value_parser = validate_country_group)]
geo_routing: Option<CountryGroup>,
/// Enable medium mixnet traffic, for experiments only. /// Enable medium mixnet traffic, for experiments only.
/// This includes things like disabling cover traffic, no per hop delays, etc. /// This includes things like disabling cover traffic, no per hop delays, etc.
#[clap(long, hide = true)] #[clap(long, hide = true)]
@@ -82,6 +87,7 @@ impl From<Run> for OverrideConfig {
use_anonymous_replies: run_config.use_anonymous_replies, use_anonymous_replies: run_config.use_anonymous_replies,
fastmode: run_config.fastmode, fastmode: run_config.fastmode,
no_cover: run_config.no_cover, no_cover: run_config.no_cover,
geo_routing: run_config.geo_routing,
medium_toggle: run_config.medium_toggle, medium_toggle: run_config.medium_toggle,
nyxd_urls: run_config.nyxd_urls, nyxd_urls: run_config.nyxd_urls,
enabled_credentials_mode: run_config.enabled_credentials_mode, enabled_credentials_mode: run_config.enabled_credentials_mode,
@@ -90,6 +96,13 @@ impl From<Run> for OverrideConfig {
} }
} }
fn validate_country_group(s: &str) -> Result<CountryGroup, String> {
match s.parse() {
Ok(cg) => Ok(cg),
Err(_) => Err(format!("failed to parse country group: {}", s)),
}
}
// this only checks compatibility between config the binary. It does not take into consideration // this only checks compatibility between config the binary. It does not take into consideration
// network version. It might do so in the future. // network version. It might do so in the future.
fn version_check(cfg: &Config) -> bool { fn version_check(cfg: &Config) -> bool {
+7 -4
View File
@@ -13,10 +13,13 @@ pub mod error;
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> { async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
setup_logging();
maybe_print_banner(crate_name!(), crate_version!());
let args = commands::Cli::parse(); let args = commands::Cli::parse();
setup_env(args.config_env_file.as_ref()); setup_env(args.config_env_file.as_ref());
commands::execute(&args).await
if !args.no_banner {
maybe_print_banner(crate_name!(), crate_version!());
}
setup_logging();
commands::execute(args).await
} }
+80 -107
View File
@@ -378,6 +378,12 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "bnum"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "845141a4fade3f790628b7daaaa298a25b204fb28907eb54febe5142db6ce653"
[[package]] [[package]]
name = "bs58" name = "bs58"
version = "0.4.0" version = "0.4.0"
@@ -658,18 +664,18 @@ dependencies = [
[[package]] [[package]]
name = "cosmwasm-derive" name = "cosmwasm-derive"
version = "1.2.5" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c9f7f0e51bfc7295f7b2664fe8513c966428642aa765dad8a74acdab5e0c773" checksum = "dec361f3c09d7b41221948fc17be9b3c96cb58e55a02f82da36f888a651f2584"
dependencies = [ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]] [[package]]
name = "cosmwasm-schema" name = "cosmwasm-schema"
version = "1.2.5" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f00b363610218eea83f24bbab09e1a7c3920b79f068334fdfcc62f6129ef9fc" checksum = "bb6b2fb76758ef59cddc77f2e2ae91c22f77da49037e9f182e9c2833f0e959b1"
dependencies = [ dependencies = [
"cosmwasm-schema-derive", "cosmwasm-schema-derive",
"schemars", "schemars",
@@ -680,9 +686,9 @@ dependencies = [
[[package]] [[package]]
name = "cosmwasm-schema-derive" name = "cosmwasm-schema-derive"
version = "1.2.5" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae38f909b2822d32b275c9e2db9728497aa33ffe67dd463bc67c6a3b7092785c" checksum = "2bfa39422f0d9f1c9a6fd3711573258495314dfa3aae738ea825ecd9964bc659"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -691,11 +697,12 @@ dependencies = [
[[package]] [[package]]
name = "cosmwasm-std" name = "cosmwasm-std"
version = "1.2.5" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a49b85345e811c8e80ec55d0d091e4fcb4f00f97ab058f9be5f614c444a730cb" checksum = "1f6dc2ee23313add5ecacc3ccac217b9967ad9d2d11bd56e5da6aa65a9da6138"
dependencies = [ dependencies = [
"base64 0.13.1", "base64 0.13.1",
"bnum",
"cosmwasm-crypto", "cosmwasm-crypto",
"cosmwasm-derive", "cosmwasm-derive",
"derivative", "derivative",
@@ -703,10 +710,9 @@ dependencies = [
"hex", "hex",
"schemars", "schemars",
"serde", "serde",
"serde-json-wasm 0.5.1", "serde-json-wasm",
"sha2 0.10.6", "sha2 0.10.6",
"thiserror", "thiserror",
"uint",
] ]
[[package]] [[package]]
@@ -810,12 +816,6 @@ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
] ]
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]] [[package]]
name = "crypto-bigint" name = "crypto-bigint"
version = "0.4.9" version = "0.4.9"
@@ -927,9 +927,9 @@ dependencies = [
[[package]] [[package]]
name = "cw-controllers" name = "cw-controllers"
version = "1.0.1" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91440ce8ec4f0642798bc8c8cb6b9b53c1926c6dadaf0eed267a5145cd529071" checksum = "d5d8edce4b78785f36413f67387e4be7d0cb7d032b5d4164bcc024f9c3f3f2ea"
dependencies = [ dependencies = [
"cosmwasm-schema", "cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
@@ -942,9 +942,9 @@ dependencies = [
[[package]] [[package]]
name = "cw-storage-plus" name = "cw-storage-plus"
version = "1.0.1" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053a5083c258acd68386734f428a5a171b29f7d733151ae83090c6fcc9417ffa" checksum = "3f0e92a069d62067f3472c62e30adedb4cab1754725c0f2a682b3128d2bf3c79"
dependencies = [ dependencies = [
"cosmwasm-std", "cosmwasm-std",
"schemars", "schemars",
@@ -968,15 +968,16 @@ dependencies = [
[[package]] [[package]]
name = "cw2" name = "cw2"
version = "1.0.1" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fb70cee2cf0b4a8ff7253e6bc6647107905e8eb37208f87d54f67810faa62f8" checksum = "29ac2dc7a55ad64173ca1e0a46697c31b7a5c51342f55a1e84a724da4eb99908"
dependencies = [ dependencies = [
"cosmwasm-schema", "cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"cw-storage-plus", "cw-storage-plus",
"schemars", "schemars",
"serde", "serde",
"thiserror",
] ]
[[package]] [[package]]
@@ -994,9 +995,9 @@ dependencies = [
[[package]] [[package]]
name = "cw3" name = "cw3"
version = "1.0.1" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fe0b587008aa221cd2a2579a21990a28c4347dc53ad43167c68ad765f5b6efa" checksum = "171af3d9127de6805a7dd819fb070c7d2f6c3ea85f4193f42cef259f0a7f33d5"
dependencies = [ dependencies = [
"cosmwasm-schema", "cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
@@ -1009,9 +1010,9 @@ dependencies = [
[[package]] [[package]]
name = "cw4" name = "cw4"
version = "1.0.1" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c236e0bae02ce97e89235a681dd0e07d099524b369f1ef908d704db3e6b049b" checksum = "a398696307efadaaa2d0850076f865fa706c959d493cb4203314f72be6b77a64"
dependencies = [ dependencies = [
"cosmwasm-schema", "cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
@@ -1539,7 +1540,7 @@ checksum = "a604f7a68fbf8103337523b1fadc8ade7361ee3f112f7c680ad179651616aed5"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"lock_api", "lock_api",
"parking_lot", "parking_lot 0.11.2",
] ]
[[package]] [[package]]
@@ -2114,9 +2115,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"js-sys",
"wasm-bindgen",
"web-sys",
] ]
[[package]] [[package]]
@@ -2477,6 +2475,7 @@ dependencies = [
"nym-config", "nym-config",
"nym-credential-storage", "nym-credential-storage",
"nym-crypto", "nym-crypto",
"nym-explorer-api-requests",
"nym-gateway-client", "nym-gateway-client",
"nym-gateway-requests", "nym-gateway-requests",
"nym-network-defaults", "nym-network-defaults",
@@ -2487,6 +2486,7 @@ dependencies = [
"nym-topology", "nym-topology",
"nym-validator-client", "nym-validator-client",
"rand 0.7.3", "rand 0.7.3",
"reqwest",
"serde", "serde",
"serde_json", "serde_json",
"sha2 0.10.6", "sha2 0.10.6",
@@ -2501,8 +2501,8 @@ dependencies = [
"url", "url",
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"wasm-timer",
"wasm-utils", "wasm-utils",
"wasmtimer",
"zeroize", "zeroize",
] ]
@@ -2539,8 +2539,8 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"wasm-bindgen-test", "wasm-bindgen-test",
"wasm-timer",
"wasm-utils", "wasm-utils",
"wasmtimer",
"wee_alloc", "wee_alloc",
"zeroize", "zeroize",
] ]
@@ -2569,22 +2569,20 @@ dependencies = [
name = "nym-coconut-bandwidth-contract-common" name = "nym-coconut-bandwidth-contract-common"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"nym-multisig-contract-common", "nym-multisig-contract-common",
"schemars",
"serde",
] ]
[[package]] [[package]]
name = "nym-coconut-dkg-common" name = "nym-coconut-dkg-common"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"cw-utils", "cw-utils",
"nym-contracts-common", "nym-contracts-common",
"nym-multisig-contract-common", "nym-multisig-contract-common",
"schemars",
"serde",
] ]
[[package]] [[package]]
@@ -2616,6 +2614,7 @@ name = "nym-contracts-common"
version = "0.5.0" version = "0.5.0"
dependencies = [ dependencies = [
"bs58 0.4.0", "bs58 0.4.0",
"cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"schemars", "schemars",
"serde", "serde",
@@ -2692,6 +2691,17 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "nym-explorer-api-requests"
version = "0.1.0"
dependencies = [
"nym-contracts-common",
"nym-mixnet-contract-common",
"nym-validator-client",
"schemars",
"serde",
]
[[package]] [[package]]
name = "nym-gateway-client" name = "nym-gateway-client"
version = "0.1.0" version = "0.1.0"
@@ -2719,8 +2729,8 @@ dependencies = [
"url", "url",
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"wasm-timer",
"wasm-utils", "wasm-utils",
"wasmtimer",
] ]
[[package]] [[package]]
@@ -2760,13 +2770,14 @@ name = "nym-mixnet-contract-common"
version = "0.6.0" version = "0.6.0"
dependencies = [ dependencies = [
"bs58 0.4.0", "bs58 0.4.0",
"cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"humantime-serde", "humantime-serde",
"log", "log",
"nym-contracts-common", "nym-contracts-common",
"schemars", "schemars",
"serde", "serde",
"serde-json-wasm 0.4.1", "serde-json-wasm",
"serde_repr", "serde_repr",
"thiserror", "thiserror",
"time", "time",
@@ -2791,11 +2802,11 @@ dependencies = [
name = "nym-name-service-common" name = "nym-name-service-common"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"cw-controllers", "cw-controllers",
"cw-utils", "cw-utils",
"nym-contracts-common", "nym-contracts-common",
"schemars",
"serde", "serde",
"thiserror", "thiserror",
] ]
@@ -2836,12 +2847,10 @@ dependencies = [
name = "nym-nonexhaustive-delayqueue" name = "nym-nonexhaustive-delayqueue"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"futures-core",
"slab",
"tokio", "tokio",
"tokio-stream", "tokio-stream",
"tokio-util", "tokio-util",
"wasm-timer", "wasmtimer",
] ]
[[package]] [[package]]
@@ -2872,12 +2881,11 @@ dependencies = [
name = "nym-service-provider-directory-common" name = "nym-service-provider-directory-common"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"cw-controllers", "cw-controllers",
"cw-utils", "cw-utils",
"nym-contracts-common", "nym-contracts-common",
"schemars",
"serde",
"thiserror", "thiserror",
] ]
@@ -3101,7 +3109,6 @@ dependencies = [
"nym-name-service-common", "nym-name-service-common",
"nym-network-defaults", "nym-network-defaults",
"nym-service-provider-directory-common", "nym-service-provider-directory-common",
"nym-vesting-contract",
"nym-vesting-contract-common", "nym-vesting-contract-common",
"openssl", "openssl",
"prost", "prost",
@@ -3116,33 +3123,16 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "nym-vesting-contract"
version = "1.4.0"
dependencies = [
"cosmwasm-derive",
"cosmwasm-std",
"cw-storage-plus",
"cw2",
"nym-contracts-common",
"nym-mixnet-contract-common",
"nym-vesting-contract-common",
"schemars",
"semver 1.0.17",
"serde",
"thiserror",
"vergen",
]
[[package]] [[package]]
name = "nym-vesting-contract-common" name = "nym-vesting-contract-common"
version = "0.7.0" version = "0.7.0"
dependencies = [ dependencies = [
"cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"nym-contracts-common", "nym-contracts-common",
"nym-mixnet-contract-common", "nym-mixnet-contract-common",
"schemars",
"serde", "serde",
"thiserror",
] ]
[[package]] [[package]]
@@ -3252,6 +3242,16 @@ dependencies = [
"parking_lot_core 0.8.6", "parking_lot_core 0.8.6",
] ]
[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core 0.9.7",
]
[[package]] [[package]]
name = "parking_lot_core" name = "parking_lot_core"
version = "0.8.6" version = "0.8.6"
@@ -4056,18 +4056,9 @@ dependencies = [
[[package]] [[package]]
name = "serde-json-wasm" name = "serde-json-wasm"
version = "0.4.1" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479b4dbc401ca13ee8ce902851b834893251404c4f3c65370a49e047a6be09a5" checksum = "a15bee9b04dd165c3f4e142628982ddde884c2022a89e8ddf99c4829bf2c3a58"
dependencies = [
"serde",
]
[[package]]
name = "serde-json-wasm"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16a62a1fad1e1828b24acac8f2b468971dade7b8c3c2e672bcadefefb1f8c137"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@@ -4511,12 +4502,6 @@ dependencies = [
"tokio-rustls 0.23.4", "tokio-rustls 0.23.4",
] ]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]] [[package]]
name = "stringprep" name = "stringprep"
version = "0.1.2" version = "0.1.2"
@@ -4979,18 +4964,6 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
[[package]]
name = "uint"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52"
dependencies = [
"byteorder",
"crunchy",
"hex",
"static_assertions",
]
[[package]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"
version = "0.3.13" version = "0.3.13"
@@ -5233,20 +5206,6 @@ dependencies = [
"quote", "quote",
] ]
[[package]]
name = "wasm-timer"
version = "0.2.5"
source = "git+https://github.com/mmsinclair/wasm-timer?rev=b9d1a54ad514c2f230a026afe0dde341e98cd7b6#b9d1a54ad514c2f230a026afe0dde341e98cd7b6"
dependencies = [
"futures",
"js-sys",
"parking_lot",
"pin-utils",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]] [[package]]
name = "wasm-utils" name = "wasm-utils"
version = "0.1.0" version = "0.1.0"
@@ -5265,6 +5224,20 @@ dependencies = [
"web-sys", "web-sys",
] ]
[[package]]
name = "wasmtimer"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f656cd8858a5164932d8a90f936700860976ec21eb00e0fe2aa8cab13f6b4cf"
dependencies = [
"futures",
"js-sys",
"parking_lot 0.12.1",
"pin-utils",
"slab",
"wasm-bindgen",
]
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.60" version = "0.3.60"
+1 -1
View File
@@ -33,7 +33,7 @@ wasm-bindgen-futures = "0.4"
thiserror = "1.0.40" thiserror = "1.0.40"
zeroize = "1.6.0" zeroize = "1.6.0"
wasm-timer = { git = "https://github.com/mmsinclair/wasm-timer", rev = "b9d1a54ad514c2f230a026afe0dde341e98cd7b6"} wasmtimer = { version = "0.2.0", features = ["tokio"] }
# internal # internal
nym-node-tester-utils = { path = "../../common/node-tester-utils" } nym-node-tester-utils = { path = "../../common/node-tester-utils" }
+1
View File
@@ -246,6 +246,7 @@ impl From<TopologyWasm> for ConfigTopology {
topology.topology_resolution_timeout_ms, topology.topology_resolution_timeout_ms,
), ),
disable_refreshing: topology.disable_refreshing, disable_refreshing: topology.disable_refreshing,
topology_structure: Default::default(),
} }
} }
} }
@@ -10,6 +10,7 @@ use std::collections::HashSet;
use std::time::Duration; use std::time::Duration;
use tokio::sync::MutexGuard as AsyncMutexGuard; use tokio::sync::MutexGuard as AsyncMutexGuard;
use wasm_utils::{console_error, console_log, console_warn}; use wasm_utils::{console_error, console_log, console_warn};
use wasmtimer::tokio::sleep;
pub(crate) struct EphemeralTestReceiver<'a> { pub(crate) struct EphemeralTestReceiver<'a> {
sent_packets: u32, sent_packets: u32,
@@ -90,7 +91,7 @@ impl<'a> EphemeralTestReceiver<'a> {
} }
pub(crate) async fn perform_test(mut self) -> NodeTestResult { pub(crate) async fn perform_test(mut self) -> NodeTestResult {
let mut timeout_fut = wasm_timer::Delay::new(self.timeout_duration); let mut timeout_fut = sleep(self.timeout_duration);
loop { loop {
tokio::select! { tokio::select! {
+70 -29
View File
@@ -5,9 +5,13 @@
// and be used by our smart contracts // and be used by our smart contracts
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
#[derive(Debug)] #[derive(Debug)]
pub struct BinaryBuildInformation { pub struct BinaryBuildInformation {
/// Provides the name of the binary, i.e. the content of `CARGO_PKG_NAME` environmental variable.
pub binary_name: &'static str,
// VERGEN_BUILD_TIMESTAMP // VERGEN_BUILD_TIMESTAMP
/// Provides the build timestamp, for example `2021-02-23T20:14:46.558472672+00:00`. /// Provides the build timestamp, for example `2021-02-23T20:14:46.558472672+00:00`.
pub build_timestamp: &'static str, pub build_timestamp: &'static str,
@@ -43,8 +47,9 @@ pub struct BinaryBuildInformation {
impl BinaryBuildInformation { impl BinaryBuildInformation {
// explicitly require the build_version to be passed as it's binary specific // explicitly require the build_version to be passed as it's binary specific
pub const fn new(build_version: &'static str) -> Self { pub const fn new(binary_name: &'static str, build_version: &'static str) -> Self {
BinaryBuildInformation { BinaryBuildInformation {
binary_name,
build_timestamp: env!("VERGEN_BUILD_TIMESTAMP"), build_timestamp: env!("VERGEN_BUILD_TIMESTAMP"),
build_version, build_version,
commit_sha: env!("VERGEN_GIT_SHA"), commit_sha: env!("VERGEN_GIT_SHA"),
@@ -58,6 +63,7 @@ impl BinaryBuildInformation {
pub fn to_owned(&self) -> BinaryBuildInformationOwned { pub fn to_owned(&self) -> BinaryBuildInformationOwned {
BinaryBuildInformationOwned { BinaryBuildInformationOwned {
binary_name: self.binary_name.to_owned(),
build_timestamp: self.build_timestamp.to_owned(), build_timestamp: self.build_timestamp.to_owned(),
build_version: self.build_version.to_owned(), build_version: self.build_version.to_owned(),
commit_sha: self.commit_sha.to_owned(), commit_sha: self.commit_sha.to_owned(),
@@ -70,39 +76,15 @@ impl BinaryBuildInformation {
} }
pub fn pretty_print(&self) -> String { pub fn pretty_print(&self) -> String {
format!( self.to_owned().to_string()
r#"
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
"#,
"Build Timestamp:",
self.build_timestamp,
"Build Version:",
self.build_version,
"Commit SHA:",
self.commit_sha,
"Commit Date:",
self.commit_timestamp,
"Commit Branch:",
self.commit_branch,
"rustc Version:",
self.rustc_version,
"rustc Channel:",
self.rustc_channel,
"cargo Profile:",
self.cargo_profile,
)
} }
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct BinaryBuildInformationOwned { pub struct BinaryBuildInformationOwned {
/// Provides the name of the binary, i.e. the content of `CARGO_PKG_NAME` environmental variable.
pub binary_name: String,
// VERGEN_BUILD_TIMESTAMP // VERGEN_BUILD_TIMESTAMP
/// Provides the build timestamp, for example `2021-02-23T20:14:46.558472672+00:00`. /// Provides the build timestamp, for example `2021-02-23T20:14:46.558472672+00:00`.
pub build_timestamp: String, pub build_timestamp: String,
@@ -135,3 +117,62 @@ pub struct BinaryBuildInformationOwned {
/// Provides the cargo profile that was used for the build, for example `debug`. /// Provides the cargo profile that was used for the build, for example `debug`.
pub cargo_profile: String, pub cargo_profile: String,
} }
impl Display for BinaryBuildInformationOwned {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
r#"
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
"#,
"Binary Name:",
self.binary_name,
"Build Timestamp:",
self.build_timestamp,
"Build Version:",
self.build_version,
"Commit SHA:",
self.commit_sha,
"Commit Date:",
self.commit_timestamp,
"Commit Branch:",
self.commit_branch,
"rustc Version:",
self.rustc_version,
"rustc Channel:",
self.rustc_channel,
"cargo Profile:",
self.cargo_profile,
)
}
}
// since this macro will get expanded at the callsite, it will pull in correct binary version
#[macro_export]
macro_rules! bin_info {
() => {
$crate::build_information::BinaryBuildInformation::new(
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION"),
)
};
}
#[macro_export]
macro_rules! bin_info_owned {
() => {
$crate::build_information::BinaryBuildInformation::new(
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION"),
)
.to_owned()
};
}
+9 -7
View File
@@ -10,27 +10,29 @@ rust-version = "1.66"
[dependencies] [dependencies]
async-trait = { workspace = true } async-trait = { workspace = true }
base64 = "0.21.2" base64 = "0.21.2"
dirs = "4.0"
dashmap = "5.4.0" dashmap = "5.4.0"
dirs = "4.0"
futures = "0.3" futures = "0.3"
humantime-serde = "1.0" humantime-serde = "1.0"
log = { workspace = true } log = { workspace = true }
rand = { version = "0.7.3", features = ["wasm-bindgen"] } rand = { version = "0.7.3", features = ["wasm-bindgen"] }
reqwest = { workspace = true }
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true } serde_json = { workspace = true }
sha2 = "0.10.6" sha2 = "0.10.6"
tap = "1.0.1" tap = "1.0.1"
thiserror = "1.0.34" thiserror = "1.0.34"
url = { version ="2.2", features = ["serde"] }
tungstenite = { version = "0.13.0", default-features = false }
tokio = { version = "1.24.1", features = ["macros"]}
time = "0.3.17" time = "0.3.17"
tokio = { version = "1.24.1", features = ["macros"]}
tungstenite = { version = "0.13.0", default-features = false }
url = { version ="2.2", features = ["serde"] }
zeroize = { workspace = true } zeroize = { workspace = true }
# internal # internal
nym-bandwidth-controller = { path = "../bandwidth-controller" } nym-bandwidth-controller = { path = "../bandwidth-controller" }
nym-config = { path = "../config" } nym-config = { path = "../config" }
nym-crypto = { path = "../crypto" } nym-crypto = { path = "../crypto" }
nym-explorer-api-requests = { path = "../../explorer-api/explorer-api-requests" }
nym-gateway-client = { path = "../client-libs/gateway-client" } nym-gateway-client = { path = "../client-libs/gateway-client" }
#gateway-client = { path = "../../common/client-libs/gateway-client", default-features = false, features = ["wasm", "coconut"] } #gateway-client = { path = "../../common/client-libs/gateway-client", default-features = false, features = ["wasm", "coconut"] }
nym-gateway-requests = { path = "../../gateway/gateway-requests" } nym-gateway-requests = { path = "../../gateway/gateway-requests" }
@@ -69,9 +71,9 @@ version = "0.4"
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen] [target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen]
version = "0.2.83" version = "0.2.83"
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-timer] [target."cfg(target_arch = \"wasm32\")".dependencies.wasmtimer]
git = "https://github.com/mmsinclair/wasm-timer" workspace = true
rev = "b9d1a54ad514c2f230a026afe0dde341e98cd7b6" features = ["tokio"]
[target."cfg(target_arch = \"wasm32\")".dependencies.gloo-timers] [target."cfg(target_arch = \"wasm32\")".dependencies.gloo-timers]
version = "0.2.4" version = "0.2.4"
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use super::received_buffer::ReceivedBufferMessage; use super::received_buffer::ReceivedBufferMessage;
use super::topology_control::geo_aware_provider::GeoAwareTopologyProvider;
use crate::client::base_client::storage::MixnetClientStorage; use crate::client::base_client::storage::MixnetClientStorage;
use crate::client::cover_traffic_stream::LoopCoverTrafficStream; use crate::client::cover_traffic_stream::LoopCoverTrafficStream;
use crate::client::inbound_messages::{InputMessage, InputMessageReceiver, InputMessageSender}; use crate::client::inbound_messages::{InputMessage, InputMessageReceiver, InputMessageSender};
@@ -339,14 +340,20 @@ where
fn setup_topology_provider( fn setup_topology_provider(
custom_provider: Option<Box<dyn TopologyProvider + Send + Sync>>, custom_provider: Option<Box<dyn TopologyProvider + Send + Sync>>,
provider_from_config: config::TopologyStructure,
nym_api_urls: Vec<Url>, nym_api_urls: Vec<Url>,
) -> Box<dyn TopologyProvider + Send + Sync> { ) -> Box<dyn TopologyProvider + Send + Sync> {
// if no custom provider was ... provided ..., create one using nym-api // if no custom provider was ... provided ..., create one using nym-api
custom_provider.unwrap_or_else(|| { custom_provider.unwrap_or_else(|| match provider_from_config {
Box::new(NymApiTopologyProvider::new( config::TopologyStructure::NymApi => Box::new(NymApiTopologyProvider::new(
nym_api_urls, nym_api_urls,
env!("CARGO_PKG_VERSION").to_string(), env!("CARGO_PKG_VERSION").to_string(),
)) )),
config::TopologyStructure::GeoAware(group) => Box::new(GeoAwareTopologyProvider::new(
nym_api_urls,
env!("CARGO_PKG_VERSION").to_string(),
group,
)),
}) })
} }
@@ -521,8 +528,10 @@ where
let topology_provider = Self::setup_topology_provider( let topology_provider = Self::setup_topology_provider(
self.custom_topology_provider.take(), self.custom_topology_provider.take(),
self.config.debug.topology.topology_structure,
self.config.get_nym_api_endpoints(), self.config.get_nym_api_endpoints(),
); );
Self::start_topology_refresher( Self::start_topology_refresher(
topology_provider, topology_provider,
self.config.debug.topology, self.config.debug.topology,
@@ -19,10 +19,10 @@ use std::time::Duration;
use tokio::sync::mpsc::error::TrySendError; use tokio::sync::mpsc::error::TrySendError;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use tokio::time; use tokio::time::{sleep, Sleep};
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use wasm_timer; use wasmtimer::tokio::{sleep, Sleep};
pub struct LoopCoverTrafficStream<R> pub struct LoopCoverTrafficStream<R>
where where
@@ -39,11 +39,7 @@ where
/// Internal state, determined by `average_message_sending_delay`, /// Internal state, determined by `average_message_sending_delay`,
/// used to keep track of when a next packet should be sent out. /// used to keep track of when a next packet should be sent out.
#[cfg(not(target_arch = "wasm32"))] next_delay: Pin<Box<Sleep>>,
next_delay: Pin<Box<time::Sleep>>,
#[cfg(target_arch = "wasm32")]
next_delay: Pin<Box<wasm_timer::Delay>>,
/// Channel used for sending prepared nym packets to `MixTrafficController` that sends them /// Channel used for sending prepared nym packets to `MixTrafficController` that sends them
/// out to the network without any further delays. /// out to the network without any further delays.
@@ -90,17 +86,9 @@ where
// The next interval value is `next_poisson_delay` after the one that just // The next interval value is `next_poisson_delay` after the one that just
// yielded. // yielded.
#[cfg(not(target_arch = "wasm32"))] let now = self.next_delay.deadline();
{ let next = now + next_poisson_delay;
let now = self.next_delay.deadline(); self.next_delay.as_mut().reset(next);
let next = now + next_poisson_delay;
self.next_delay.as_mut().reset(next);
}
#[cfg(target_arch = "wasm32")]
{
self.next_delay.as_mut().reset(next_poisson_delay);
}
Poll::Ready(Some(())) Poll::Ready(Some(()))
} }
@@ -120,11 +108,7 @@ impl LoopCoverTrafficStream<OsRng> {
) -> Self { ) -> Self {
let rng = OsRng; let rng = OsRng;
#[cfg(not(target_arch = "wasm32"))] let next_delay = Box::pin(sleep(Default::default()));
let next_delay = Box::pin(time::sleep(Default::default()));
#[cfg(target_arch = "wasm32")]
let next_delay = Box::pin(wasm_timer::Delay::new(Default::default()));
LoopCoverTrafficStream { LoopCoverTrafficStream {
ack_key, ack_key,
@@ -142,12 +126,7 @@ impl LoopCoverTrafficStream<OsRng> {
} }
fn set_next_delay(&mut self, amount: Duration) { fn set_next_delay(&mut self, amount: Duration) {
#[cfg(not(target_arch = "wasm32"))] let next_delay = Box::pin(sleep(amount));
let next_delay = Box::pin(time::sleep(amount));
#[cfg(target_arch = "wasm32")]
let next_delay = Box::pin(wasm_timer::Delay::new(amount));
self.next_delay = next_delay; self.next_delay = next_delay;
} }
@@ -2,13 +2,12 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use std::time::Duration; use std::time::Duration;
use wasm_timer;
pub use wasm_timer::*; pub use wasmtimer::{std::Instant, tokio::*};
pub type IntervalStream = gloo_timers::future::IntervalStream; pub type IntervalStream = gloo_timers::future::IntervalStream;
pub(crate) fn get_time_now() -> Instant { pub(crate) fn get_time_now() -> Instant {
wasm_timer::Instant::now() Instant::now()
} }
pub(crate) fn new_interval_stream(polling_rate: Duration) -> IntervalStream { pub(crate) fn new_interval_stream(polling_rate: Duration) -> IntervalStream {
@@ -27,9 +27,10 @@ use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use tokio::time; use tokio::time::{sleep, Sleep};
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use wasm_timer; use wasmtimer::tokio::{sleep, Sleep};
mod sending_delay_controller; mod sending_delay_controller;
@@ -82,11 +83,7 @@ where
/// Internal state, determined by `average_message_sending_delay`, /// Internal state, determined by `average_message_sending_delay`,
/// used to keep track of when a next packet should be sent out. /// used to keep track of when a next packet should be sent out.
#[cfg(not(target_arch = "wasm32"))] next_delay: Option<Pin<Box<Sleep>>>,
next_delay: Option<Pin<Box<time::Sleep>>>,
#[cfg(target_arch = "wasm32")]
next_delay: Option<Pin<Box<wasm_timer::Delay>>>,
// To make sure we don't overload the mix_tx channel, we limit the rate we are pushing // To make sure we don't overload the mix_tx channel, we limit the rate we are pushing
// messages. // messages.
@@ -373,17 +370,9 @@ where
// The next interval value is `next_poisson_delay` after the one that just // The next interval value is `next_poisson_delay` after the one that just
// yielded. // yielded.
#[cfg(not(target_arch = "wasm32"))] let now = next_delay.deadline();
{ let next = now + next_poisson_delay;
let now = next_delay.deadline(); next_delay.as_mut().reset(next);
let next = now + next_poisson_delay;
next_delay.as_mut().reset(next);
}
#[cfg(target_arch = "wasm32")]
{
next_delay.as_mut().reset(next_poisson_delay);
}
// On every iteration we get new messages from upstream. Given that these come bunched // On every iteration we get new messages from upstream. Given that these come bunched
// in `Vec`, this ensures that on average we will fetch messages faster than we can // in `Vec`, this ensures that on average we will fetch messages faster than we can
@@ -421,12 +410,7 @@ where
self.config.traffic.message_sending_average_delay, self.config.traffic.message_sending_average_delay,
); );
#[cfg(not(target_arch = "wasm32"))] let next_delay = Box::pin(sleep(sampled));
let next_delay = Box::pin(time::sleep(sampled));
#[cfg(target_arch = "wasm32")]
let next_delay = Box::pin(wasm_timer::Delay::new(sampled));
self.next_delay = Some(next_delay); self.next_delay = Some(next_delay);
Poll::Pending Poll::Pending
@@ -0,0 +1,319 @@
use std::{collections::HashMap, fmt};
use log::{debug, error, info};
use nym_explorer_api_requests::PrettyDetailedMixNodeBond;
use nym_topology::{
nym_topology_from_detailed,
provider_trait::{async_trait, TopologyProvider},
NymTopology,
};
use nym_validator_client::client::MixId;
use rand::{prelude::SliceRandom, thread_rng};
use serde::{Deserialize, Serialize};
use url::Url;
const MIN_NODES_PER_LAYER: usize = 1;
const EXPLORER_API_MIXNODES_URL: &str = "https://explorer.nymtech.net/api/v1/mix-nodes";
// TODO: create a explorer-api-client
async fn fetch_mixnodes_from_explorer_api() -> Option<Vec<PrettyDetailedMixNodeBond>> {
reqwest::get(EXPLORER_API_MIXNODES_URL)
.await
.ok()?
.json::<Vec<PrettyDetailedMixNodeBond>>()
.await
.ok()
}
#[derive(Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub enum CountryGroup {
Europe,
NorthAmerica,
SouthAmerica,
Oceania,
Asia,
Africa,
Unknown,
}
impl CountryGroup {
// We map contry codes into group, which initially are continent codes to a first approximation,
// but we do it manually to reserve the right to tweak this distribution for our purposes.
fn new(country_code: &str) -> Self {
let country_code = country_code.to_uppercase();
use CountryGroup::*;
match country_code.as_ref() {
// Europe
"AT" => Europe,
"BG" => Europe,
"CH" => Europe,
"CY" => Europe,
"CZ" => Europe,
"DE" => Europe,
"DK" => Europe,
"ES" => Europe,
"FI" => Europe,
"FR" => Europe,
"GB" => Europe,
"GR" => Europe,
"IE" => Europe,
"IT" => Europe,
"LT" => Europe,
"LU" => Europe,
"LV" => Europe,
"MD" => Europe,
"MT" => Europe,
"NL" => Europe,
"NO" => Europe,
"PL" => Europe,
"RO" => Europe,
"SE" => Europe,
"SK" => Europe,
"TR" => Europe,
"UA" => Europe,
// North America
"CA" => NorthAmerica,
"MX" => NorthAmerica,
"US" => NorthAmerica,
// South America
"AR" => SouthAmerica,
"BR" => SouthAmerica,
"CL" => SouthAmerica,
"CO" => SouthAmerica,
"CR" => SouthAmerica,
"GT" => SouthAmerica,
// Oceania
"AU" => Oceania,
// Asia
"AM" => Asia,
"BH" => Asia,
"CN" => Asia,
"GE" => Asia,
"HK" => Asia,
"ID" => Asia,
"IL" => Asia,
"IN" => Asia,
"JP" => Asia,
"KH" => Asia,
"KR" => Asia,
"KZ" => Asia,
"MY" => Asia,
"RU" => Asia,
"SG" => Asia,
"TH" => Asia,
"VN" => Asia,
// Africa
"SC" => Africa,
"UG" => Africa,
"ZA" => Africa,
// And group level codes work too
"EU" => Europe,
"NA" => NorthAmerica,
"SA" => SouthAmerica,
"OC" => Oceania,
"AS" => Asia,
"AF" => Africa,
// And some aliases
"EUROPE" => Europe,
"NORTHAMERICA" => NorthAmerica,
"SOUTHAMERICA" => SouthAmerica,
"OCEANIA" => Oceania,
"ASIA" => Asia,
"AFRICA" => Africa,
_ => {
info!("Unknown country code: {}", country_code);
Unknown
}
}
}
}
impl fmt::Display for CountryGroup {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use CountryGroup::*;
match self {
Europe => write!(f, "EU"),
NorthAmerica => write!(f, "NA"),
SouthAmerica => write!(f, "SA"),
Oceania => write!(f, "OC"),
Asia => write!(f, "AS"),
Africa => write!(f, "AF"),
Unknown => write!(f, "Unknown"),
}
}
}
impl std::str::FromStr for CountryGroup {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
let group = CountryGroup::new(s);
if group == CountryGroup::Unknown {
Err(())
} else {
Ok(group)
}
}
}
impl CountryGroup {
#[allow(unused)]
fn known(self) -> Option<CountryGroup> {
use CountryGroup::*;
match self {
Europe | NorthAmerica | SouthAmerica | Oceania | Asia | Africa => Some(self),
Unknown => None,
}
}
}
fn group_mixnodes_by_country_code(
mixnodes: Vec<PrettyDetailedMixNodeBond>,
) -> HashMap<CountryGroup, Vec<MixId>> {
mixnodes
.into_iter()
.fold(HashMap::<CountryGroup, Vec<MixId>>::new(), |mut acc, m| {
if let Some(ref location) = m.location {
let country_code = location.two_letter_iso_country_code.clone();
let group_code = CountryGroup::new(country_code.as_str());
let mixnodes = acc.entry(group_code).or_insert_with(Vec::new);
mixnodes.push(m.mix_id);
}
acc
})
}
fn log_mixnode_distribution(mixnodes: &HashMap<CountryGroup, Vec<MixId>>) {
let mixnode_distribution = mixnodes
.iter()
.map(|(k, v)| format!("{}: {}", k, v.len()))
.collect::<Vec<_>>()
.join(", ");
debug!("Mixnode distribution - {}", mixnode_distribution);
}
fn check_layer_integrity(topology: NymTopology) -> Result<(), ()> {
let mixes = topology.mixes();
if mixes.keys().len() < 3 {
error!("Layer is missing in topology!");
return Err(());
}
for (layer, mixnodes) in mixes {
debug!("Layer {:?} has {} mixnodes", layer, mixnodes.len());
if mixnodes.len() < MIN_NODES_PER_LAYER {
error!(
"There are only {} mixnodes in layer {:?}",
mixnodes.len(),
layer
);
return Err(());
}
}
Ok(())
}
pub struct GeoAwareTopologyProvider {
validator_client: nym_validator_client::client::NymApiClient,
filter_on: CountryGroup,
client_version: String,
}
impl GeoAwareTopologyProvider {
pub fn new(
mut nym_api_urls: Vec<Url>,
client_version: String,
filter_on: CountryGroup,
) -> GeoAwareTopologyProvider {
log::info!(
"Creating geo-aware topology provider with filter on {:?}",
filter_on
);
nym_api_urls.shuffle(&mut thread_rng());
GeoAwareTopologyProvider {
validator_client: nym_validator_client::client::NymApiClient::new(
nym_api_urls[0].clone(),
),
filter_on,
client_version,
}
}
async fn get_topology(&self) -> Option<NymTopology> {
let mixnodes = match self.validator_client.get_cached_active_mixnodes().await {
Err(err) => {
error!("failed to get network mixnodes - {err}");
return None;
}
Ok(mixes) => mixes,
};
let gateways = match self.validator_client.get_cached_gateways().await {
Err(err) => {
error!("failed to get network gateways - {err}");
return None;
}
Ok(gateways) => gateways,
};
// Also fetch mixnodes cached by explorer-api, with the purpose of getting their
// geolocation.
debug!("Fetching mixnodes from explorer-api...");
let Some(mixnodes_from_explorer_api) = fetch_mixnodes_from_explorer_api().await else {
error!("failed to get mixnodes from explorer-api");
return None;
};
// Partition mixnodes_from_explorer_api according to the value of
// two_letter_iso_country_code.
// NOTE: we construct the full distribution here, but only use the one we're interested in.
// The reason we this instead of a straight filter is that this opens up the possibility to
// complement a small grouping with mixnodes from adjecent countries.
let mixnode_distribution = group_mixnodes_by_country_code(mixnodes_from_explorer_api);
log_mixnode_distribution(&mixnode_distribution);
let Some(filtered_mixnode_ids) = mixnode_distribution.get(&self.filter_on) else {
error!("no mixnodes found for: {}", self.filter_on);
return None;
};
let mixnodes = mixnodes
.into_iter()
.filter(|m| filtered_mixnode_ids.contains(&m.mix_id()))
.collect::<Vec<_>>();
let topology = nym_topology_from_detailed(mixnodes, gateways)
.filter_system_version(&self.client_version);
// TODO: return real error type
check_layer_integrity(topology.clone()).ok()?;
Some(topology)
}
}
#[cfg(not(target_arch = "wasm32"))]
#[async_trait]
impl TopologyProvider for GeoAwareTopologyProvider {
// this will be manually refreshed on a timer specified inside mixnet client config
async fn get_new_topology(&mut self) -> Option<NymTopology> {
self.get_topology().await
}
}
#[cfg(target_arch = "wasm32")]
#[async_trait(?Send)]
impl TopologyProvider for GeoAwareTopologyProvider {
// this will be manually refreshed on a timer specified inside mixnet client config
async fn get_new_topology(&mut self) -> Option<NymTopology> {
self.get_topology().await
}
}
@@ -10,6 +10,7 @@ use nym_topology::NymTopologyError;
use std::time::Duration; use std::time::Duration;
mod accessor; mod accessor;
pub mod geo_aware_provider;
pub(crate) mod nym_api_provider; pub(crate) mod nym_api_provider;
// TODO: move it to config later // TODO: move it to config later
+21 -1
View File
@@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
use std::time::Duration; use std::time::Duration;
use url::Url; use url::Url;
use crate::error::ClientCoreError; use crate::{client::topology_control::geo_aware_provider::CountryGroup, error::ClientCoreError};
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
@@ -158,6 +158,15 @@ impl Config {
self self
} }
pub fn with_topology_structure(mut self, topology_structure: TopologyStructure) -> Self {
self.set_topology_structure(topology_structure);
self
}
pub fn set_topology_structure(&mut self, topology_structure: TopologyStructure) {
self.debug.topology.topology_structure = topology_structure;
}
pub fn with_no_per_hop_delays(mut self, no_per_hop_delays: bool) -> Self { pub fn with_no_per_hop_delays(mut self, no_per_hop_delays: bool) -> Self {
if no_per_hop_delays { if no_per_hop_delays {
self.set_no_per_hop_delays() self.set_no_per_hop_delays()
@@ -466,6 +475,16 @@ pub struct Topology {
/// the first valid instance. /// the first valid instance.
/// Supersedes `topology_refresh_rate_ms`. /// Supersedes `topology_refresh_rate_ms`.
pub disable_refreshing: bool, pub disable_refreshing: bool,
/// Specifies the mixnode topology to be used for sending packets.
pub topology_structure: TopologyStructure,
}
#[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum TopologyStructure {
#[default]
NymApi,
GeoAware(CountryGroup),
} }
impl Default for Topology { impl Default for Topology {
@@ -474,6 +493,7 @@ impl Default for Topology {
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE, topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT, topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
disable_refreshing: false, disable_refreshing: false,
topology_structure: TopologyStructure::default(),
} }
} }
} }
@@ -267,6 +267,7 @@ impl From<TopologyV1_1_20_2> for Topology {
topology_refresh_rate: value.topology_refresh_rate, topology_refresh_rate: value.topology_refresh_rate,
topology_resolution_timeout: value.topology_resolution_timeout, topology_resolution_timeout: value.topology_resolution_timeout,
disable_refreshing: value.disable_refreshing, disable_refreshing: value.disable_refreshing,
topology_structure: Default::default(),
} }
} }
} }
+7 -9
View File
@@ -27,13 +27,17 @@ use tokio_tungstenite::connect_async;
use tokio_tungstenite::{MaybeTlsStream, WebSocketStream}; use tokio_tungstenite::{MaybeTlsStream, WebSocketStream};
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
type WsConn = WebSocketStream<MaybeTlsStream<TcpStream>>; type WsConn = WebSocketStream<MaybeTlsStream<TcpStream>>;
#[cfg(not(target_arch = "wasm32"))]
use tokio::time::sleep;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use nym_bandwidth_controller::wasm_mockups::DirectSigningNyxdClient; use nym_bandwidth_controller::wasm_mockups::DirectSigningNyxdClient;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use wasm_timer::Instant;
#[cfg(target_arch = "wasm32")]
use wasm_utils::websocket::JSWebsocket; use wasm_utils::websocket::JSWebsocket;
#[cfg(target_arch = "wasm32")]
use wasmtimer::std::Instant;
#[cfg(target_arch = "wasm32")]
use wasmtimer::tokio::sleep;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
type WsConn = JSWebsocket; type WsConn = JSWebsocket;
@@ -125,15 +129,9 @@ async fn measure_latency(gateway: &gateway::Node) -> Result<GatewayWithLatency,
Ok::<(), ClientCoreError>(()) Ok::<(), ClientCoreError>(())
}; };
// thanks to wasm we can't use tokio::time::timeout : ( let timeout = sleep(PING_TIMEOUT);
#[cfg(not(target_arch = "wasm32"))]
let timeout = tokio::time::sleep(PING_TIMEOUT);
#[cfg(not(target_arch = "wasm32"))]
tokio::pin!(timeout); tokio::pin!(timeout);
#[cfg(target_arch = "wasm32")]
let mut timeout = wasm_timer::Delay::new(PING_TIMEOUT);
tokio::select! { tokio::select! {
_ = &mut timeout => { _ = &mut timeout => {
warn!("timed out while trying to perform measurement...") warn!("timed out while trying to perform measurement...")
+3 -3
View File
@@ -58,9 +58,9 @@ path = "../../wasm-utils"
features = ["websocket"] features = ["websocket"]
# only import it in wasm. Prefer proper tokio timer in non-wasm # only import it in wasm. Prefer proper tokio timer in non-wasm
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-timer] [target."cfg(target_arch = \"wasm32\")".dependencies.wasmtimer]
git = "https://github.com/mmsinclair/wasm-timer" workspace = true
rev = "b9d1a54ad514c2f230a026afe0dde341e98cd7b6" features = ["tokio"]
# this is due to tungstenite using `rand` 0.8 and associated changes in `getrandom` crate # this is due to tungstenite using `rand` 0.8 and associated changes in `getrandom` crate
# which now does not support wasm32-unknown-unknown target by default. # which now does not support wasm32-unknown-unknown target by default.
@@ -31,14 +31,16 @@ use tungstenite::protocol::Message;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use nym_validator_client::nyxd::traits::DkgQueryClient; use nym_validator_client::nyxd::traits::DkgQueryClient;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use tokio::time::sleep;
#[cfg(not(target_arch = "wasm32"))]
use tokio_tungstenite::connect_async; use tokio_tungstenite::connect_async;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use nym_bandwidth_controller::wasm_mockups::DkgQueryClient; use nym_bandwidth_controller::wasm_mockups::DkgQueryClient;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use wasm_timer;
#[cfg(target_arch = "wasm32")]
use wasm_utils::websocket::JSWebsocket; use wasm_utils::websocket::JSWebsocket;
#[cfg(target_arch = "wasm32")]
use wasmtimer::tokio::sleep;
const DEFAULT_RECONNECTION_ATTEMPTS: usize = 10; const DEFAULT_RECONNECTION_ATTEMPTS: usize = 10;
const DEFAULT_RECONNECTION_BACKOFF: Duration = Duration::from_secs(5); const DEFAULT_RECONNECTION_BACKOFF: Duration = Duration::from_secs(5);
@@ -198,15 +200,7 @@ impl<C, St> GatewayClient<C, St> {
} }
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
tokio::time::sleep(self.reconnection_backoff).await; sleep(self.reconnection_backoff).await;
#[cfg(target_arch = "wasm32")]
if let Err(err) = wasm_timer::Delay::new(self.reconnection_backoff).await {
error!(
"the timer has gone away while in reconnection backoff! - {}",
err
);
}
} }
// final attempt (done separately to be able to return a proper error) // final attempt (done separately to be able to return a proper error)
@@ -235,16 +229,9 @@ impl<C, St> GatewayClient<C, St> {
_ => return Err(GatewayClientError::ConnectionInInvalidState), _ => return Err(GatewayClientError::ConnectionInInvalidState),
}; };
#[cfg(not(target_arch = "wasm32"))] let timeout = sleep(self.response_timeout_duration);
let timeout = tokio::time::sleep(self.response_timeout_duration);
#[cfg(not(target_arch = "wasm32"))]
tokio::pin!(timeout); tokio::pin!(timeout);
// technically the `wasm_timer` also works outside wasm, but unless required,
// I really prefer to just stick to tokio
#[cfg(target_arch = "wasm32")]
let mut timeout = wasm_timer::Delay::new(self.response_timeout_duration);
loop { loop {
tokio::select! { tokio::select! {
_ = self.shutdown.recv() => { _ = self.shutdown.recv() => {
@@ -20,7 +20,6 @@ nym-multisig-contract-common = { path = "../../cosmwasm-smart-contracts/multisig
nym-name-service-common = { path = "../../cosmwasm-smart-contracts/name-service" } nym-name-service-common = { path = "../../cosmwasm-smart-contracts/name-service" }
nym-group-contract-common = { path = "../../cosmwasm-smart-contracts/group-contract" } nym-group-contract-common = { path = "../../cosmwasm-smart-contracts/group-contract" }
nym-service-provider-directory-common = { path = "../../cosmwasm-smart-contracts/service-provider-directory" } nym-service-provider-directory-common = { path = "../../cosmwasm-smart-contracts/service-provider-directory" }
nym-vesting-contract = { path = "../../../contracts/vesting" }
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true } serde_json = { workspace = true }
reqwest = { version = "0.11", features = ["json"] } reqwest = { version = "0.11", features = ["json"] }
@@ -32,7 +32,7 @@ impl Display for AutoFeeGrant {
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Fee { pub enum Fee {
Manual(#[serde(with = "sealed::TxFee")] tx::Fee), Manual(tx::Fee),
Auto(Option<GasAdjustment>), Auto(Option<GasAdjustment>),
PayerGranterAuto(AutoFeeGrant), PayerGranterAuto(AutoFeeGrant),
} }
@@ -121,58 +121,3 @@ impl GasAdjustable for Gas {
} }
} }
} }
// a workaround to provide serde implementation for tx::Fee. We don't want to ever expose any of those
// types to the public and ideally they will get replaced by proper implementation inside comrs
mod sealed {
use cosmrs::tx::{self};
use cosmrs::{AccountId, Denom as CosmosDenom};
use cosmrs::{Coin as CosmosCoin, Gas};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Serialize, Deserialize, Clone)]
struct Coin {
denom: CosmosDenom,
amount: u128,
}
impl From<Coin> for CosmosCoin {
fn from(val: Coin) -> Self {
CosmosCoin {
denom: val.denom,
amount: val.amount,
}
}
}
impl From<CosmosCoin> for Coin {
fn from(val: CosmosCoin) -> Self {
Coin {
denom: val.denom,
amount: val.amount,
}
}
}
fn coin_vec_ser<S: Serializer>(val: &[CosmosCoin], serializer: S) -> Result<S::Ok, S::Error> {
let vec: Vec<Coin> = val.iter().cloned().map(Into::into).collect();
vec.serialize(serializer)
}
fn coin_vec_deser<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Vec<CosmosCoin>, D::Error> {
let vec: Vec<Coin> = Deserialize::deserialize(deserializer)?;
Ok(vec.iter().cloned().map(Into::into).collect())
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "tx::Fee")]
pub(super) struct TxFee {
#[serde(serialize_with = "coin_vec_ser")]
#[serde(deserialize_with = "coin_vec_deser")]
pub amount: Vec<CosmosCoin>,
pub gas_limit: Gas,
pub payer: Option<AccountId>,
pub granter: Option<AccountId>,
}
}
@@ -8,10 +8,9 @@ use async_trait::async_trait;
use cosmrs::AccountId; use cosmrs::AccountId;
use nym_contracts_common::signing::Nonce; use nym_contracts_common::signing::Nonce;
use nym_mixnet_contract_common::delegation::{MixNodeDelegationResponse, OwnerProxySubKey}; use nym_mixnet_contract_common::delegation::{MixNodeDelegationResponse, OwnerProxySubKey};
use nym_mixnet_contract_common::families::Family;
use nym_mixnet_contract_common::mixnode::{ use nym_mixnet_contract_common::mixnode::{
MixNodeDetails, MixnodeRewardingDetailsResponse, PagedMixnodesDetailsResponse, MixnodeRewardingDetailsResponse, PagedMixnodesDetailsResponse, PagedUnbondedMixnodesResponse,
PagedUnbondedMixnodesResponse, StakeSaturationResponse, UnbondedMixnodeResponse, StakeSaturationResponse, UnbondedMixnodeResponse,
}; };
use nym_mixnet_contract_common::reward_params::{Performance, RewardingParams}; use nym_mixnet_contract_common::reward_params::{Performance, RewardingParams};
use nym_mixnet_contract_common::rewarding::{ use nym_mixnet_contract_common::rewarding::{
@@ -19,14 +18,15 @@ use nym_mixnet_contract_common::rewarding::{
}; };
use nym_mixnet_contract_common::{ use nym_mixnet_contract_common::{
delegation, ContractBuildInformation, ContractState, ContractStateParams, delegation, ContractBuildInformation, ContractState, ContractStateParams,
CurrentIntervalResponse, EpochEventId, EpochStatus, GatewayBondResponse, CurrentIntervalResponse, EpochEventId, EpochStatus, FamilyByHeadResponse,
GatewayOwnershipResponse, IdentityKey, IntervalEventId, LayerDistribution, MixId, FamilyByLabelResponse, FamilyMembersByHeadResponse, FamilyMembersByLabelResponse,
MixOwnershipResponse, MixnodeDetailsResponse, NumberOfPendingEventsResponse, GatewayBondResponse, GatewayOwnershipResponse, IdentityKey, IntervalEventId, LayerDistribution,
PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse, PagedFamiliesResponse, MixId, MixOwnershipResponse, MixnodeDetailsByIdentityResponse, MixnodeDetailsResponse,
PagedGatewayResponse, PagedMembersResponse, PagedMixNodeDelegationsResponse, NumberOfPendingEventsResponse, PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse,
PagedMixnodeBondsResponse, PagedRewardedSetResponse, PendingEpochEventResponse, PagedFamiliesResponse, PagedGatewayResponse, PagedMembersResponse,
PendingEpochEventsResponse, PendingIntervalEventResponse, PendingIntervalEventsResponse, PagedMixNodeDelegationsResponse, PagedMixnodeBondsResponse, PagedRewardedSetResponse,
QueryMsg as MixnetQueryMsg, PendingEpochEventResponse, PendingEpochEventsResponse, PendingIntervalEventResponse,
PendingIntervalEventsResponse, QueryMsg as MixnetQueryMsg,
}; };
use serde::Deserialize; use serde::Deserialize;
@@ -100,6 +100,24 @@ pub trait MixnetQueryClient {
.await .await
} }
async fn get_family_members_by_head<S: Into<String> + Send>(
&self,
head: S,
) -> Result<FamilyMembersByHeadResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetFamilyMembersByHead { head: head.into() })
.await
}
async fn get_family_members_by_label<S: Into<String> + Send>(
&self,
label: S,
) -> Result<FamilyMembersByLabelResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetFamilyMembersByLabel {
label: label.into(),
})
.await
}
// mixnode-related: // mixnode-related:
async fn get_mixnode_bonds_paged( async fn get_mixnode_bonds_paged(
@@ -178,7 +196,7 @@ pub trait MixnetQueryClient {
async fn get_mixnode_details_by_identity( async fn get_mixnode_details_by_identity(
&self, &self,
mix_identity: IdentityKey, mix_identity: IdentityKey,
) -> Result<Option<MixNodeDetails>, NyxdError> { ) -> Result<MixnodeDetailsByIdentityResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetBondedMixnodeDetailsByIdentity { self.query_mixnet_contract(MixnetQueryMsg::GetBondedMixnodeDetailsByIdentity {
mix_identity, mix_identity,
}) })
@@ -415,14 +433,17 @@ pub trait MixnetQueryClient {
.await .await
} }
async fn get_node_family_by_label(&self, label: &str) -> Result<Option<Family>, NyxdError> { async fn get_node_family_by_label(
&self,
label: &str,
) -> Result<FamilyByLabelResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetFamilyByLabel { self.query_mixnet_contract(MixnetQueryMsg::GetFamilyByLabel {
label: label.to_string(), label: label.to_string(),
}) })
.await .await
} }
async fn get_node_family_by_head(&self, head: &str) -> Result<Option<Family>, NyxdError> { async fn get_node_family_by_head(&self, head: &str) -> Result<FamilyByHeadResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetFamilyByHead { self.query_mixnet_contract(MixnetQueryMsg::GetFamilyByHead {
head: head.to_string(), head: head.to_string(),
}) })
@@ -10,12 +10,11 @@ use cosmwasm_std::{Coin as CosmWasmCoin, Timestamp};
use nym_contracts_common::ContractBuildInformation; use nym_contracts_common::ContractBuildInformation;
use nym_mixnet_contract_common::MixId; use nym_mixnet_contract_common::MixId;
use nym_vesting_contract_common::{ use nym_vesting_contract_common::{
messages::QueryMsg as VestingQueryMsg, AccountVestingCoins, AccountsResponse, messages::QueryMsg as VestingQueryMsg, Account, AccountVestingCoins, AccountsResponse,
AllDelegationsResponse, BaseVestingAccountInfo, DelegationTimesResponse, AllDelegationsResponse, BaseVestingAccountInfo, DelegationTimesResponse,
OriginalVestingResponse, Period, PledgeData, VestingCoinsResponse, VestingDelegation, OriginalVestingResponse, Period, PledgeData, VestingCoinsResponse, VestingDelegation,
}; };
use serde::Deserialize; use serde::Deserialize;
use vesting_contract::vesting::Account;
#[async_trait] #[async_trait]
pub trait VestingQueryClient { pub trait VestingQueryClient {
@@ -12,10 +12,8 @@ use nym_mixnet_contract_common::families::FamilyHead;
use nym_mixnet_contract_common::gateway::GatewayConfigUpdate; use nym_mixnet_contract_common::gateway::GatewayConfigUpdate;
use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, MixNodeCostParams}; use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
use nym_mixnet_contract_common::{Gateway, MixId, MixNode}; use nym_mixnet_contract_common::{Gateway, MixId, MixNode};
use nym_vesting_contract_common::messages::{ use nym_vesting_contract_common::messages::ExecuteMsg as VestingExecuteMsg;
ExecuteMsg as VestingExecuteMsg, VestingSpecification, use nym_vesting_contract_common::{PledgeCap, VestingSpecification};
};
use nym_vesting_contract_common::PledgeCap;
#[async_trait] #[async_trait]
pub trait VestingSigningClient { pub trait VestingSigningClient {
@@ -34,6 +34,7 @@ pub async fn delegate_to_mixnode(args: Args, client: SigningClient) {
.get_mixnode_details_by_identity(identity_key) .get_mixnode_details_by_identity(identity_key)
.await .await
.expect("contract query failed") .expect("contract query failed")
.mixnode_details
.expect("mixnode with the specified identity doesnt exist"); .expect("mixnode with the specified identity doesnt exist");
node_details.mix_id() node_details.mix_id()
} }
@@ -29,6 +29,7 @@ pub async fn claim_delegator_reward(args: Args, client: SigningClient) {
.get_mixnode_details_by_identity(identity_key) .get_mixnode_details_by_identity(identity_key)
.await .await
.expect("contract query failed") .expect("contract query failed")
.mixnode_details
.expect("mixnode with the specified identity doesnt exist"); .expect("mixnode with the specified identity doesnt exist");
node_details.mix_id() node_details.mix_id()
} }
@@ -29,6 +29,7 @@ pub async fn vesting_claim_delegator_reward(args: Args, client: SigningClient) {
.get_mixnode_details_by_identity(identity_key) .get_mixnode_details_by_identity(identity_key)
.await .await
.expect("contract query failed") .expect("contract query failed")
.mixnode_details
.expect("mixnode with the specified identity doesnt exist"); .expect("mixnode with the specified identity doesnt exist");
node_details.mix_id() node_details.mix_id()
} }
@@ -29,6 +29,7 @@ pub async fn undelegate_from_mixnode(args: Args, client: SigningClient) {
.get_mixnode_details_by_identity(identity_key) .get_mixnode_details_by_identity(identity_key)
.await .await
.expect("contract query failed") .expect("contract query failed")
.mixnode_details
.expect("mixnode with the specified identity doesnt exist"); .expect("mixnode with the specified identity doesnt exist");
node_details.mix_id() node_details.mix_id()
} }
@@ -40,6 +40,7 @@ pub async fn vesting_delegate_to_mixnode(args: Args, client: SigningClient) {
.get_mixnode_details_by_identity(identity_key) .get_mixnode_details_by_identity(identity_key)
.await .await
.expect("contract query failed") .expect("contract query failed")
.mixnode_details
.expect("mixnode with the specified identity doesnt exist"); .expect("mixnode with the specified identity doesnt exist");
node_details.mix_id() node_details.mix_id()
} }
@@ -34,6 +34,7 @@ pub async fn vesting_undelegate_from_mixnode(args: Args, client: SigningClient)
.get_mixnode_details_by_identity(identity_key) .get_mixnode_details_by_identity(identity_key)
.await .await
.expect("contract query failed") .expect("contract query failed")
.mixnode_details
.expect("mixnode with the specified identity doesnt exist"); .expect("mixnode with the specified identity doesnt exist");
node_details.mix_id() node_details.mix_id()
} }
@@ -50,6 +50,7 @@ pub async fn create_family_join_permit_sign_payload(args: Args, client: QueryCli
.get_node_family_by_head(mixnode.bond_information.identity()) .get_node_family_by_head(mixnode.bond_information.identity())
.await .await
.unwrap() .unwrap()
.family
.is_none() .is_none()
{ {
eprintln!("{} does not even seem to own a family!", args.address); eprintln!("{} does not even seem to own a family!", args.address);
@@ -28,7 +28,7 @@ pub struct Args {
pub async fn join_family(args: Args, client: SigningClient) { pub async fn join_family(args: Args, client: SigningClient) {
info!("Join family"); info!("Join family");
let family_head = FamilyHead::new(&args.family_head.to_base58_string()); let family_head = FamilyHead::new(args.family_head.to_base58_string());
let res = if args.with_vesting_account { let res = if args.with_vesting_account {
client client
@@ -23,7 +23,7 @@ pub struct Args {
pub async fn leave_family(args: Args, client: SigningClient) { pub async fn leave_family(args: Args, client: SigningClient) {
info!("Leave family"); info!("Leave family");
let family_head = FamilyHead::new(&args.family_head.to_base58_string()); let family_head = FamilyHead::new(args.family_head.to_base58_string());
let res = if args.with_vesting_account { let res = if args.with_vesting_account {
client client
@@ -11,7 +11,7 @@ use nym_network_defaults::NymNetworkDetails;
use nym_validator_client::nyxd::traits::VestingSigningClient; use nym_validator_client::nyxd::traits::VestingSigningClient;
use nym_validator_client::nyxd::AccountId; use nym_validator_client::nyxd::AccountId;
use nym_validator_client::nyxd::{CosmosCoin, Denom}; use nym_validator_client::nyxd::{CosmosCoin, Denom};
use nym_vesting_contract_common::messages::VestingSpecification; use nym_vesting_contract_common::types::VestingSpecification;
use nym_vesting_contract_common::PledgeCap; use nym_vesting_contract_common::PledgeCap;
use crate::context::SigningClient; use crate::context::SigningClient;
@@ -7,6 +7,9 @@ edition = "2021"
[dependencies] [dependencies]
cosmwasm-std = { workspace = true } cosmwasm-std = { workspace = true }
schemars = "0.8" cosmwasm-schema = { workspace = true }
serde = { version = "1.0.103", default-features = false, features = ["derive"] } cw2 = { workspace = true, optional = true }
nym-multisig-contract-common = { path = "../multisig-contract" } nym-multisig-contract-common = { path = "../multisig-contract" }
[features]
schema = ["cw2"]
@@ -1,10 +1,9 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use schemars::JsonSchema; use cosmwasm_schema::cw_serde;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[cw_serde]
pub struct DepositData { pub struct DepositData {
deposit_info: String, deposit_info: String,
identity_key: String, identity_key: String,
@@ -1,39 +1,41 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::Coin;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::{deposit::DepositData, spend_credential::SpendCredentialData}; use crate::{deposit::DepositData, spend_credential::SpendCredentialData};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Coin;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[cfg(feature = "schema")]
use crate::spend_credential::{PagedSpendCredentialResponse, SpendCredentialResponse};
#[cfg(feature = "schema")]
use cosmwasm_schema::QueryResponses;
#[cw_serde]
pub struct InstantiateMsg { pub struct InstantiateMsg {
pub multisig_addr: String, pub multisig_addr: String,
pub pool_addr: String, pub pool_addr: String,
pub mix_denom: String, pub mix_denom: String,
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg { pub enum ExecuteMsg {
DepositFunds { data: DepositData }, DepositFunds { data: DepositData },
SpendCredential { data: SpendCredentialData }, SpendCredential { data: SpendCredentialData },
ReleaseFunds { funds: Coin }, ReleaseFunds { funds: Coin },
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[cw_serde]
#[serde(rename_all = "snake_case")] #[cfg_attr(feature = "schema", derive(QueryResponses))]
pub enum QueryMsg { pub enum QueryMsg {
GetSpentCredential { #[cfg_attr(feature = "schema", returns(SpendCredentialResponse))]
blinded_serial_number: String, GetSpentCredential { blinded_serial_number: String },
},
#[cfg_attr(feature = "schema", returns(PagedSpendCredentialResponse))]
GetAllSpentCredentials { GetAllSpentCredentials {
limit: Option<u32>, limit: Option<u32>,
start_after: Option<String>, start_after: Option<String>,
}, },
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub struct MigrateMsg {} pub struct MigrateMsg {}
@@ -1,14 +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 cosmwasm_schema::cw_serde;
use cosmwasm_std::{from_binary, to_binary, Addr, Coin, CosmosMsg, StdResult, WasmMsg}; use cosmwasm_std::{from_binary, to_binary, Addr, Coin, CosmosMsg, StdResult, WasmMsg};
use nym_multisig_contract_common::msg::ExecuteMsg as MultisigExecuteMsg; use nym_multisig_contract_common::msg::ExecuteMsg as MultisigExecuteMsg;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::msg::ExecuteMsg; use crate::msg::ExecuteMsg;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[cw_serde]
pub struct SpendCredentialData { pub struct SpendCredentialData {
funds: Coin, funds: Coin,
blinded_serial_number: String, blinded_serial_number: String,
@@ -37,13 +36,14 @@ impl SpendCredentialData {
} }
} }
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] #[cw_serde]
#[derive(Copy)]
pub enum SpendCredentialStatus { pub enum SpendCredentialStatus {
InProgress, InProgress,
Spent, Spent,
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] #[cw_serde]
pub struct SpendCredential { pub struct SpendCredential {
funds: Coin, funds: Coin,
blinded_serial_number: String, blinded_serial_number: String,
@@ -74,10 +74,12 @@ impl SpendCredential {
} }
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] #[cw_serde]
pub struct PagedSpendCredentialResponse { pub struct PagedSpendCredentialResponse {
pub spend_credentials: Vec<SpendCredential>, pub spend_credentials: Vec<SpendCredential>,
pub per_page: usize, pub per_page: usize,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<String>, pub start_next_after: Option<String>,
} }
@@ -95,7 +97,7 @@ impl PagedSpendCredentialResponse {
} }
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] #[cw_serde]
pub struct SpendCredentialResponse { pub struct SpendCredentialResponse {
pub spend_credential: Option<SpendCredential>, pub spend_credential: Option<SpendCredential>,
} }
@@ -6,10 +6,12 @@ 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
[dependencies] [dependencies]
cosmwasm-schema = { workspace = true }
cosmwasm-std = { workspace = true } cosmwasm-std = { workspace = true }
cw-utils = { workspace = true } cw-utils = { workspace = true }
schemars = "0.8"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
contracts-common = { path = "../contracts-common", package = "nym-contracts-common" } contracts-common = { path = "../contracts-common", package = "nym-contracts-common" }
nym-multisig-contract-common = { path = "../multisig-contract" } nym-multisig-contract-common = { path = "../multisig-contract" }
[features]
schema = []
@@ -2,11 +2,10 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::types::{ContractSafeBytes, EncodedBTEPublicKeyWithProof, NodeIndex}; use crate::types::{ContractSafeBytes, EncodedBTEPublicKeyWithProof, NodeIndex};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Addr; use cosmwasm_std::Addr;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub struct DealerDetails { pub struct DealerDetails {
pub address: Addr, pub address: Addr,
pub bte_public_key_with_proof: EncodedBTEPublicKeyWithProof, pub bte_public_key_with_proof: EncodedBTEPublicKeyWithProof,
@@ -14,8 +13,8 @@ pub struct DealerDetails {
pub assigned_index: NodeIndex, pub assigned_index: NodeIndex,
} }
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] #[cw_serde]
#[serde(rename_all = "snake_case")] #[derive(Copy)]
pub enum DealerType { pub enum DealerType {
Current, Current,
Past, Past,
@@ -28,8 +27,7 @@ impl DealerType {
} }
} }
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub struct DealerDetailsResponse { pub struct DealerDetailsResponse {
pub details: Option<DealerDetails>, pub details: Option<DealerDetails>,
pub dealer_type: DealerType, pub dealer_type: DealerType,
@@ -44,11 +42,12 @@ impl DealerDetailsResponse {
} }
} }
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub struct PagedDealerResponse { pub struct PagedDealerResponse {
pub dealers: Vec<DealerDetails>, pub dealers: Vec<DealerDetails>,
pub per_page: usize, pub per_page: usize,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<Addr>, pub start_next_after: Option<Addr>,
} }
@@ -66,8 +65,7 @@ impl PagedDealerResponse {
} }
} }
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub struct ContractDealing { pub struct ContractDealing {
pub dealing: ContractSafeBytes, pub dealing: ContractSafeBytes,
pub dealer: Addr, pub dealer: Addr,
@@ -79,11 +77,12 @@ impl ContractDealing {
} }
} }
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub struct PagedDealingsResponse { pub struct PagedDealingsResponse {
pub dealings: Vec<ContractDealing>, pub dealings: Vec<ContractDealing>,
pub per_page: usize, pub per_page: usize,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<Addr>, pub start_next_after: Option<Addr>,
} }
@@ -3,11 +3,19 @@
use crate::types::{ContractSafeBytes, EncodedBTEPublicKeyWithProof, EpochId, TimeConfiguration}; use crate::types::{ContractSafeBytes, EncodedBTEPublicKeyWithProof, EpochId, TimeConfiguration};
use crate::verification_key::VerificationKeyShare; use crate::verification_key::VerificationKeyShare;
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Addr; use cosmwasm_std::Addr;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[cfg(feature = "schema")]
use crate::{
dealer::{DealerDetailsResponse, PagedDealerResponse, PagedDealingsResponse},
types::{Epoch, InitialReplacementData},
verification_key::PagedVKSharesResponse,
};
#[cfg(feature = "schema")]
use cosmwasm_schema::QueryResponses;
#[cw_serde]
pub struct InstantiateMsg { pub struct InstantiateMsg {
pub group_addr: String, pub group_addr: String,
pub multisig_addr: String, pub multisig_addr: String,
@@ -15,8 +23,7 @@ pub struct InstantiateMsg {
pub mix_denom: String, pub mix_denom: String,
} }
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, JsonSchema)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg { pub enum ExecuteMsg {
RegisterDealer { RegisterDealer {
bte_key_with_proof: EncodedBTEPublicKeyWithProof, bte_key_with_proof: EncodedBTEPublicKeyWithProof,
@@ -44,28 +51,41 @@ pub enum ExecuteMsg {
AdvanceEpochState {}, AdvanceEpochState {},
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[cw_serde]
#[serde(rename_all = "snake_case")] #[cfg_attr(feature = "schema", derive(QueryResponses))]
pub enum QueryMsg { pub enum QueryMsg {
#[cfg_attr(feature = "schema", returns(Epoch))]
GetCurrentEpochState {}, GetCurrentEpochState {},
#[cfg_attr(feature = "schema", returns(u64))]
GetCurrentEpochThreshold {}, GetCurrentEpochThreshold {},
#[cfg_attr(feature = "schema", returns(Option<InitialReplacementData>))]
GetInitialDealers {}, GetInitialDealers {},
GetDealerDetails {
dealer_address: String, #[cfg_attr(feature = "schema", returns(DealerDetailsResponse))]
}, GetDealerDetails { dealer_address: String },
#[cfg_attr(feature = "schema", returns(PagedDealerResponse))]
GetCurrentDealers { GetCurrentDealers {
limit: Option<u32>, limit: Option<u32>,
start_after: Option<String>, start_after: Option<String>,
}, },
#[cfg_attr(feature = "schema", returns(PagedDealerResponse))]
GetPastDealers { GetPastDealers {
limit: Option<u32>, limit: Option<u32>,
start_after: Option<String>, start_after: Option<String>,
}, },
#[cfg_attr(feature = "schema", returns(PagedDealingsResponse))]
GetDealing { GetDealing {
idx: u64, idx: u64,
limit: Option<u32>, limit: Option<u32>,
start_after: Option<String>, start_after: Option<String>,
}, },
#[cfg_attr(feature = "schema", returns(PagedVKSharesResponse))]
GetVerificationKeys { GetVerificationKeys {
epoch_id: EpochId, epoch_id: EpochId,
limit: Option<u32>, limit: Option<u32>,
@@ -73,6 +93,5 @@ pub enum QueryMsg {
}, },
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub struct MigrateMsg {} pub struct MigrateMsg {}
@@ -1,8 +1,7 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net> // Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use schemars::JsonSchema; use cosmwasm_schema::cw_serde;
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::str::FromStr; use std::str::FromStr;
@@ -18,15 +17,14 @@ pub type EpochId = u64;
// 2 public attributes, 2 private attributes, 1 fixed for coconut credential // 2 public attributes, 2 private attributes, 1 fixed for coconut credential
pub const TOTAL_DEALINGS: usize = 2 + 2 + 1; pub const TOTAL_DEALINGS: usize = 2 + 2 + 1;
#[derive(Serialize, Deserialize, Default, Clone, Debug, PartialEq, Eq, Ord, PartialOrd)] #[cw_serde]
pub struct InitialReplacementData { pub struct InitialReplacementData {
pub initial_dealers: Vec<Addr>, pub initial_dealers: Vec<Addr>,
pub initial_height: u64, pub initial_height: u64,
} }
#[derive( #[cw_serde]
Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd, JsonSchema, #[derive(Copy)]
)]
pub struct TimeConfiguration { pub struct TimeConfiguration {
// The time sign-up is open for dealers to join // The time sign-up is open for dealers to join
pub public_key_submission_time_secs: u64, pub public_key_submission_time_secs: u64,
@@ -75,8 +73,8 @@ impl Default for TimeConfiguration {
} }
} }
#[derive(Serialize, Deserialize, Default, Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)] #[cw_serde]
#[serde(rename_all = "snake_case")] #[derive(Copy, Default)]
pub struct Epoch { pub struct Epoch {
pub state: EpochState, pub state: EpochState,
pub epoch_id: EpochId, pub epoch_id: EpochId,
@@ -155,8 +153,8 @@ impl Epoch {
// 8. InProgress -> all receivers have all their secrets derived and all is good // 8. InProgress -> all receivers have all their secrets derived and all is good
// //
// Note: It's important that the variant ordering is not changed otherwise it would mess up the derived `PartialOrd` // Note: It's important that the variant ordering is not changed otherwise it would mess up the derived `PartialOrd`
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)] #[cw_serde]
#[serde(rename_all = "snake_case")] #[derive(Copy)]
pub enum EpochState { pub enum EpochState {
PublicKeySubmission { resharing: bool }, PublicKeySubmission { resharing: bool },
DealingExchange { resharing: bool }, DealingExchange { resharing: bool },
@@ -3,14 +3,14 @@
use crate::msg::ExecuteMsg; use crate::msg::ExecuteMsg;
use crate::types::{EpochId, NodeIndex}; use crate::types::{EpochId, NodeIndex};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{from_binary, to_binary, Addr, CosmosMsg, StdResult, Timestamp, WasmMsg}; use cosmwasm_std::{from_binary, to_binary, Addr, CosmosMsg, StdResult, Timestamp, WasmMsg};
use cw_utils::Expiration; use cw_utils::Expiration;
use nym_multisig_contract_common::msg::ExecuteMsg as MultisigExecuteMsg; use nym_multisig_contract_common::msg::ExecuteMsg as MultisigExecuteMsg;
use serde::{Deserialize, Serialize};
pub type VerificationKeyShare = String; pub type VerificationKeyShare = String;
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] #[cw_serde]
pub struct ContractVKShare { pub struct ContractVKShare {
pub share: VerificationKeyShare, pub share: VerificationKeyShare,
pub announce_address: String, pub announce_address: String,
@@ -20,11 +20,12 @@ pub struct ContractVKShare {
pub verified: bool, pub verified: bool,
} }
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub struct PagedVKSharesResponse { pub struct PagedVKSharesResponse {
pub shares: Vec<ContractVKShare>, pub shares: Vec<ContractVKShare>,
pub per_page: usize, pub per_page: usize,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<Addr>, pub start_next_after: Option<Addr>,
} }
@@ -10,9 +10,10 @@ repository = { workspace = true }
[dependencies] [dependencies]
bs58 = "0.4.0" bs58 = "0.4.0"
cosmwasm-std = { workspace = true } cosmwasm-std = { workspace = true }
cosmwasm-schema = { workspace = true }
schemars = "0.8" schemars = "0.8"
serde = { version = "1.0", features = ["derive"] } serde = { workspace = true, features = ["derive"] }
thiserror = "1" thiserror = { workspace = true }
[dev-dependencies] [dev-dependencies]
serde_json = "1.0.0" serde_json = { workspace = true }
@@ -1,8 +1,6 @@
// 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
#[cfg(feature = "dkg")]
use nym_dkg::{error::DkgError, Dealing};
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
@@ -1,16 +1,17 @@
// 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 cosmwasm_schema::cw_serde;
use cosmwasm_std::Decimal; use cosmwasm_std::Decimal;
use cosmwasm_std::Uint128; use cosmwasm_std::Uint128;
use schemars::JsonSchema;
use serde::de::Error; use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize}; use serde::{Deserialize, Deserializer};
use std::fmt::{self, Display, Formatter}; use std::fmt::{self, Display, Formatter};
use std::ops::Mul; use std::ops::Mul;
use std::str::FromStr; use std::str::FromStr;
use thiserror::Error; use thiserror::Error;
/// Ed25519 public key strinfified into base58.
pub type IdentityKey = String; pub type IdentityKey = String;
pub type IdentityKeyRef<'a> = &'a str; pub type IdentityKeyRef<'a> = &'a str;
@@ -32,9 +33,8 @@ pub enum ContractsCommonError {
/// Percent represents a value between 0 and 100% /// Percent represents a value between 0 and 100%
/// (i.e. between 0.0 and 1.0) /// (i.e. between 0.0 and 1.0)
#[derive( #[cw_serde]
Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Serialize, Deserialize, JsonSchema, #[derive(Copy, Default, PartialOrd)]
)]
pub struct Percent(#[serde(deserialize_with = "de_decimal_percent")] Decimal); pub struct Percent(#[serde(deserialize_with = "de_decimal_percent")] Decimal);
impl Percent { impl Percent {
@@ -129,7 +129,7 @@ where
// TODO: there's no reason this couldn't be used for proper binaries, but in that case // TODO: there's no reason this couldn't be used for proper binaries, but in that case
// perhaps the struct should get renamed and moved to a "more" common crate // perhaps the struct should get renamed and moved to a "more" common crate
#[derive(Debug, Serialize, Deserialize)] #[cw_serde]
pub struct ContractBuildInformation { pub struct ContractBuildInformation {
// VERGEN_BUILD_TIMESTAMP // VERGEN_BUILD_TIMESTAMP
/// Provides the build timestamp, for example `2021-02-23T20:14:46.558472672+00:00`. /// Provides the build timestamp, for example `2021-02-23T20:14:46.558472672+00:00`.
@@ -46,3 +46,5 @@ pub enum QueryMsg {
#[returns(cw_controllers::HooksResponse)] #[returns(cw_controllers::HooksResponse)]
Hooks {}, Hooks {},
} }
#[cw_serde]
pub struct MigrateMsg {}
@@ -11,14 +11,16 @@ repository = { workspace = true }
[dependencies] [dependencies]
bs58 = "0.4.0" bs58 = "0.4.0"
cosmwasm-std = { workspace = true } cosmwasm-std = { workspace = true }
serde = { version = "1.0", features = ["derive"] } cosmwasm-schema = { workspace = true }
cw2 = { workspace = true, optional = true }
serde = { workspace = true, features = ["derive"] }
serde_repr = "0.1" serde_repr = "0.1"
# we still have to preserve that import for `JsonSchema` for `Layer` type (since we can't use cw_serde macro due to custom serde impl)
schemars = "0.8" schemars = "0.8"
thiserror = "1.0" thiserror = "1.0"
contracts-common = { path = "../contracts-common", package = "nym-contracts-common", version = "0.5.0" } contracts-common = { path = "../contracts-common", package = "nym-contracts-common", version = "0.5.0" }
# use 0.4.1 as that's the version used by cosmwasm-std 1.0.0 serde-json-wasm = { workspace = true }
# (and ideally we don't want to pull the same dependency twice)
serde-json-wasm = "=0.4.1"
humantime-serde = "1.1.1" humantime-serde = "1.1.1"
# TO CHECK WHETHER STILL NEEDED: # TO CHECK WHETHER STILL NEEDED:
@@ -33,4 +35,5 @@ time = { version = "0.3.5", features = ["serde", "macros"] }
[features] [features]
default = [] default = []
contract-testing = [] contract-testing = []
schema = ["cw2"]
generate-ts = ['ts-rs'] generate-ts = ['ts-rs']
@@ -1,15 +1,11 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// due to code generated by JsonSchema
#![allow(clippy::field_reassign_with_default)]
use crate::constants::TOKEN_SUPPLY; use crate::constants::TOKEN_SUPPLY;
use crate::helpers::IntoBaseDecimal; use crate::helpers::IntoBaseDecimal;
use crate::{Addr, MixId}; use crate::{Addr, MixId};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Coin, Decimal, StdResult}; use cosmwasm_std::{Coin, Decimal, StdResult};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
// just use a string representation of those so that we wouldn't need to bother with decoding bytes // just use a string representation of those so that we wouldn't need to bother with decoding bytes
// and trying to figure out whether they're valid, etc // and trying to figure out whether they're valid, etc
@@ -37,7 +33,9 @@ pub fn generate_owner_storage_subkey(
} }
} }
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, JsonSchema)] /// Information about tokens being delegated towards given mixnode in order to accrue rewards
/// with their work.
#[cw_serde]
pub struct Delegation { pub struct Delegation {
/// Address of the owner of this delegation. /// Address of the owner of this delegation.
pub owner: Addr, pub owner: Addr,
@@ -114,9 +112,13 @@ impl Delegation {
} }
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] /// Response containing paged list of all delegations made towards particular mixnode.
#[cw_serde]
pub struct PagedMixNodeDelegationsResponse { pub struct PagedMixNodeDelegationsResponse {
/// Each individual delegation made.
pub delegations: Vec<Delegation>, pub delegations: Vec<Delegation>,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<OwnerProxySubKey>, pub start_next_after: Option<OwnerProxySubKey>,
} }
@@ -129,9 +131,13 @@ impl PagedMixNodeDelegationsResponse {
} }
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] /// Response containing paged list of all delegations made by the particular address.
#[cw_serde]
pub struct PagedDelegatorDelegationsResponse { pub struct PagedDelegatorDelegationsResponse {
/// Each individual delegation made.
pub delegations: Vec<Delegation>, pub delegations: Vec<Delegation>,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<(MixId, OwnerProxySubKey)>, pub start_next_after: Option<(MixId, OwnerProxySubKey)>,
} }
@@ -147,9 +153,13 @@ impl PagedDelegatorDelegationsResponse {
} }
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] /// Response containing delegation details.
#[cw_serde]
pub struct MixNodeDelegationResponse { pub struct MixNodeDelegationResponse {
/// If the delegation exists, this field contains its detailed information.
pub delegation: Option<Delegation>, pub delegation: Option<Delegation>,
/// Flag indicating whether the node towards which the delegation was made is still bonded in the network.
pub mixnode_still_bonded: bool, pub mixnode_still_bonded: bool,
} }
@@ -162,9 +172,13 @@ impl MixNodeDelegationResponse {
} }
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] /// Response containing paged list of all delegations currently active.
#[cw_serde]
pub struct PagedAllDelegationsResponse { pub struct PagedAllDelegationsResponse {
/// Each individual delegation made.
pub delegations: Vec<Delegation>, pub delegations: Vec<Delegation>,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<StorageKey>, pub start_next_after: Option<StorageKey>,
} }
@@ -165,6 +165,9 @@ pub enum MixnetContractError {
#[error("Family with head {head} does not exist!")] #[error("Family with head {head} does not exist!")]
FamilyDoesNotExist { head: String }, FamilyDoesNotExist { head: String },
#[error("Family with label {label} does not exist!")]
FamilyLabelDoesNotExist { label: String },
#[error("Family with label '{0}' already exists")] #[error("Family with label '{0}' already exists")]
FamilyWithLabelExists(String), FamilyWithLabelExists(String),
@@ -1,22 +1,34 @@
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::{IdentityKey, IdentityKeyRef}; use crate::{IdentityKey, IdentityKeyRef};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Addr; use cosmwasm_std::Addr;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::str::FromStr; use std::str::FromStr;
/// A group of mixnodes associated with particular staking entity.
/// When defined all nodes belonging to the same family will be prioritised to be put onto the same layer.
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))] #[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr( #[cfg_attr(
feature = "generate-ts", feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/NodeFamily.ts") ts(export_to = "ts-packages/types/src/types/rust/NodeFamily.ts")
)] )]
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, JsonSchema)] #[cw_serde]
pub struct Family { pub struct Family {
/// Owner of this family.
head: FamilyHead, head: FamilyHead,
/// Optional proxy (i.e. vesting contract address) used when creating the family.
proxy: Option<String>, proxy: Option<String>,
/// Human readable label for this family.
label: String, label: String,
} }
/// Head of particular family as identified by its identity key (i.e. public component of its ed25519 keypair stringified into base58).
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))] #[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr( #[cfg_attr(
feature = "generate-ts", feature = "generate-ts",
@@ -62,8 +74,8 @@ impl Display for FamilyHead {
} }
impl FamilyHead { impl FamilyHead {
pub fn new(identity: IdentityKeyRef<'_>) -> Self { pub fn new<S: Into<String>>(identity: S) -> Self {
FamilyHead(identity.to_string()) FamilyHead(identity.into())
} }
pub fn identity(&self) -> IdentityKeyRef<'_> { pub fn identity(&self) -> IdentityKeyRef<'_> {
@@ -99,6 +111,66 @@ impl Family {
} }
} }
/// Response containing paged list of all families registered in the contract.
#[cw_serde]
pub struct PagedFamiliesResponse {
/// The families registered in the contract.
pub families: Vec<Family>,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<String>,
}
/// Response containing paged list of all family members (of ALL families) registered in the contract.
#[cw_serde]
pub struct PagedMembersResponse {
/// The members alongside their family heads.
pub members: Vec<(IdentityKey, FamilyHead)>,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<String>,
}
/// Response containing family information.
#[cw_serde]
pub struct FamilyByHeadResponse {
/// The family head used for the query.
pub head: FamilyHead,
/// If applicable, the family associated with the provided head.
pub family: Option<Family>,
}
/// Response containing family information.
#[cw_serde]
pub struct FamilyByLabelResponse {
/// The family label used for the query.
pub label: String,
/// If applicable, the family associated with the provided label.
pub family: Option<Family>,
}
/// Response containing family members information.
#[cw_serde]
pub struct FamilyMembersByHeadResponse {
/// The family head used for the query.
pub head: FamilyHead,
/// All members belonging to the specified family.
pub members: Vec<IdentityKey>,
}
/// Response containing family members information.
#[cw_serde]
pub struct FamilyMembersByLabelResponse {
/// The family label used for the query.
pub label: String,
/// All members belonging to the specified family.
pub members: Vec<IdentityKey>,
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@@ -1,34 +1,56 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// due to code generated by JsonSchema
#![allow(clippy::field_reassign_with_default)]
use crate::{IdentityKey, SphinxKey}; use crate::{IdentityKey, SphinxKey};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Addr, Coin}; use cosmwasm_std::{Addr, Coin};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::cmp::Ordering; use std::cmp::Ordering;
use std::fmt::Display; use std::fmt::Display;
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, PartialOrd, Serialize, JsonSchema)] /// Information provided by the node operator during bonding that are used to allow other entities to use the services of this node.
#[cw_serde]
#[derive(PartialOrd)]
pub struct Gateway { pub struct Gateway {
/// Network address of this gateway, for example 1.1.1.1 or foo.gateway.com
pub host: String, pub host: String,
/// Port used by this gateway for listening for mix packets.
pub mix_port: u16, pub mix_port: u16,
/// Port used by this gateway for listening for client requests.
pub clients_port: u16, pub clients_port: u16,
/// The physical, self-reported, location of this gateway.
// this field should be deprecated in favour of externally hosted information, like the mixnodes'.
pub location: String, pub location: String,
/// Base58-encoded x25519 public key used for sphinx key derivation.
pub sphinx_key: SphinxKey, pub sphinx_key: SphinxKey,
/// Base58 encoded ed25519 EdDSA public key of the gateway used to derive shared keys with clients /// Base58 encoded ed25519 EdDSA public key of the gateway used to derive shared keys with clients
pub identity_key: IdentityKey, pub identity_key: IdentityKey,
/// The self-reported semver version of this gateway.
pub version: String, pub version: String,
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] /// Basic gateway information provided by the node operator.
#[cw_serde]
pub struct GatewayBond { pub struct GatewayBond {
/// Original amount pledged by the operator of this node.
pub pledge_amount: Coin, pub pledge_amount: Coin,
/// Address of the owner of this gateway.
pub owner: Addr, pub owner: Addr,
/// Block height at which this gateway has been bonded.
pub block_height: u64, pub block_height: u64,
/// Information provided by the operator for the purposes of bonding.
pub gateway: Gateway, pub gateway: Gateway,
/// Entity who bonded this gateway on behalf of the owner.
/// If exists, it's most likely the address of the vesting contract.
pub proxy: Option<Addr>, pub proxy: Option<Addr>,
} }
@@ -117,7 +139,7 @@ impl Display for GatewayBond {
feature = "generate-ts", feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/GatewayConfigUpdate.ts") ts(export_to = "ts-packages/types/src/types/rust/GatewayConfigUpdate.ts")
)] )]
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] #[cw_serde]
pub struct GatewayConfigUpdate { pub struct GatewayConfigUpdate {
pub host: String, pub host: String,
pub mix_port: u16, pub mix_port: u16,
@@ -132,10 +154,17 @@ impl GatewayConfigUpdate {
} }
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] /// Response containing paged list of all gateway bonds in the contract.
#[cw_serde]
pub struct PagedGatewayResponse { pub struct PagedGatewayResponse {
/// The gateway bond information present in the contract.
pub nodes: Vec<GatewayBond>, pub nodes: Vec<GatewayBond>,
/// Maximum number of entries that could be included in a response. `per_page <= nodes.len()`
// this field is rather redundant and should be deprecated.
pub per_page: usize, pub per_page: usize,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<IdentityKey>, pub start_next_after: Option<IdentityKey>,
} }
@@ -153,15 +182,23 @@ impl PagedGatewayResponse {
} }
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] /// Response containing details of a gateway belonging to the particular owner.
#[cw_serde]
pub struct GatewayOwnershipResponse { pub struct GatewayOwnershipResponse {
/// Validated address of the gateway owner.
pub address: Addr, pub address: Addr,
/// If the provided address owns a gateway, this field contains its details.
pub gateway: Option<GatewayBond>, pub gateway: Option<GatewayBond>,
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] /// Response containing details of a gateway with the provided identity key.
#[cw_serde]
pub struct GatewayBondResponse { pub struct GatewayBondResponse {
/// The identity key (base58-encoded ed25519 public key) of the gateway.
pub identity: IdentityKey, pub identity: IdentityKey,
/// If there exists a gateway with the provided identity key, this field contains its details.
pub gateway: Option<GatewayBond>, pub gateway: Option<GatewayBond>,
} }
@@ -2,20 +2,20 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::error::MixnetContractError; use crate::error::MixnetContractError;
use crate::pending_events::{PendingEpochEvent, PendingIntervalEvent}; use crate::MixId;
use crate::{ use cosmwasm_schema::cw_serde;
EpochEventId, EpochId, IntervalEventId, IntervalId, MixId, PendingEpochEventData, use cosmwasm_schema::schemars::gen::SchemaGenerator;
PendingIntervalEventData, use cosmwasm_schema::schemars::schema::{InstanceType, Schema, SchemaObject};
}; use cosmwasm_schema::schemars::JsonSchema;
use cosmwasm_std::{Addr, Env}; use cosmwasm_std::{Addr, Env};
use schemars::gen::SchemaGenerator;
use schemars::schema::{InstanceType, Schema, SchemaObject};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::time::Duration; use std::time::Duration;
use time::OffsetDateTime; use time::OffsetDateTime;
pub type EpochId = u32;
pub type IntervalId = u32;
// internally, since version 0.3.6, time uses deserialize_any for deserialization, which can't be handled // internally, since version 0.3.6, time uses deserialize_any for deserialization, which can't be handled
// by serde wasm. We could just downgrade to 0.3.5 and call it a day, but then it would break // by serde wasm. We could just downgrade to 0.3.5 and call it a day, but then it would break
// when we decided to upgrade it at some point in the future. And then it would have been more problematic // when we decided to upgrade it at some point in the future. And then it would have been more problematic
@@ -64,12 +64,15 @@ pub(crate) mod string_rfc3339_offset_date_time {
} }
} }
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)] /// The status of the current rewarding epoch.
#[cw_serde]
pub struct EpochStatus { pub struct EpochStatus {
// TODO: introduce mechanism to allow another validator to take over if no progress has been made in X blocks / Y seconds // TODO: introduce mechanism to allow another validator to take over if no progress has been made in X blocks / Y seconds
/// Specifies either, which validator is currently performing progression into the following epoch (if the epoch is currently being progressed), /// Specifies either, which validator is currently performing progression into the following epoch (if the epoch is currently being progressed),
/// or which validator was responsible for progressing into the current epoch (if the epoch is currently in progress) /// or which validator was responsible for progressing into the current epoch (if the epoch is currently in progress)
pub being_advanced_by: Addr, pub being_advanced_by: Addr,
/// The concrete state of the epoch.
pub state: EpochState, pub state: EpochState,
} }
@@ -150,7 +153,9 @@ impl EpochStatus {
} }
} }
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq)] /// The state of the current rewarding epoch.
#[cw_serde]
#[derive(Copy)]
pub enum EpochState { pub enum EpochState {
/// Represents the state of an epoch that's in progress (well, duh.) /// Represents the state of an epoch that's in progress (well, duh.)
/// All actions are allowed to be issued. /// All actions are allowed to be issued.
@@ -159,8 +164,10 @@ pub enum EpochState {
/// Represents the state of an epoch when the rewarding entity has been decided on, /// Represents the state of an epoch when the rewarding entity has been decided on,
/// and the mixnodes are in the process of being rewarded for their work in this epoch. /// and the mixnodes are in the process of being rewarded for their work in this epoch.
Rewarding { Rewarding {
/// The id of the last node that has already received its rewards.
last_rewarded: MixId, last_rewarded: MixId,
/// The id of the last node that's going to be rewarded before progressing into the next state.
final_node_id: MixId, final_node_id: MixId,
// total_rewarded: u32, // total_rewarded: u32,
}, },
@@ -191,6 +198,7 @@ impl Display for EpochState {
} }
} }
/// Specification of a rewarding interval.
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))] #[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr( #[cfg_attr(
feature = "generate-ts", feature = "generate-ts",
@@ -198,7 +206,10 @@ impl Display for EpochState {
)] )]
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize)] #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize)]
pub struct Interval { pub struct Interval {
/// Monotonously increasing id of this interval.
id: IntervalId, id: IntervalId,
/// Number of epochs in this interval.
epochs_in_interval: u32, epochs_in_interval: u32,
// TODO add a better TS type generation // TODO add a better TS type generation
@@ -207,10 +218,17 @@ pub struct Interval {
// note: the `ts-rs failed to parse this attribute. It will be ignored.` warning emitted during // note: the `ts-rs failed to parse this attribute. It will be ignored.` warning emitted during
// compilation is fine (I guess). `ts-rs` can't handle `with` serde attribute, but that's okay // compilation is fine (I guess). `ts-rs` can't handle `with` serde attribute, but that's okay
// since we explicitly specified this field should correspond to typescript's string // since we explicitly specified this field should correspond to typescript's string
/// The timestamp indicating the start of the current rewarding epoch.
current_epoch_start: OffsetDateTime, current_epoch_start: OffsetDateTime,
/// Monotonously increasing id of the current epoch in this interval.
current_epoch_id: EpochId, current_epoch_id: EpochId,
/// The duration of all epochs in this interval.
#[cfg_attr(feature = "generate-ts", ts(type = "{ secs: number; nanos: number; }"))] #[cfg_attr(feature = "generate-ts", ts(type = "{ secs: number; nanos: number; }"))]
epoch_length: Duration, epoch_length: Duration,
/// The total amount of elapsed epochs since the first epoch of the first interval.
total_elapsed_epochs: EpochId, total_elapsed_epochs: EpochId,
} }
@@ -455,11 +473,19 @@ impl Display for Interval {
} }
} }
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize)] /// Information about the current rewarding interval.
#[cw_serde]
pub struct CurrentIntervalResponse { pub struct CurrentIntervalResponse {
/// Detailed information about the underlying interval.
pub interval: Interval, pub interval: Interval,
/// The current blocktime
pub current_blocktime: u64, pub current_blocktime: u64,
/// Flag indicating whether the current interval is over and it should be advanced.
pub is_current_interval_over: bool, pub is_current_interval_over: bool,
/// Flag indicating whether the current epoch is over and it should be advanced.
pub is_current_epoch_over: bool, pub is_current_epoch_over: bool,
} }
@@ -489,87 +515,6 @@ impl CurrentIntervalResponse {
} }
} }
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct PendingEpochEventsResponse {
pub seconds_until_executable: i64,
pub events: Vec<PendingEpochEvent>,
pub start_next_after: Option<u32>,
}
impl PendingEpochEventsResponse {
pub fn new(
seconds_until_executable: i64,
events: Vec<PendingEpochEvent>,
start_next_after: Option<u32>,
) -> Self {
PendingEpochEventsResponse {
seconds_until_executable,
events,
start_next_after,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct PendingIntervalEventsResponse {
pub seconds_until_executable: i64,
pub events: Vec<PendingIntervalEvent>,
pub start_next_after: Option<u32>,
}
impl PendingIntervalEventsResponse {
pub fn new(
seconds_until_executable: i64,
events: Vec<PendingIntervalEvent>,
start_next_after: Option<u32>,
) -> Self {
PendingIntervalEventsResponse {
seconds_until_executable,
events,
start_next_after,
}
}
}
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct PendingEpochEventResponse {
pub event_id: EpochEventId,
pub event: Option<PendingEpochEventData>,
}
impl PendingEpochEventResponse {
pub fn new(event_id: EpochEventId, event: Option<PendingEpochEventData>) -> Self {
PendingEpochEventResponse { event_id, event }
}
}
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct PendingIntervalEventResponse {
pub event_id: IntervalEventId,
pub event: Option<PendingIntervalEventData>,
}
impl PendingIntervalEventResponse {
pub fn new(event_id: IntervalEventId, event: Option<PendingIntervalEventData>) -> Self {
PendingIntervalEventResponse { event_id, event }
}
}
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct NumberOfPendingEventsResponse {
pub epoch_events: u32,
pub interval_events: u32,
}
impl NumberOfPendingEventsResponse {
pub fn new(epoch_events: u32, interval_events: u32) -> Self {
Self {
epoch_events,
interval_events,
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@@ -11,14 +11,14 @@ pub mod events;
pub mod families; pub mod families;
pub mod gateway; pub mod gateway;
pub mod helpers; pub mod helpers;
mod interval; pub mod interval;
pub mod mixnode; pub mod mixnode;
mod msg; pub mod msg;
pub mod pending_events; pub mod pending_events;
pub mod reward_params; pub mod reward_params;
pub mod rewarding; pub mod rewarding;
pub mod signing_types; pub mod signing_types;
mod types; pub mod types;
pub use contracts_common::types::*; pub use contracts_common::types::*;
pub use cosmwasm_std::{Addr, Coin, Decimal, Fraction}; pub use cosmwasm_std::{Addr, Coin, Decimal, Fraction};
@@ -26,25 +26,32 @@ pub use delegation::{
Delegation, PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse, Delegation, PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse,
PagedMixNodeDelegationsResponse, PagedMixNodeDelegationsResponse,
}; };
pub use families::{
Family, FamilyByHeadResponse, FamilyByLabelResponse, FamilyHead, FamilyMembersByHeadResponse,
FamilyMembersByLabelResponse, PagedFamiliesResponse, PagedMembersResponse,
};
pub use gateway::{ pub use gateway::{
Gateway, GatewayBond, GatewayBondResponse, GatewayConfigUpdate, GatewayOwnershipResponse, Gateway, GatewayBond, GatewayBondResponse, GatewayConfigUpdate, GatewayOwnershipResponse,
PagedGatewayResponse, PagedGatewayResponse,
}; };
pub use interval::{ pub use interval::{
CurrentIntervalResponse, EpochState, EpochStatus, Interval, NumberOfPendingEventsResponse, CurrentIntervalResponse, EpochId, EpochState, EpochStatus, Interval, IntervalId,
PendingEpochEventResponse, PendingEpochEventsResponse, PendingIntervalEventResponse,
PendingIntervalEventsResponse,
}; };
pub use mixnode::{ pub use mixnode::{
Layer, MixNode, MixNodeBond, MixNodeConfigUpdate, MixNodeCostParams, MixNodeDetails, Layer, MixNode, MixNodeBond, MixNodeConfigUpdate, MixNodeCostParams, MixNodeDetails,
MixNodeRewarding, MixOwnershipResponse, MixnodeDetailsResponse, PagedMixnodeBondsResponse, MixNodeRewarding, MixOwnershipResponse, MixnodeDetailsByIdentityResponse,
RewardedSetNodeStatus, UnbondedMixnode, MixnodeDetailsResponse, PagedMixnodeBondsResponse, RewardedSetNodeStatus, UnbondedMixnode,
}; };
pub use msg::*; pub use msg::*;
pub use pending_events::{ pub use pending_events::{
PendingEpochEvent, PendingEpochEventData, PendingEpochEventKind, PendingIntervalEvent, EpochEventId, IntervalEventId, NumberOfPendingEventsResponse, PendingEpochEvent,
PendingIntervalEventData, PendingIntervalEventKind, PendingEpochEventData, PendingEpochEventKind, PendingEpochEventResponse,
PendingEpochEventsResponse, PendingIntervalEvent, PendingIntervalEventData,
PendingIntervalEventKind, PendingIntervalEventResponse, PendingIntervalEventsResponse,
}; };
pub use reward_params::{IntervalRewardParams, IntervalRewardingParamsUpdate, RewardingParams}; pub use reward_params::{IntervalRewardParams, IntervalRewardingParamsUpdate, RewardingParams};
pub use rewarding::{
EstimatedCurrentEpochRewardResponse, PagedRewardedSetResponse, PendingRewardResponse,
};
pub use signing_types::*; pub use signing_types::*;
pub use types::*; pub use types::*;
@@ -11,19 +11,24 @@ use crate::reward_params::{NodeRewardParams, RewardingParams};
use crate::rewarding::helpers::truncate_reward; use crate::rewarding::helpers::truncate_reward;
use crate::rewarding::RewardDistribution; use crate::rewarding::RewardDistribution;
use crate::{Delegation, EpochEventId, EpochId, IdentityKey, MixId, Percent, SphinxKey}; use crate::{Delegation, EpochEventId, EpochId, IdentityKey, MixId, Percent, SphinxKey};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Addr, Coin, Decimal, StdResult, Uint128}; use cosmwasm_std::{Addr, Coin, Decimal, StdResult, Uint128};
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_repr::{Deserialize_repr, Serialize_repr};
/// Current state of given node in the rewarded set.
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))] #[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr( #[cfg_attr(
feature = "generate-ts", feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/RewardedSetNodeStatus.ts") ts(export_to = "ts-packages/types/src/types/rust/RewardedSetNodeStatus.ts")
)] )]
#[derive(Clone, Copy, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq)] #[cw_serde]
#[derive(Copy)]
pub enum RewardedSetNodeStatus { pub enum RewardedSetNodeStatus {
/// Node that is currently active, i.e. is expected to be used by clients for mixing packets.
Active, Active,
/// Node that is currently in standby, i.e. it's present in the rewarded set but is not active.
Standby, Standby,
} }
@@ -33,10 +38,16 @@ impl RewardedSetNodeStatus {
} }
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] /// Full details associated with given mixnode.
#[cw_serde]
pub struct MixNodeDetails { pub struct MixNodeDetails {
/// Basic bond information of this mixnode, such as owner address, original pledge, etc.
pub bond_information: MixNodeBond, pub bond_information: MixNodeBond,
/// Details used for computation of rewarding related data.
pub rewarding_details: MixNodeRewarding, pub rewarding_details: MixNodeRewarding,
/// Adjustments to the mixnode that are ought to happen during future epoch transitions.
#[serde(default)] #[serde(default)]
pub pending_changes: PendingMixNodeChanges, pub pending_changes: PendingMixNodeChanges,
} }
@@ -58,6 +69,10 @@ impl MixNodeDetails {
self.bond_information.mix_id self.bond_information.mix_id
} }
pub fn layer(&self) -> Layer {
self.bond_information.layer
}
pub fn is_unbonding(&self) -> bool { pub fn is_unbonding(&self) -> bool {
self.bond_information.is_unbonding self.bond_information.is_unbonding
} }
@@ -86,7 +101,7 @@ impl MixNodeDetails {
} }
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] #[cw_serde]
pub struct MixNodeRewarding { pub struct MixNodeRewarding {
/// Information provided by the operator that influence the cost function. /// Information provided by the operator that influence the cost function.
pub cost_params: MixNodeCostParams, pub cost_params: MixNodeCostParams,
@@ -464,8 +479,8 @@ impl MixNodeRewarding {
} }
} }
// operator information + data assigned by the contract(s) /// Basic mixnode information provided by the node operator.
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] #[cw_serde]
pub struct MixNodeBond { pub struct MixNodeBond {
/// Unique id assigned to the bonded mixnode. /// Unique id assigned to the bonded mixnode.
pub mix_id: MixId, pub mix_id: MixId,
@@ -533,21 +548,24 @@ impl MixNodeBond {
} }
} }
// information provided by the operator /// Information provided by the node operator during bonding that are used to allow other entities to use the services of this node.
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] #[cw_serde]
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))] #[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr( #[cfg_attr(
feature = "generate-ts", feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/Mixnode.ts") ts(export_to = "ts-packages/types/src/types/rust/Mixnode.ts")
)] )]
pub struct MixNode { pub struct MixNode {
/// Network address of this mixnode, for example 1.1.1.1:1234 or foo.mixnode.com /// Network address of this mixnode, for example 1.1.1.1 or foo.mixnode.com
pub host: String, pub host: String,
/// Port used by this mixnode for listening for mix packets.
pub mix_port: u16, pub mix_port: u16,
/// Port used by this mixnode for listening for verloc requests.
pub verloc_port: u16, pub verloc_port: u16,
/// Port used by this mixnode for its http(s) API
pub http_api_port: u16, pub http_api_port: u16,
/// Base58-encoded x25519 public key used for sphinx key derivation. /// Base58-encoded x25519 public key used for sphinx key derivation.
@@ -556,11 +574,15 @@ pub struct MixNode {
/// Base58-encoded ed25519 EdDSA public key. /// Base58-encoded ed25519 EdDSA public key.
pub identity_key: IdentityKey, pub identity_key: IdentityKey,
/// The self-reported semver version of this mixnode.
pub version: String, pub version: String,
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] /// The cost parameters, or the cost function, defined for the particular mixnode that influences
/// how the rewards should be split between the node operator and its delegators.
#[cw_serde]
pub struct MixNodeCostParams { pub struct MixNodeCostParams {
/// The profit margin of the associated mixnode, i.e. the desired percent of the reward to be distributed to the operator.
pub profit_margin_percent: Percent, pub profit_margin_percent: Percent,
/// Operating cost of the associated mixnode per the entire interval. /// Operating cost of the associated mixnode per the entire interval.
@@ -633,7 +655,8 @@ impl From<Layer> for u8 {
feature = "generate-ts", feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/PendingMixnodeChanges.ts") ts(export_to = "ts-packages/types/src/types/rust/PendingMixnodeChanges.ts")
)] )]
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] #[cw_serde]
#[derive(Default, Copy)]
pub struct PendingMixNodeChanges { pub struct PendingMixNodeChanges {
pub pledge_change: Option<EpochEventId>, pub pledge_change: Option<EpochEventId>,
// pub cost_params_change: Option<IntervalEventId>, // pub cost_params_change: Option<IntervalEventId>,
@@ -647,21 +670,27 @@ impl PendingMixNodeChanges {
} }
} }
/// Basic information of a node that used to be part of the mix network but has already unbonded.
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))] #[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr( #[cfg_attr(
feature = "generate-ts", feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/UnbondedMixnode.ts") ts(export_to = "ts-packages/types/src/types/rust/UnbondedMixnode.ts")
)] )]
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] #[cw_serde]
pub struct UnbondedMixnode { pub struct UnbondedMixnode {
/// Base58-encoded ed25519 EdDSA public key.
pub identity_key: IdentityKey, pub identity_key: IdentityKey,
/// Address of the owner of this mixnode.
#[cfg_attr(feature = "generate-ts", ts(type = "string"))] #[cfg_attr(feature = "generate-ts", ts(type = "string"))]
pub owner: Addr, pub owner: Addr,
/// Entity who bonded this mixnode on behalf of the owner.
/// If exists, it's most likely the address of the vesting contract.
#[cfg_attr(feature = "generate-ts", ts(type = "string | null"))] #[cfg_attr(feature = "generate-ts", ts(type = "string | null"))]
pub proxy: Option<Addr>, pub proxy: Option<Addr>,
/// Block height at which this mixnode has unbonded.
#[cfg_attr(feature = "generate-ts", ts(type = "number"))] #[cfg_attr(feature = "generate-ts", ts(type = "number"))]
pub unbonding_height: u64, pub unbonding_height: u64,
} }
@@ -671,7 +700,7 @@ pub struct UnbondedMixnode {
feature = "generate-ts", feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/MixNodeConfigUpdate.ts") ts(export_to = "ts-packages/types/src/types/rust/MixNodeConfigUpdate.ts")
)] )]
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] #[cw_serde]
pub struct MixNodeConfigUpdate { pub struct MixNodeConfigUpdate {
pub host: String, pub host: String,
pub mix_port: u16, pub mix_port: u16,
@@ -686,10 +715,17 @@ impl MixNodeConfigUpdate {
} }
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] /// Response containing paged list of all mixnode bonds in the contract.
#[cw_serde]
pub struct PagedMixnodeBondsResponse { pub struct PagedMixnodeBondsResponse {
/// The mixnode bond information present in the contract.
pub nodes: Vec<MixNodeBond>, pub nodes: Vec<MixNodeBond>,
/// Maximum number of entries that could be included in a response. `per_page <= nodes.len()`
// this field is rather redundant and should be deprecated.
pub per_page: usize, pub per_page: usize,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<MixId>, pub start_next_after: Option<MixId>,
} }
@@ -703,10 +739,19 @@ impl PagedMixnodeBondsResponse {
} }
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] /// Response containing paged list of all mixnode details in the contract.
#[cw_serde]
pub struct PagedMixnodesDetailsResponse { pub struct PagedMixnodesDetailsResponse {
/// All mixnode details stored in the contract.
/// Apart from the basic bond information it also contains details required for all future reward calculation
/// as well as any pending changes requested by the operator.
pub nodes: Vec<MixNodeDetails>, pub nodes: Vec<MixNodeDetails>,
/// Maximum number of entries that could be included in a response. `per_page <= nodes.len()`
// this field is rather redundant and should be deprecated.
pub per_page: usize, pub per_page: usize,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<MixId>, pub start_next_after: Option<MixId>,
} }
@@ -724,10 +769,17 @@ impl PagedMixnodesDetailsResponse {
} }
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] /// Response containing paged list of all mixnodes that have ever unbonded.
#[cw_serde]
pub struct PagedUnbondedMixnodesResponse { pub struct PagedUnbondedMixnodesResponse {
/// The past ids of unbonded mixnodes alongside their basic information such as the owner or the identity key.
pub nodes: Vec<(MixId, UnbondedMixnode)>, pub nodes: Vec<(MixId, UnbondedMixnode)>,
/// Maximum number of entries that could be included in a response. `per_page <= nodes.len()`
// this field is rather redundant and should be deprecated.
pub per_page: usize, pub per_page: usize,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<MixId>, pub start_next_after: Option<MixId>,
} }
@@ -745,33 +797,68 @@ impl PagedUnbondedMixnodesResponse {
} }
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] /// Response containing details of a mixnode belonging to the particular owner.
#[cw_serde]
pub struct MixOwnershipResponse { pub struct MixOwnershipResponse {
/// Validated address of the mixnode owner.
pub address: Addr, pub address: Addr,
/// If the provided address owns a mixnode, this field contains its detailed information.
pub mixnode_details: Option<MixNodeDetails>, pub mixnode_details: Option<MixNodeDetails>,
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] /// Response containing details of a mixnode with the provided id.
#[cw_serde]
pub struct MixnodeDetailsResponse { pub struct MixnodeDetailsResponse {
/// Id of the requested mixnode.
pub mix_id: MixId, pub mix_id: MixId,
/// If there exists a mixnode with the provided id, this field contains its detailed information.
pub mixnode_details: Option<MixNodeDetails>, pub mixnode_details: Option<MixNodeDetails>,
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] /// Response containing details of a bonded mixnode with the provided identity key.
#[cw_serde]
pub struct MixnodeDetailsByIdentityResponse {
/// The identity key (base58-encoded ed25519 public key) of the mixnode.
pub identity_key: IdentityKey,
/// If there exists a bonded mixnode with the provided identity key, this field contains its detailed information.
pub mixnode_details: Option<MixNodeDetails>,
}
/// Response containing rewarding information of a mixnode with the provided id.
#[cw_serde]
pub struct MixnodeRewardingDetailsResponse { pub struct MixnodeRewardingDetailsResponse {
/// Id of the requested mixnode.
pub mix_id: MixId, pub mix_id: MixId,
/// If there exists a mixnode with the provided id, this field contains its rewarding information.
pub rewarding_details: Option<MixNodeRewarding>, pub rewarding_details: Option<MixNodeRewarding>,
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] /// Response containing basic information of an unbonded mixnode with the provided id.
#[cw_serde]
pub struct UnbondedMixnodeResponse { pub struct UnbondedMixnodeResponse {
/// Id of the requested mixnode.
pub mix_id: MixId, pub mix_id: MixId,
/// If there existed a mixnode with the provided id, this field contains its basic information.
pub unbonded_info: Option<UnbondedMixnode>, pub unbonded_info: Option<UnbondedMixnode>,
} }
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)] /// Response containing the current state of the stake saturation of a mixnode with the provided id.
#[cw_serde]
pub struct StakeSaturationResponse { pub struct StakeSaturationResponse {
/// Id of the requested mixnode.
pub mix_id: MixId, pub mix_id: MixId,
/// The current stake saturation of this node that is indirectly used in reward calculation formulas.
/// Note that it can't be larger than 1.
pub current_saturation: Option<Decimal>, pub current_saturation: Option<Decimal>,
/// The current, absolute, stake saturation of this node.
/// Note that as the name suggests it can be larger than 1.
/// However, anything beyond that value has no effect on the total node reward.
pub uncapped_saturation: Option<Decimal>, pub uncapped_saturation: Option<Decimal>,
} }
@@ -1,28 +1,54 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::delegation::OwnerProxySubKey; use crate::delegation::{self, OwnerProxySubKey};
use crate::error::MixnetContractError; use crate::error::MixnetContractError;
use crate::families::FamilyHead; use crate::families::FamilyHead;
use crate::gateway::GatewayConfigUpdate; use crate::gateway::{Gateway, GatewayConfigUpdate};
use crate::helpers::IntoBaseDecimal; use crate::helpers::IntoBaseDecimal;
use crate::mixnode::{MixNodeConfigUpdate, MixNodeCostParams}; use crate::mixnode::{Layer, MixNode, MixNodeConfigUpdate, MixNodeCostParams};
use crate::pending_events::{EpochEventId, IntervalEventId};
use crate::reward_params::{ use crate::reward_params::{
IntervalRewardParams, IntervalRewardingParamsUpdate, Performance, RewardingParams, IntervalRewardParams, IntervalRewardingParamsUpdate, Performance, RewardingParams,
}; };
use crate::{ use crate::types::{ContractStateParams, LayerAssignment, MixId};
delegation, ContractStateParams, EpochEventId, IntervalEventId, Layer, LayerAssignment, MixId, use contracts_common::{signing::MessageSignature, IdentityKey, Percent};
Percent, use cosmwasm_schema::cw_serde;
};
use crate::{Gateway, IdentityKey, MixNode};
use contracts_common::signing::MessageSignature;
use cosmwasm_std::{Coin, Decimal}; use cosmwasm_std::{Coin, Decimal};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::time::Duration; use std::time::Duration;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[cfg(feature = "schema")]
#[serde(rename_all = "snake_case")] use crate::{
delegation::{
MixNodeDelegationResponse, PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse,
PagedMixNodeDelegationsResponse,
},
families::{
FamilyByHeadResponse, FamilyByLabelResponse, FamilyMembersByHeadResponse,
FamilyMembersByLabelResponse, PagedFamiliesResponse, PagedMembersResponse,
},
gateway::{GatewayBondResponse, GatewayOwnershipResponse, PagedGatewayResponse},
interval::{CurrentIntervalResponse, EpochStatus},
mixnode::{
MixOwnershipResponse, MixnodeDetailsByIdentityResponse, MixnodeDetailsResponse,
MixnodeRewardingDetailsResponse, PagedMixnodeBondsResponse, PagedMixnodesDetailsResponse,
PagedUnbondedMixnodesResponse, StakeSaturationResponse, UnbondedMixnodeResponse,
},
pending_events::{
NumberOfPendingEventsResponse, PendingEpochEventResponse, PendingEpochEventsResponse,
PendingIntervalEventResponse, PendingIntervalEventsResponse,
},
rewarding::{
EstimatedCurrentEpochRewardResponse, PagedRewardedSetResponse, PendingRewardResponse,
},
types::{ContractState, LayerDistribution},
};
#[cfg(feature = "schema")]
use contracts_common::{signing::Nonce, ContractBuildInformation};
#[cfg(feature = "schema")]
use cosmwasm_schema::QueryResponses;
#[cw_serde]
pub struct InstantiateMsg { pub struct InstantiateMsg {
pub rewarding_validator_address: String, pub rewarding_validator_address: String,
pub vesting_contract_address: String, pub vesting_contract_address: String,
@@ -33,8 +59,7 @@ pub struct InstantiateMsg {
pub initial_rewarding_params: InitialRewardingParams, pub initial_rewarding_params: InitialRewardingParams,
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub struct InitialRewardingParams { pub struct InitialRewardingParams {
pub initial_reward_pool: Decimal, pub initial_reward_pool: Decimal,
pub initial_staking_supply: Decimal, pub initial_staking_supply: Decimal,
@@ -76,8 +101,7 @@ impl InitialRewardingParams {
} }
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg { pub enum ExecuteMsg {
AssignNodeLayer { AssignNodeLayer {
mix_id: MixId, mix_id: MixId,
@@ -365,177 +389,376 @@ impl ExecuteMsg {
} }
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[cw_serde]
#[serde(rename_all = "snake_case")] #[cfg_attr(feature = "schema", derive(QueryResponses))]
pub enum QueryMsg { pub enum QueryMsg {
// families // families
/// Gets the list of families registered in this contract.
#[cfg_attr(feature = "schema", returns(PagedFamiliesResponse))]
GetAllFamiliesPaged { GetAllFamiliesPaged {
/// Controls the maximum number of entries returned by the query. Note that too large values will be overwritten by a saner default.
limit: Option<u32>, limit: Option<u32>,
/// Pagination control for the values returned by the query. Note that the provided value itself will **not** be used for the response.
start_after: Option<String>, start_after: Option<String>,
}, },
/// Gets the list of all family members registered in this contract.
#[cfg_attr(feature = "schema", returns(PagedMembersResponse))]
GetAllMembersPaged { GetAllMembersPaged {
/// Controls the maximum number of entries returned by the query. Note that too large values will be overwritten by a saner default.
limit: Option<u32>, limit: Option<u32>,
/// Pagination control for the values returned by the query. Note that the provided value itself will **not** be used for the response.
start_after: Option<String>, start_after: Option<String>,
}, },
GetFamilyByHead {
head: String, /// Attempts to lookup family information given the family head.
}, #[cfg_attr(feature = "schema", returns(FamilyByHeadResponse))]
GetFamilyByLabel { GetFamilyByHead { head: String },
label: String,
}, /// Attempts to lookup family information given the family label.
GetFamilyMembersByHead { #[cfg_attr(feature = "schema", returns(FamilyByLabelResponse))]
head: String, GetFamilyByLabel { label: String },
},
GetFamilyMembersByLabel { /// Attempts to retrieve family members given the family head.
label: String, #[cfg_attr(feature = "schema", returns(FamilyMembersByHeadResponse))]
}, GetFamilyMembersByHead { head: String },
/// Attempts to retrieve family members given the family label.
#[cfg_attr(feature = "schema", returns(FamilyMembersByLabelResponse))]
GetFamilyMembersByLabel { label: String },
// state/sys-params-related // state/sys-params-related
/// Gets build information of this contract, such as the commit hash used for the build or rustc version.
#[cfg_attr(feature = "schema", returns(ContractBuildInformation))]
GetContractVersion {}, GetContractVersion {},
/// Gets the stored contract version information that's required by the CW2 spec interface for migrations.
#[serde(rename = "get_cw2_contract_version")] #[serde(rename = "get_cw2_contract_version")]
#[cfg_attr(feature = "schema", returns(cw2::ContractVersion))]
GetCW2ContractVersion {}, GetCW2ContractVersion {},
/// Gets the address of the validator that's allowed to send rewarding transactions and transition the epoch.
#[cfg_attr(feature = "schema", returns(String))]
GetRewardingValidatorAddress {}, GetRewardingValidatorAddress {},
/// Gets the contract parameters that could be adjusted in a transaction by the contract admin.
#[cfg_attr(feature = "schema", returns(ContractStateParams))]
GetStateParams {}, GetStateParams {},
/// Gets the current state of the contract.
#[cfg_attr(feature = "schema", returns(ContractState))]
GetState {}, GetState {},
/// Gets the current parameters used for reward calculation.
#[cfg_attr(feature = "schema", returns(RewardingParams))]
GetRewardingParams {}, GetRewardingParams {},
/// Gets the status of the current rewarding epoch.
#[cfg_attr(feature = "schema", returns(EpochStatus))]
GetEpochStatus {}, GetEpochStatus {},
/// Get the details of the current rewarding interval.
#[cfg_attr(feature = "schema", returns(CurrentIntervalResponse))]
GetCurrentIntervalDetails {}, GetCurrentIntervalDetails {},
/// Gets the current list of mixnodes in the rewarded set.
#[cfg_attr(feature = "schema", returns(PagedRewardedSetResponse))]
GetRewardedSet { GetRewardedSet {
/// Controls the maximum number of entries returned by the query. Note that too large values will be overwritten by a saner default.
limit: Option<u32>, limit: Option<u32>,
/// Pagination control for the values returned by the query. Note that the provided value itself will **not** be used for the response.
start_after: Option<MixId>, start_after: Option<MixId>,
}, },
// mixnode-related: // mixnode-related:
/// Gets the basic list of all currently bonded mixnodes.
#[cfg_attr(feature = "schema", returns(PagedMixnodeBondsResponse))]
GetMixNodeBonds { GetMixNodeBonds {
/// Controls the maximum number of entries returned by the query. Note that too large values will be overwritten by a saner default.
limit: Option<u32>, limit: Option<u32>,
/// Pagination control for the values returned by the query. Note that the provided value itself will **not** be used for the response.
start_after: Option<MixId>, start_after: Option<MixId>,
}, },
/// Gets the detailed list of all currently bonded mixnodes.
#[cfg_attr(feature = "schema", returns(PagedMixnodesDetailsResponse))]
GetMixNodesDetailed { GetMixNodesDetailed {
/// Controls the maximum number of entries returned by the query. Note that too large values will be overwritten by a saner default.
limit: Option<u32>, limit: Option<u32>,
/// Pagination control for the values returned by the query. Note that the provided value itself will **not** be used for the response.
start_after: Option<MixId>, start_after: Option<MixId>,
}, },
/// Gets the basic list of all unbonded mixnodes.
#[cfg_attr(feature = "schema", returns(PagedUnbondedMixnodesResponse))]
GetUnbondedMixNodes { GetUnbondedMixNodes {
/// Controls the maximum number of entries returned by the query. Note that too large values will be overwritten by a saner default.
limit: Option<u32>, limit: Option<u32>,
/// Pagination control for the values returned by the query. Note that the provided value itself will **not** be used for the response.
start_after: Option<MixId>, start_after: Option<MixId>,
}, },
/// Gets the basic list of all unbonded mixnodes that belonged to a particular owner.
#[cfg_attr(feature = "schema", returns(PagedUnbondedMixnodesResponse))]
GetUnbondedMixNodesByOwner { GetUnbondedMixNodesByOwner {
/// The address of the owner of the the mixnodes used for the query.
owner: String, owner: String,
/// Controls the maximum number of entries returned by the query. Note that too large values will be overwritten by a saner default.
limit: Option<u32>, limit: Option<u32>,
/// Pagination control for the values returned by the query. Note that the provided value itself will **not** be used for the response.
start_after: Option<MixId>, start_after: Option<MixId>,
}, },
/// Gets the basic list of all unbonded mixnodes that used the particular identity key.
#[cfg_attr(feature = "schema", returns(PagedUnbondedMixnodesResponse))]
GetUnbondedMixNodesByIdentityKey { GetUnbondedMixNodesByIdentityKey {
/// The identity key (base58-encoded ed25519 public key) of the mixnode used for the query.
identity_key: String, identity_key: String,
/// Controls the maximum number of entries returned by the query. Note that too large values will be overwritten by a saner default.
limit: Option<u32>, limit: Option<u32>,
/// Pagination control for the values returned by the query. Note that the provided value itself will **not** be used for the response.
start_after: Option<MixId>, start_after: Option<MixId>,
}, },
/// Gets the detailed mixnode information belonging to the particular owner.
#[cfg_attr(feature = "schema", returns(MixOwnershipResponse))]
GetOwnedMixnode { GetOwnedMixnode {
/// Address of the mixnode owner to use for the query.
address: String, address: String,
}, },
/// Gets the detailed mixnode information of a node with the provided id.
#[cfg_attr(feature = "schema", returns(MixnodeDetailsResponse))]
GetMixnodeDetails { GetMixnodeDetails {
/// Id of the node to query.
mix_id: MixId, mix_id: MixId,
}, },
/// Gets the rewarding information of a mixnode with the provided id.
#[cfg_attr(feature = "schema", returns(MixnodeRewardingDetailsResponse))]
GetMixnodeRewardingDetails { GetMixnodeRewardingDetails {
/// Id of the node to query.
mix_id: MixId, mix_id: MixId,
}, },
/// Gets the stake saturation of a mixnode with the provided id.
#[cfg_attr(feature = "schema", returns(StakeSaturationResponse))]
GetStakeSaturation { GetStakeSaturation {
/// Id of the node to query.
mix_id: MixId, mix_id: MixId,
}, },
/// Gets the basic information of an unbonded mixnode with the provided id.
#[cfg_attr(feature = "schema", returns(UnbondedMixnodeResponse))]
GetUnbondedMixNodeInformation { GetUnbondedMixNodeInformation {
/// Id of the node to query.
mix_id: MixId, mix_id: MixId,
}, },
/// Gets the detailed mixnode information of a node given its current identity key.
#[cfg_attr(feature = "schema", returns(MixnodeDetailsByIdentityResponse))]
GetBondedMixnodeDetailsByIdentity { GetBondedMixnodeDetailsByIdentity {
/// The identity key (base58-encoded ed25519 public key) of the mixnode used for the query.
mix_identity: IdentityKey, mix_identity: IdentityKey,
}, },
/// Gets the current layer configuration of the mix network.
#[cfg_attr(feature = "schema", returns(LayerDistribution))]
GetLayerDistribution {}, GetLayerDistribution {},
// gateway-related: // gateway-related:
/// Gets the basic list of all currently bonded gateways.
#[cfg_attr(feature = "schema", returns(PagedGatewayResponse))]
GetGateways { GetGateways {
/// Pagination control for the values returned by the query. Note that the provided value itself will **not** be used for the response.
start_after: Option<IdentityKey>, start_after: Option<IdentityKey>,
/// Controls the maximum number of entries returned by the query. Note that too large values will be overwritten by a saner default.
limit: Option<u32>, limit: Option<u32>,
}, },
/// Gets the gateway details of a node given its identity key.
#[cfg_attr(feature = "schema", returns(GatewayBondResponse))]
GetGatewayBond { GetGatewayBond {
/// The identity key (base58-encoded ed25519 public key) of the gateway used for the query.
identity: IdentityKey, identity: IdentityKey,
}, },
/// Gets the detailed gateway information belonging to the particular owner.
#[cfg_attr(feature = "schema", returns(GatewayOwnershipResponse))]
GetOwnedGateway { GetOwnedGateway {
/// Address of the gateway owner to use for the query.
address: String, address: String,
}, },
// delegation-related: // delegation-related:
// gets all [paged] delegations associated with particular mixnode /// Gets all delegations associated with particular mixnode
#[cfg_attr(feature = "schema", returns(PagedMixNodeDelegationsResponse))]
GetMixnodeDelegations { GetMixnodeDelegations {
/// Id of the node to query.
mix_id: MixId, mix_id: MixId,
// since `start_after` is user-provided input, we can't use `Addr` as we
// can't guarantee it's validated. /// Pagination control for the values returned by the query. Note that the provided value itself will **not** be used for the response.
start_after: Option<String>, start_after: Option<OwnerProxySubKey>,
/// Controls the maximum number of entries returned by the query. Note that too large values will be overwritten by a saner default.
limit: Option<u32>, limit: Option<u32>,
}, },
// gets all [paged] delegations associated with particular delegator
/// Gets all delegations associated with particular delegator
#[cfg_attr(feature = "schema", returns(PagedDelegatorDelegationsResponse))]
GetDelegatorDelegations { GetDelegatorDelegations {
// since `delegator` is user-provided input, we can't use `Addr` as we // since `delegator` is user-provided input, we can't use `Addr` as we
// can't guarantee it's validated. // can't guarantee it's validated.
/// The address of the owner of the delegations.
delegator: String, delegator: String,
/// Pagination control for the values returned by the query. Note that the provided value itself will **not** be used for the response.
start_after: Option<(MixId, OwnerProxySubKey)>, start_after: Option<(MixId, OwnerProxySubKey)>,
/// Controls the maximum number of entries returned by the query. Note that too large values will be overwritten by a saner default.
limit: Option<u32>, limit: Option<u32>,
}, },
// gets delegation associated with particular mixnode, delegator pair
/// Gets delegation information associated with particular mixnode - delegator pair
#[cfg_attr(feature = "schema", returns(MixNodeDelegationResponse))]
GetDelegationDetails { GetDelegationDetails {
/// Id of the node to query.
mix_id: MixId, mix_id: MixId,
/// The address of the owner of the delegation.
delegator: String, delegator: String,
/// Entity who made the delegation on behalf of the owner.
/// If present, it's most likely the address of the vesting contract.
proxy: Option<String>, proxy: Option<String>,
}, },
// gets all delegations in the system
/// Gets all delegations in the system
#[cfg_attr(feature = "schema", returns(PagedAllDelegationsResponse))]
GetAllDelegations { GetAllDelegations {
/// Pagination control for the values returned by the query. Note that the provided value itself will **not** be used for the response.
start_after: Option<delegation::StorageKey>, start_after: Option<delegation::StorageKey>,
/// Controls the maximum number of entries returned by the query. Note that too large values will be overwritten by a saner default.
limit: Option<u32>, limit: Option<u32>,
}, },
// rewards related // rewards related
/// Gets the reward amount accrued by the node operator that has not yet been claimed.
#[cfg_attr(feature = "schema", returns(PendingRewardResponse))]
GetPendingOperatorReward { GetPendingOperatorReward {
/// Address of the operator to use for the query.
address: String, address: String,
}, },
/// Gets the reward amount accrued by the particular mixnode that has not yet been claimed.
#[cfg_attr(feature = "schema", returns(PendingRewardResponse))]
GetPendingMixNodeOperatorReward { GetPendingMixNodeOperatorReward {
/// Id of the node to query.
mix_id: MixId, mix_id: MixId,
}, },
/// Gets the reward amount accrued by the particular delegator that has not yet been claimed.
#[cfg_attr(feature = "schema", returns(PendingRewardResponse))]
GetPendingDelegatorReward { GetPendingDelegatorReward {
/// Address of the delegator to use for the query.
address: String, address: String,
/// Id of the node to query.
mix_id: MixId, mix_id: MixId,
/// Entity who made the delegation on behalf of the owner.
/// If present, it's most likely the address of the vesting contract.
proxy: Option<String>, proxy: Option<String>,
}, },
// given the provided performance, estimate the reward at the end of the current epoch
/// Given the provided node performance, attempt to estimate the operator reward for the current epoch.
#[cfg_attr(feature = "schema", returns(EstimatedCurrentEpochRewardResponse))]
GetEstimatedCurrentEpochOperatorReward { GetEstimatedCurrentEpochOperatorReward {
/// Id of the node to query.
mix_id: MixId, mix_id: MixId,
/// The estimated performance for the current epoch of the given node.
estimated_performance: Performance, estimated_performance: Performance,
}, },
/// Given the provided node performance, attempt to estimate the delegator reward for the current epoch.
#[cfg_attr(feature = "schema", returns(EstimatedCurrentEpochRewardResponse))]
GetEstimatedCurrentEpochDelegatorReward { GetEstimatedCurrentEpochDelegatorReward {
/// Address of the delegator to use for the query.
address: String, address: String,
/// Id of the node to query.
mix_id: MixId, mix_id: MixId,
/// Entity who made the delegation on behalf of the owner.
/// If present, it's most likely the address of the vesting contract.
proxy: Option<String>, proxy: Option<String>,
/// The estimated performance for the current epoch of the given node.
estimated_performance: Performance, estimated_performance: Performance,
}, },
// interval-related // interval-related
/// Gets the list of all currently pending epoch events that will be resolved once the current epoch finishes.
#[cfg_attr(feature = "schema", returns(PendingEpochEventsResponse))]
GetPendingEpochEvents { GetPendingEpochEvents {
/// Controls the maximum number of entries returned by the query. Note that too large values will be overwritten by a saner default.
limit: Option<u32>, limit: Option<u32>,
/// Pagination control for the values returned by the query. Note that the provided value itself will **not** be used for the response.
start_after: Option<u32>, start_after: Option<u32>,
}, },
/// Gets the list of all currently pending interval events that will be resolved once the current interval finishes.
#[cfg_attr(feature = "schema", returns(PendingIntervalEventsResponse))]
GetPendingIntervalEvents { GetPendingIntervalEvents {
/// Controls the maximum number of entries returned by the query. Note that too large values will be overwritten by a saner default.
limit: Option<u32>, limit: Option<u32>,
/// Pagination control for the values returned by the query. Note that the provided value itself will **not** be used for the response.
start_after: Option<u32>, start_after: Option<u32>,
}, },
/// Gets detailed information about a pending epoch event given its id.
#[cfg_attr(feature = "schema", returns(PendingEpochEventResponse))]
GetPendingEpochEvent { GetPendingEpochEvent {
/// The unique id associated with the event.
event_id: EpochEventId, event_id: EpochEventId,
}, },
/// Gets detailed information about a pending interval event given its id.
#[cfg_attr(feature = "schema", returns(PendingIntervalEventResponse))]
GetPendingIntervalEvent { GetPendingIntervalEvent {
/// The unique id associated with the event.
event_id: IntervalEventId, event_id: IntervalEventId,
}, },
/// Gets the information about the number of currently pending epoch and interval events.
#[cfg_attr(feature = "schema", returns(NumberOfPendingEventsResponse))]
GetNumberOfPendingEvents {}, GetNumberOfPendingEvents {},
// signing-related // signing-related
/// Gets the signing nonce associated with the particular cosmos address.
#[cfg_attr(feature = "schema", returns(Nonce))]
GetSigningNonce { GetSigningNonce {
/// Cosmos address used for the query of the signing nonce.
address: String, address: String,
}, },
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub struct MigrateMsg { pub struct MigrateMsg {
pub vesting_contract_address: Option<String>, pub vesting_contract_address: Option<String>,
} }
@@ -3,49 +3,95 @@
use crate::mixnode::MixNodeCostParams; use crate::mixnode::MixNodeCostParams;
use crate::reward_params::IntervalRewardingParamsUpdate; use crate::reward_params::IntervalRewardingParamsUpdate;
use crate::{BlockHeight, EpochEventId, IntervalEventId, MixId}; use crate::{BlockHeight, MixId};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Addr, Coin}; use cosmwasm_std::{Addr, Coin};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] pub type EpochEventId = u32;
pub type IntervalEventId = u32;
/// A request made at some point in the current epoch that's going to get resolved once the epoch rolls over.
#[cw_serde]
pub struct PendingEpochEvent { pub struct PendingEpochEvent {
/// The unique id associated with the event.
pub id: EpochEventId, pub id: EpochEventId,
/// The underlying event details, containing its type and information on how it should get resolved.
pub event: PendingEpochEventData, pub event: PendingEpochEventData,
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] /// Details of a particular pending epoch event.
#[cw_serde]
pub struct PendingEpochEventData { pub struct PendingEpochEventData {
/// The block height at which the request has been made.
pub created_at: BlockHeight, pub created_at: BlockHeight,
/// The underlying event data, containing its concrete type and information on how it should get resolved.
pub kind: PendingEpochEventKind, pub kind: PendingEpochEventKind,
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] /// Enum encompassing all possible epoch events.
#[cw_serde]
pub enum PendingEpochEventKind { pub enum PendingEpochEventKind {
// can't just pass the `Delegation` struct here as it's impossible to determine // can't just pass the `Delegation` struct here as it's impossible to determine
// `cumulative_reward_ratio` ahead of time // `cumulative_reward_ratio` ahead of time
/// Request to create a delegation towards particular mixnode.
/// Note that if such delegation already exists, it will get updated with the provided token amount.
Delegate { Delegate {
/// The address of the owner of the delegation.
owner: Addr, owner: Addr,
/// The id of the mixnode used for the delegation.
mix_id: MixId, mix_id: MixId,
/// The amount of tokens to use for the delegation.
amount: Coin, amount: Coin,
/// Entity who made the delegation on behalf of the owner.
/// If present, it's most likely the address of the vesting contract.
proxy: Option<Addr>, proxy: Option<Addr>,
}, },
/// Request to remove delegation from particular mixnode.
Undelegate { Undelegate {
/// The address of the owner of the delegation.
owner: Addr, owner: Addr,
/// The id of the mixnode used for the delegation.
mix_id: MixId, mix_id: MixId,
/// Entity who made the delegation on behalf of the owner.
/// If present, it's most likely the address of the vesting contract.
proxy: Option<Addr>, proxy: Option<Addr>,
}, },
/// Request to pledge more tokens (by the node operator) towards its node.
PledgeMore { PledgeMore {
/// The id of the mixnode that will have its pledge updated.
mix_id: MixId, mix_id: MixId,
/// The amount of additional tokens to use by the pledge.
amount: Coin, amount: Coin,
}, },
/// Request to decrease amount of pledged tokens (by the node operator) from its node.
DecreasePledge { DecreasePledge {
/// The id of the mixnode that will have its pledge updated.
mix_id: MixId, mix_id: MixId,
/// The amount of tokens that should be removed from the pledge.
decrease_by: Coin, decrease_by: Coin,
}, },
/// Request to unbond a mixnode and completely remove it from the network.
UnbondMixnode { UnbondMixnode {
/// The id of the mixnode that will get unbonded.
mix_id: MixId, mix_id: MixId,
}, },
/// Request to update the current size of the active set.
UpdateActiveSetSize { UpdateActiveSetSize {
/// The new desired size of the active set.
new_size: u32, new_size: u32,
}, },
} }
@@ -68,29 +114,50 @@ impl From<(EpochEventId, PendingEpochEventData)> for PendingEpochEvent {
} }
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] /// A request made at some point in the current interval that's going to get resolved once the interval rolls over.
#[cw_serde]
pub struct PendingIntervalEvent { pub struct PendingIntervalEvent {
/// The unique id associated with the event.
pub id: IntervalEventId, pub id: IntervalEventId,
/// The underlying event details, containing its type and information on how it should get resolved.
pub event: PendingIntervalEventData, pub event: PendingIntervalEventData,
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] /// Details of a particular pending interval event.
#[cw_serde]
pub struct PendingIntervalEventData { pub struct PendingIntervalEventData {
/// The block height at which the request has been made.
pub created_at: BlockHeight, pub created_at: BlockHeight,
/// The underlying event data, containing its concrete type and information on how it should get resolved.
pub kind: PendingIntervalEventKind, pub kind: PendingIntervalEventKind,
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] /// Enum encompassing all possible interval events.
#[cw_serde]
pub enum PendingIntervalEventKind { pub enum PendingIntervalEventKind {
/// Request to update cost parameters of given mixnode.
ChangeMixCostParams { ChangeMixCostParams {
/// The id of the mixnode that will have its cost parameters updated.
mix_id: MixId, mix_id: MixId,
/// The new updated cost function of this mixnode.
new_costs: MixNodeCostParams, new_costs: MixNodeCostParams,
}, },
/// Request to update the underlying rewarding parameters used by the system
UpdateRewardingParams { UpdateRewardingParams {
/// The detailed specification of the update.
update: IntervalRewardingParamsUpdate, update: IntervalRewardingParamsUpdate,
}, },
/// Request to change the next interval configuration.
UpdateIntervalConfig { UpdateIntervalConfig {
/// The new number of epochs in intervals.
epochs_in_interval: u32, epochs_in_interval: u32,
/// The new epoch duration.
epoch_duration_secs: u64, epoch_duration_secs: u64,
}, },
} }
@@ -112,3 +179,102 @@ impl From<(IntervalEventId, PendingIntervalEventData)> for PendingIntervalEvent
} }
} }
} }
/// Response containing all currently pending epoch events that will be resolved once the current epoch finishes.
#[cw_serde]
pub struct PendingEpochEventsResponse {
/// Amount of seconds until the events would be eligible to be resolved.
/// It's equivalent to the time until the current epoch finishes.
pub seconds_until_executable: i64,
/// The currently pending events.
pub events: Vec<PendingEpochEvent>,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<u32>,
}
impl PendingEpochEventsResponse {
pub fn new(
seconds_until_executable: i64,
events: Vec<PendingEpochEvent>,
start_next_after: Option<u32>,
) -> Self {
PendingEpochEventsResponse {
seconds_until_executable,
events,
start_next_after,
}
}
}
/// Response containing all currently pending interval events that will be resolved once the current interval finishes.
#[cw_serde]
pub struct PendingIntervalEventsResponse {
/// Amount of seconds until the events would be eligible to be resolved.
/// It's equivalent to the time until the current interval finishes.
pub seconds_until_executable: i64,
/// The currently pending events.
pub events: Vec<PendingIntervalEvent>,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<u32>,
}
impl PendingIntervalEventsResponse {
pub fn new(
seconds_until_executable: i64,
events: Vec<PendingIntervalEvent>,
start_next_after: Option<u32>,
) -> Self {
PendingIntervalEventsResponse {
seconds_until_executable,
events,
start_next_after,
}
}
}
#[cw_serde]
pub struct PendingEpochEventResponse {
pub event_id: EpochEventId,
pub event: Option<PendingEpochEventData>,
}
impl PendingEpochEventResponse {
pub fn new(event_id: EpochEventId, event: Option<PendingEpochEventData>) -> Self {
PendingEpochEventResponse { event_id, event }
}
}
#[cw_serde]
pub struct PendingIntervalEventResponse {
pub event_id: IntervalEventId,
pub event: Option<PendingIntervalEventData>,
}
impl PendingIntervalEventResponse {
pub fn new(event_id: IntervalEventId, event: Option<PendingIntervalEventData>) -> Self {
PendingIntervalEventResponse { event_id, event }
}
}
/// Response containing number of currently pending epoch and interval events.
#[cw_serde]
pub struct NumberOfPendingEventsResponse {
/// The number of the currently pending epoch events.
pub epoch_events: u32,
/// The number of the currently pending epoch events.
pub interval_events: u32,
}
impl NumberOfPendingEventsResponse {
pub fn new(epoch_events: u32, interval_events: u32) -> Self {
Self {
epoch_events,
interval_events,
}
}
}
@@ -3,9 +3,8 @@
use crate::helpers::IntoBaseDecimal; use crate::helpers::IntoBaseDecimal;
use crate::{error::MixnetContractError, Percent}; use crate::{error::MixnetContractError, Percent};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Decimal; use cosmwasm_std::Decimal;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
pub type Performance = Percent; pub type Performance = Percent;
@@ -15,7 +14,8 @@ pub type Performance = Percent;
feature = "generate-ts", feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/IntervalRewardParams.ts") ts(export_to = "ts-packages/types/src/types/rust/IntervalRewardParams.ts")
)] )]
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, PartialOrd, Serialize, JsonSchema)] #[cw_serde]
#[derive(Copy)]
pub struct IntervalRewardParams { pub struct IntervalRewardParams {
/// Current value of the rewarding pool. /// Current value of the rewarding pool.
/// It is expected to be constant throughout the interval. /// It is expected to be constant throughout the interval.
@@ -74,21 +74,26 @@ impl IntervalRewardParams {
} }
} }
/// Parameters used for reward calculation.
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))] #[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr( #[cfg_attr(
feature = "generate-ts", feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/RewardingParams.ts") ts(export_to = "ts-packages/types/src/types/rust/RewardingParams.ts")
)] )]
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, PartialOrd, Serialize, JsonSchema)] #[cw_serde]
#[derive(Copy)]
pub struct RewardingParams { pub struct RewardingParams {
/// Parameters that should remain unchanged throughout an interval. /// Parameters that should remain unchanged throughout an interval.
pub interval: IntervalRewardParams, pub interval: IntervalRewardParams,
// while the active set size can change between epochs to accommodate for bandwidth demands, // while the rewarded set size can change between epochs to accommodate for bandwidth demands,
// the active set size should be unchanged between epochs and should only be adjusted between // the active set size should be unchanged between epochs and should only be adjusted between
// intervals. However, it makes more sense to keep both of those values together as they're // intervals. However, it makes more sense to keep both of those values together as they're
// very strongly related to each other. // very strongly related to each other.
/// The expected number of mixnodes in the rewarded set (i.e. active + standby).
pub rewarded_set_size: u32, pub rewarded_set_size: u32,
/// The expected number of mixnodes in the active set.
pub active_set_size: u32, pub active_set_size: u32,
} }
@@ -224,9 +229,14 @@ impl RewardingParams {
} }
// TODO: possibly refactor this // TODO: possibly refactor this
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, PartialOrd, Serialize, JsonSchema)] /// Parameters used for rewarding particular mixnode.
#[cw_serde]
#[derive(Copy)]
pub struct NodeRewardParams { pub struct NodeRewardParams {
/// Performance of the particular node in the current epoch.
pub performance: Percent, pub performance: Percent,
/// Flag indicating whether the node has been in the active set during the epoch.
pub in_active_set: bool, pub in_active_set: bool,
} }
@@ -239,33 +249,40 @@ impl NodeRewardParams {
} }
} }
/// Specification on how the rewarding params should be updated.
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))] #[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr( #[cfg_attr(
feature = "generate-ts", feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/IntervalRewardingParamsUpdate.ts") ts(export_to = "ts-packages/types/src/types/rust/IntervalRewardingParamsUpdate.ts")
)] )]
#[derive( #[cw_serde]
Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq, PartialOrd, Serialize, JsonSchema, #[derive(Copy, Default)]
)]
pub struct IntervalRewardingParamsUpdate { pub struct IntervalRewardingParamsUpdate {
#[cfg_attr(feature = "generate-ts", ts(type = "string | null"))] #[cfg_attr(feature = "generate-ts", ts(type = "string | null"))]
/// Defines the new value of the reward pool.
pub reward_pool: Option<Decimal>, pub reward_pool: Option<Decimal>,
#[cfg_attr(feature = "generate-ts", ts(type = "string | null"))] #[cfg_attr(feature = "generate-ts", ts(type = "string | null"))]
/// Defines the new value of the staking supply.
pub staking_supply: Option<Decimal>, pub staking_supply: Option<Decimal>,
#[cfg_attr(feature = "generate-ts", ts(type = "string | null"))] #[cfg_attr(feature = "generate-ts", ts(type = "string | null"))]
/// Defines the new value of the staking supply scale factor.
pub staking_supply_scale_factor: Option<Percent>, pub staking_supply_scale_factor: Option<Percent>,
#[cfg_attr(feature = "generate-ts", ts(type = "string | null"))] #[cfg_attr(feature = "generate-ts", ts(type = "string | null"))]
/// Defines the new value of the sybil resistance percent.
pub sybil_resistance_percent: Option<Percent>, pub sybil_resistance_percent: Option<Percent>,
#[cfg_attr(feature = "generate-ts", ts(type = "string | null"))] #[cfg_attr(feature = "generate-ts", ts(type = "string | null"))]
/// Defines the new value of the active set work factor.
pub active_set_work_factor: Option<Decimal>, pub active_set_work_factor: Option<Decimal>,
#[cfg_attr(feature = "generate-ts", ts(type = "string | null"))] #[cfg_attr(feature = "generate-ts", ts(type = "string | null"))]
/// Defines the new value of the interval pool emission rate.
pub interval_pool_emission: Option<Percent>, pub interval_pool_emission: Option<Percent>,
/// Defines the new size of the rewarded set.
pub rewarded_set_size: Option<u32>, pub rewarded_set_size: Option<u32>,
} }
@@ -1,9 +1,9 @@
// 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 crate::{MixId, RewardedSetNodeStatus};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Coin, Decimal}; use cosmwasm_std::{Coin, Decimal};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
pub mod helpers; pub mod helpers;
pub mod simulator; pub mod simulator;
@@ -13,32 +13,52 @@ pub mod simulator;
feature = "generate-ts", feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/RewardEstimate.ts") ts(export_to = "ts-packages/types/src/types/rust/RewardEstimate.ts")
)] )]
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, JsonSchema, PartialEq, Eq)] #[cw_serde]
#[derive(Copy, Default)]
pub struct RewardEstimate { pub struct RewardEstimate {
/// The amount of **decimal** coins that are going to get distributed to the node,
/// i.e. the operator and all its delegators.
#[cfg_attr(feature = "generate-ts", ts(type = "string"))] #[cfg_attr(feature = "generate-ts", ts(type = "string"))]
pub total_node_reward: Decimal, pub total_node_reward: Decimal,
// note that operator reward includes the operating_cost, // note that operator reward includes the operating_cost,
// i.e. say total_node_reward was `1nym` and operating_cost was `2nym` // i.e. say total_node_reward was `1nym` and operating_cost was `2nym`
// in that case the operator reward would still be `1nym` as opposed to 0 // in that case the operator reward would still be `1nym` as opposed to 0
/// The share of the reward that is going to get distributed to the node operator.
#[cfg_attr(feature = "generate-ts", ts(type = "string"))] #[cfg_attr(feature = "generate-ts", ts(type = "string"))]
pub operator: Decimal, pub operator: Decimal,
/// The share of the reward that is going to get distributed among the node delegators.
#[cfg_attr(feature = "generate-ts", ts(type = "string"))] #[cfg_attr(feature = "generate-ts", ts(type = "string"))]
pub delegates: Decimal, pub delegates: Decimal,
/// The operating cost of this node. Note: it's already included in the operator reward.
#[cfg_attr(feature = "generate-ts", ts(type = "string"))] #[cfg_attr(feature = "generate-ts", ts(type = "string"))]
pub operating_cost: Decimal, pub operating_cost: Decimal,
} }
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, JsonSchema, PartialEq, Eq)] #[cw_serde]
#[derive(Copy, Default)]
pub struct RewardDistribution { pub struct RewardDistribution {
/// The share of the reward that is going to get distributed to the node operator.
pub operator: Decimal, pub operator: Decimal,
/// The share of the reward that is going to get distributed among the node delegators.
pub delegates: Decimal, pub delegates: Decimal,
} }
#[derive(Clone, Debug, Default, Deserialize, Serialize, JsonSchema, PartialEq, Eq)] /// Response containing information about accrued rewards.
#[cw_serde]
#[derive(Default)]
pub struct PendingRewardResponse { pub struct PendingRewardResponse {
/// The amount of tokens initially staked.
pub amount_staked: Option<Coin>, pub amount_staked: Option<Coin>,
/// The amount of tokens that could be claimed.
pub amount_earned: Option<Coin>, pub amount_earned: Option<Coin>,
/// The full pending rewards. Note that it's nearly identical to `amount_earned`,
/// however, it contains few additional decimal points for more accurate reward calculation.
pub amount_earned_detailed: Option<Decimal>, pub amount_earned_detailed: Option<Decimal>,
/// The associated mixnode is still fully bonded, meaning it is neither unbonded /// The associated mixnode is still fully bonded, meaning it is neither unbonded
@@ -46,14 +66,25 @@ pub struct PendingRewardResponse {
pub mixnode_still_fully_bonded: bool, pub mixnode_still_fully_bonded: bool,
} }
#[derive(Clone, Debug, Default, Deserialize, Serialize, JsonSchema, PartialEq, Eq)] /// Response containing estimation of node rewards for the current epoch.
#[cw_serde]
pub struct EstimatedCurrentEpochRewardResponse { pub struct EstimatedCurrentEpochRewardResponse {
/// The amount of tokens initially staked.
pub original_stake: Option<Coin>, pub original_stake: Option<Coin>,
/// The current stake value given all past rewarding and compounding since the original staking was performed.
pub current_stake_value: Option<Coin>, pub current_stake_value: Option<Coin>,
/// The current stake value. Note that it's nearly identical to `current_stake_value`,
/// however, it contains few additional decimal points for more accurate reward calculation.
pub current_stake_value_detailed_amount: Option<Decimal>, pub current_stake_value_detailed_amount: Option<Decimal>,
/// The reward estimation for the current epoch, i.e. the amount of tokens that could be claimable
/// after the epoch finishes and the state of the network does not change.
pub estimation: Option<Coin>, pub estimation: Option<Coin>,
/// The full reward estimation. Note that it's nearly identical to `estimation`,
/// however, it contains few additional decimal points for more accurate reward calculation.
pub detailed_estimation_amount: Option<Decimal>, pub detailed_estimation_amount: Option<Decimal>,
} }
@@ -68,3 +99,13 @@ impl EstimatedCurrentEpochRewardResponse {
} }
} }
} }
/// Response containing paged list of all mixnodes in the rewarded set.
#[cw_serde]
pub struct PagedRewardedSetResponse {
/// Nodes in the current rewarded set.
pub nodes: Vec<(MixId, RewardedSetNodeStatus)>,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<MixId>,
}
@@ -2,29 +2,26 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::error::MixnetContractError; use crate::error::MixnetContractError;
use crate::families::{Family, FamilyHead}; use crate::Layer;
use crate::{Layer, RewardedSetNodeStatus}; use cosmwasm_schema::cw_serde;
use contracts_common::IdentityKey;
use cosmwasm_std::Addr; use cosmwasm_std::Addr;
use cosmwasm_std::Coin; use cosmwasm_std::Coin;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::ops::Index; use std::ops::Index;
// type aliases for better reasoning about available data // type aliases for better reasoning about available data
pub type SphinxKey = String; pub type SphinxKey = String;
pub type SphinxKeyRef<'a> = &'a str; pub type SphinxKeyRef<'a> = &'a str;
pub type EpochId = u32;
pub type IntervalId = u32;
pub type MixId = u32; pub type MixId = u32;
pub type BlockHeight = u64; pub type BlockHeight = u64;
pub type EpochEventId = u32;
pub type IntervalEventId = u32;
#[allow(clippy::derive_partial_eq_without_eq)] /// Specifies layer assignment for the given mixnode.
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, PartialEq, Eq)] #[cw_serde]
pub struct LayerAssignment { pub struct LayerAssignment {
/// The id of the mixnode.
mix_id: MixId, mix_id: MixId,
/// The layer to which it's going to be assigned
layer: Layer, layer: Layer,
} }
@@ -42,10 +39,17 @@ impl LayerAssignment {
} }
} }
#[derive(Debug, Default, Serialize, Deserialize, Copy, Clone, Eq, PartialEq)] /// The current layer distribution of the mix network.
#[cw_serde]
#[derive(Copy, Default)]
pub struct LayerDistribution { pub struct LayerDistribution {
/// Number of nodes on the first layer.
pub layer1: u64, pub layer1: u64,
/// Number of nodes on the second layer.
pub layer2: u64, pub layer2: u64,
/// Number of nodes on the third layer.
pub layer3: u64, pub layer3: u64,
} }
@@ -118,19 +122,29 @@ impl Index<Layer> for LayerDistribution {
} }
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] /// The current state of the mixnet contract.
#[cw_serde]
pub struct ContractState { pub struct ContractState {
pub owner: Addr, // only the owner account can update state /// Address of the contract owner.
pub owner: Addr,
/// Address of "rewarding validator" (nym-api) that's allowed to send any rewarding-related transactions.
pub rewarding_validator_address: Addr, pub rewarding_validator_address: Addr,
/// Address of the vesting contract to which the mixnet contract would be sending all /// Address of the vesting contract to which the mixnet contract would be sending all
/// track-related messages. /// track-related messages.
pub vesting_contract_address: Addr, pub vesting_contract_address: Addr,
/// The expected denom used for rewarding (and realistically any other operation).
/// Default: `unym`
pub rewarding_denom: String, pub rewarding_denom: String,
/// Contract parameters that could be adjusted in a transaction the contract admin.
pub params: ContractStateParams, pub params: ContractStateParams,
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] /// Contract parameters that could be adjusted in a transaction by the contract admin.
#[cw_serde]
pub struct ContractStateParams { pub struct ContractStateParams {
/// Minimum amount a delegator must stake in orders for his delegation to get accepted. /// Minimum amount a delegator must stake in orders for his delegation to get accepted.
pub minimum_mixnode_delegation: Option<Coin>, pub minimum_mixnode_delegation: Option<Coin>,
@@ -141,21 +155,3 @@ pub struct ContractStateParams {
/// Minimum amount a gateway must pledge to get into the system. /// Minimum amount a gateway must pledge to get into the system.
pub minimum_gateway_pledge: Coin, pub minimum_gateway_pledge: Coin,
} }
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, JsonSchema)]
pub struct PagedRewardedSetResponse {
pub nodes: Vec<(MixId, RewardedSetNodeStatus)>,
pub start_next_after: Option<MixId>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, JsonSchema)]
pub struct PagedFamiliesResponse {
pub families: Vec<Family>,
pub start_next_after: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, JsonSchema)]
pub struct PagedMembersResponse {
pub members: Vec<(IdentityKey, FamilyHead)>,
pub start_next_after: Option<String>,
}
@@ -8,7 +8,7 @@ edition = "2021"
[dependencies] [dependencies]
cw-utils = { workspace = true } cw-utils = { workspace = true }
cw3 = { workspace = true } cw3 = { workspace = true }
cw4 = { workspace= true } cw4 = { workspace = true }
cw-storage-plus = { workspace = true } cw-storage-plus = { workspace = true }
cosmwasm-schema = { workspace = true } cosmwasm-schema = { workspace = true }
cosmwasm-std = { workspace = true } cosmwasm-std = { workspace = true }
@@ -6,10 +6,14 @@ 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
[dependencies] [dependencies]
cosmwasm-schema = { workspace = true }
cosmwasm-std = { workspace = true } cosmwasm-std = { workspace = true }
cw2 = { workspace = true, optional = true }
cw-controllers = { workspace = true } cw-controllers = { workspace = true }
cw-utils = { workspace = true } cw-utils = { workspace = true }
nym-contracts-common = { path = "../contracts-common", version = "0.5.0" } nym-contracts-common = { path = "../contracts-common", version = "0.5.0" }
schemars = "0.8"
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
thiserror = { workspace = true } thiserror = { workspace = true }
[features]
schema = ["cw2"]
@@ -1,10 +1,22 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::{Address, NameDetails, NameId, NymName}; use crate::{Address, NameDetails, NameId, NymName};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Coin; use cosmwasm_std::Coin;
use nym_contracts_common::signing::MessageSignature; use nym_contracts_common::signing::MessageSignature;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] #[cfg(feature = "schema")]
#[serde(rename_all = "snake_case")] use crate::{
response::{ConfigResponse, NamesListResponse, PagedNamesListResponse},
types::RegisteredName,
};
#[cfg(feature = "schema")]
use cosmwasm_schema::QueryResponses;
#[cfg(feature = "schema")]
use nym_contracts_common::{signing::Nonce, ContractBuildInformation};
#[cw_serde]
pub struct InstantiateMsg { pub struct InstantiateMsg {
pub deposit_required: Coin, pub deposit_required: Coin,
} }
@@ -15,22 +27,23 @@ impl InstantiateMsg {
} }
} }
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub struct MigrateMsg {} pub struct MigrateMsg {}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg { pub enum ExecuteMsg {
/// Announcing a name pointing to a nym-address /// Announcing a name pointing to a nym-address
Register { Register {
name: NameDetails, name: NameDetails,
owner_signature: MessageSignature, owner_signature: MessageSignature,
}, },
/// Delete a name entry by id /// Delete a name entry by id
DeleteId { name_id: NameId }, DeleteId { name_id: NameId },
/// Delete a name entry by name /// Delete a name entry by name
DeleteName { name: NymName }, DeleteName { name: NymName },
/// Change the deposit required for announcing a name /// Change the deposit required for announcing a name
UpdateDepositRequired { deposit_required: Coin }, UpdateDepositRequired { deposit_required: Coin },
} }
@@ -61,33 +74,42 @@ impl ExecuteMsg {
} }
} }
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] #[cw_serde]
#[serde(rename_all = "snake_case")] #[cfg_attr(feature = "schema", derive(QueryResponses))]
pub enum QueryMsg { pub enum QueryMsg {
/// Query the name by it's assigned id /// Query the name by it's assigned id
NameId { #[cfg_attr(feature = "schema", returns(RegisteredName))]
name_id: NameId, NameId { name_id: NameId },
},
// Query the names by the registrator /// Query the names by the registrator
ByOwner { #[cfg_attr(feature = "schema", returns(NamesListResponse))]
owner: String, ByOwner { owner: String },
},
ByName { #[cfg_attr(feature = "schema", returns(RegisteredName))]
name: NymName, ByName { name: NymName },
},
ByAddress { #[cfg_attr(feature = "schema", returns(NamesListResponse))]
address: Address, ByAddress { address: Address },
},
#[cfg_attr(feature = "schema", returns(PagedNamesListResponse))]
All { All {
limit: Option<u32>, limit: Option<u32>,
start_after: Option<NameId>, start_after: Option<NameId>,
}, },
SigningNonce {
address: String, #[cfg_attr(feature = "schema", returns(Nonce))]
}, SigningNonce { address: String },
#[cfg_attr(feature = "schema", returns(ConfigResponse))]
Config {}, Config {},
/// Gets build information of this contract, such as the commit hash used for the build or rustc version.
#[cfg_attr(feature = "schema", returns(ContractBuildInformation))]
GetContractVersion {}, GetContractVersion {},
/// Gets the stored contract version information that's required by the CW2 spec interface for migrations.
#[serde(rename = "get_cw2_contract_version")] #[serde(rename = "get_cw2_contract_version")]
#[cfg_attr(feature = "schema", returns(cw2::ContractVersion))]
GetCW2ContractVersion {}, GetCW2ContractVersion {},
} }
@@ -1,10 +1,11 @@
use crate::{NameId, RegisteredName}; // Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
use cosmwasm_std::Coin; // SPDX-License-Identifier: Apache-2.0
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)] use crate::{NameId, RegisteredName};
#[serde(rename_all = "snake_case")] use cosmwasm_schema::cw_serde;
use cosmwasm_std::Coin;
#[cw_serde]
pub struct NamesListResponse { pub struct NamesListResponse {
pub names: Vec<RegisteredName>, pub names: Vec<RegisteredName>,
} }
@@ -23,11 +24,12 @@ impl From<&[RegisteredName]> for NamesListResponse {
} }
} }
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub struct PagedNamesListResponse { pub struct PagedNamesListResponse {
pub names: Vec<RegisteredName>, pub names: Vec<RegisteredName>,
pub per_page: usize, pub per_page: usize,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<NameId>, pub start_next_after: Option<NameId>,
} }
@@ -45,8 +47,7 @@ impl PagedNamesListResponse {
} }
} }
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub struct ConfigResponse { pub struct ConfigResponse {
pub deposit_required: Coin, pub deposit_required: Coin,
} }
@@ -1,14 +1,15 @@
use std::fmt::{Display, Formatter}; // Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Addr, Coin}; use cosmwasm_std::{Addr, Coin};
use nym_contracts_common::IdentityKey; use nym_contracts_common::IdentityKey;
use schemars::JsonSchema; use std::fmt::{Display, Formatter};
use serde::{Deserialize, Serialize};
/// The directory of names are indexed by [`NameId`]. /// The directory of names are indexed by [`NameId`].
pub type NameId = u32; pub type NameId = u32;
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug, JsonSchema)] #[cw_serde]
pub struct RegisteredName { pub struct RegisteredName {
/// Unique id assigned to the registerd name. /// Unique id assigned to the registerd name.
pub id: NameId, pub id: NameId,
@@ -33,7 +34,7 @@ impl RegisteredName {
} }
} }
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug, JsonSchema)] #[cw_serde]
pub struct NameDetails { pub struct NameDetails {
/// The name pointing to the nym address /// The name pointing to the nym address
pub name: NymName, pub name: NymName,
@@ -48,8 +49,7 @@ pub struct NameDetails {
/// String representation of a nym address, which is of the form /// String representation of a nym address, which is of the form
/// client_id.client_enc@gateway_id. /// client_id.client_enc@gateway_id.
/// NOTE: entirely unvalidated. /// NOTE: entirely unvalidated.
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, JsonSchema)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub enum Address { pub enum Address {
NymAddress(String), NymAddress(String),
// Possible extension: // Possible extension:
@@ -83,8 +83,7 @@ impl Display for Address {
} }
/// Name stored and pointing a to a nym-address /// Name stored and pointing a to a nym-address
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, JsonSchema)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub struct NymName(String); pub struct NymName(String);
#[derive(Debug)] #[derive(Debug)]
@@ -6,10 +6,13 @@ 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
[dependencies] [dependencies]
cosmwasm-schema = { workspace = true }
cosmwasm-std = { workspace = true } cosmwasm-std = { workspace = true }
cw2 = { workspace = true, optional = true }
cw-controllers = { workspace = true } cw-controllers = { workspace = true }
cw-utils = { workspace = true } cw-utils = { workspace = true }
nym-contracts-common = { path = "../contracts-common", version = "0.5.0" } nym-contracts-common = { path = "../contracts-common", version = "0.5.0" }
schemars = "0.8"
serde = { workspace = true, features = ["derive"] }
thiserror = { workspace = true } thiserror = { workspace = true }
[features]
schema = ["cw2"]
@@ -1,10 +1,22 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::{NymAddress, ServiceDetails, ServiceId}; use crate::{NymAddress, ServiceDetails, ServiceId};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Coin; use cosmwasm_std::Coin;
use nym_contracts_common::signing::MessageSignature; use nym_contracts_common::signing::MessageSignature;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] #[cfg(feature = "schema")]
#[serde(rename_all = "snake_case")] use crate::{
response::{ConfigResponse, PagedServicesListResponse, ServicesListResponse},
types::Service,
};
#[cfg(feature = "schema")]
use cosmwasm_schema::QueryResponses;
#[cfg(feature = "schema")]
use nym_contracts_common::{signing::Nonce, ContractBuildInformation};
#[cw_serde]
pub struct InstantiateMsg { pub struct InstantiateMsg {
pub deposit_required: Coin, pub deposit_required: Coin,
} }
@@ -15,12 +27,10 @@ impl InstantiateMsg {
} }
} }
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub struct MigrateMsg {} pub struct MigrateMsg {}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg { pub enum ExecuteMsg {
Announce { Announce {
service: ServiceDetails, service: ServiceDetails,
@@ -64,28 +74,37 @@ impl ExecuteMsg {
} }
} }
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] #[cw_serde]
#[serde(rename_all = "snake_case")] #[cfg_attr(feature = "schema", derive(QueryResponses))]
pub enum QueryMsg { pub enum QueryMsg {
ServiceId { #[cfg_attr(feature = "schema", returns(Service))]
service_id: ServiceId, ServiceId { service_id: ServiceId },
},
ByAnnouncer { #[cfg_attr(feature = "schema", returns(ServicesListResponse))]
announcer: String, ByAnnouncer { announcer: String },
},
ByNymAddress { #[cfg_attr(feature = "schema", returns(ServicesListResponse))]
nym_address: NymAddress, ByNymAddress { nym_address: NymAddress },
},
#[cfg_attr(feature = "schema", returns(PagedServicesListResponse))]
All { All {
limit: Option<u32>, limit: Option<u32>,
start_after: Option<ServiceId>, start_after: Option<ServiceId>,
}, },
SigningNonce {
address: String, #[cfg_attr(feature = "schema", returns(Nonce))]
}, SigningNonce { address: String },
#[cfg_attr(feature = "schema", returns(ConfigResponse))]
Config {}, Config {},
/// Gets build information of this contract, such as the commit hash used for the build or rustc version.
#[cfg_attr(feature = "schema", returns(ContractBuildInformation))]
GetContractVersion {}, GetContractVersion {},
/// Gets the stored contract version information that's required by the CW2 spec interface for migrations.
#[serde(rename = "get_cw2_contract_version")] #[serde(rename = "get_cw2_contract_version")]
#[cfg_attr(feature = "schema", returns(cw2::ContractVersion))]
GetCW2ContractVersion {}, GetCW2ContractVersion {},
} }
@@ -1,17 +1,17 @@
use crate::{Service, ServiceId}; // Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
use cosmwasm_std::Coin; // SPDX-License-Identifier: Apache-2.0
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] use crate::{Service, ServiceId};
#[serde(rename_all = "snake_case")] use cosmwasm_schema::cw_serde;
use cosmwasm_std::Coin;
#[cw_serde]
pub struct ServiceInfoResponse { pub struct ServiceInfoResponse {
pub service_id: ServiceId, pub service_id: ServiceId,
pub service: Option<Service>, pub service: Option<Service>,
} }
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub struct ServicesListResponse { pub struct ServicesListResponse {
pub services: Vec<Service>, pub services: Vec<Service>,
} }
@@ -30,11 +30,12 @@ impl From<&[Service]> for ServicesListResponse {
} }
} }
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub struct PagedServicesListResponse { pub struct PagedServicesListResponse {
pub services: Vec<Service>, pub services: Vec<Service>,
pub per_page: usize, pub per_page: usize,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<ServiceId>, pub start_next_after: Option<ServiceId>,
} }
@@ -52,8 +53,7 @@ impl PagedServicesListResponse {
} }
} }
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub struct ConfigResponse { pub struct ConfigResponse {
pub deposit_required: Coin, pub deposit_required: Coin,
} }
@@ -1,15 +1,17 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::ServiceDetails;
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Addr, Coin}; use cosmwasm_std::{Addr, Coin};
use nym_contracts_common::signing::{ use nym_contracts_common::signing::{
ContractMessageContent, MessageType, Nonce, SignableMessage, SigningPurpose, ContractMessageContent, MessageType, Nonce, SignableMessage, SigningPurpose,
}; };
use serde::Serialize;
use crate::ServiceDetails;
pub type SignableServiceProviderAnnounceMsg = pub type SignableServiceProviderAnnounceMsg =
SignableMessage<ContractMessageContent<ServiceProviderAnnounce>>; SignableMessage<ContractMessageContent<ServiceProviderAnnounce>>;
#[derive(Serialize)] #[cw_serde]
pub struct ServiceProviderAnnounce { pub struct ServiceProviderAnnounce {
service: ServiceDetails, service: ServiceDetails,
} }
@@ -1,14 +1,15 @@
use std::fmt::{Display, Formatter}; // Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Addr, Coin}; use cosmwasm_std::{Addr, Coin};
use nym_contracts_common::IdentityKey; use nym_contracts_common::IdentityKey;
use schemars::JsonSchema; use std::fmt::{Display, Formatter};
use serde::{Deserialize, Serialize};
/// The directory of services are indexed by [`ServiceId`]. /// The directory of services are indexed by [`ServiceId`].
pub type ServiceId = u32; pub type ServiceId = u32;
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug, JsonSchema)] #[cw_serde]
pub struct Service { pub struct Service {
/// Unique id assigned to the anounced service. /// Unique id assigned to the anounced service.
pub service_id: ServiceId, pub service_id: ServiceId,
@@ -22,7 +23,7 @@ pub struct Service {
pub deposit: Coin, pub deposit: Coin,
} }
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug, JsonSchema)] #[cw_serde]
pub struct ServiceDetails { pub struct ServiceDetails {
/// The address of the service. /// The address of the service.
pub nym_address: NymAddress, pub nym_address: NymAddress,
@@ -33,8 +34,7 @@ pub struct ServiceDetails {
} }
/// The types of addresses supported. /// The types of addresses supported.
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, JsonSchema)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub enum NymAddress { pub enum NymAddress {
/// String representation of a nym address, which is of the form /// String representation of a nym address, which is of the form
/// client_id.client_enc@gateway_id. /// client_id.client_enc@gateway_id.
@@ -64,8 +64,7 @@ impl Display for NymAddress {
} }
/// The type of services provider supported /// The type of services provider supported
#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Debug, JsonSchema)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub enum ServiceType { pub enum ServiceType {
NetworkRequester, NetworkRequester,
} }
@@ -9,11 +9,14 @@ repository = { workspace = true }
[dependencies] [dependencies]
cosmwasm-std = { workspace = true } cosmwasm-std = { workspace = true }
cosmwasm-schema = { workspace = true }
cw2 = { workspace = true, optional = true }
mixnet-contract-common = { path = "../mixnet-contract", package = "nym-mixnet-contract-common", version = "0.6.0" } mixnet-contract-common = { path = "../mixnet-contract", package = "nym-mixnet-contract-common", version = "0.6.0" }
contracts-common = { path = "../contracts-common", package = "nym-contracts-common", version = "0.5.0" } contracts-common = { path = "../contracts-common", package = "nym-contracts-common", version = "0.5.0" }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
schemars = "0.8" thiserror = "1.0"
ts-rs = {version = "6.1.2", optional = true} ts-rs = {version = "6.1.2", optional = true}
[features] [features]
schema = ["cw2"]
generate-ts = ["ts-rs"] generate-ts = ["ts-rs"]
@@ -0,0 +1,124 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::{Period, PledgeCap, VestingContractError, VestingPeriod};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Addr, Coin, Timestamp};
// this shouldn't really be exposed like this, but we really don't want to migrate the contract just for this...
pub type VestingAccountStorageKey = u32;
/// Vesting account information.
#[cw_serde]
pub struct Account {
/// Address of the owner of the vesting account.
pub owner_address: Addr,
/// Optional address of an account allowed to perform staking on behalf of the owner.
pub staking_address: Option<Addr>,
/// The starting vesting time.
pub start_time: Timestamp,
/// All vesting periods for this account.
pub periods: Vec<VestingPeriod>,
/// The initial amount of coins used creation of this account.
pub coin: Coin,
/// The id/storage_key of this vesting account.
pub storage_key: VestingAccountStorageKey,
/// Optional custom pledge cap of this vesting account.
#[serde(default)]
pub pledge_cap: Option<PledgeCap>,
}
impl Account {
pub fn pledge_cap(&self) -> PledgeCap {
self.pledge_cap.clone().unwrap_or_default()
}
pub fn coin(&self) -> Coin {
self.coin.clone()
}
pub fn num_vesting_periods(&self) -> usize {
self.periods.len()
}
pub fn period_duration(&self) -> Result<u64, VestingContractError> {
self.periods
.get(0)
.ok_or(VestingContractError::UnpopulatedVestingPeriods {
owner: self.owner_address.clone(),
})
.map(|p| p.period_seconds)
}
pub fn storage_key(&self) -> u32 {
self.storage_key
}
pub fn owner_address(&self) -> Addr {
self.owner_address.clone()
}
pub fn staking_address(&self) -> Option<&Addr> {
self.staking_address.as_ref()
}
pub fn periods(&self) -> Vec<VestingPeriod> {
self.periods.clone()
}
pub fn start_time(&self) -> Timestamp {
self.start_time
}
pub fn tokens_per_period(&self) -> Result<u128, VestingContractError> {
let amount = self.coin.amount.u128();
if amount < self.num_vesting_periods() as u128 {
Err(VestingContractError::ImprobableVestingAmount(amount))
} else {
// Remainder tokens will be lumped into the last period.
Ok(amount / self.num_vesting_periods() as u128)
}
}
/// Returns the index of the next vesting period. Unless the current time is somehow in the past or vesting has not started yet.
/// In case vesting is over it will always return NUM_VESTING_PERIODS.
pub fn get_current_vesting_period(
&self,
block_time: Timestamp,
) -> Result<Period, VestingContractError> {
let first_period =
self.periods
.first()
.ok_or(VestingContractError::UnpopulatedVestingPeriods {
owner: self.owner_address.clone(),
})?;
let last_period =
self.periods
.last()
.ok_or(VestingContractError::UnpopulatedVestingPeriods {
owner: self.owner_address.clone(),
})?;
if block_time.seconds() < first_period.start_time {
Ok(Period::Before)
} else if last_period.end_time() < block_time {
Ok(Period::After)
} else {
let mut index = 0;
for period in &self.periods {
if block_time < period.end_time() {
break;
}
index += 1;
}
Ok(Period::In(index))
}
}
}
@@ -1,10 +1,13 @@
use crate::storage::AccountStorageKey; // Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::account::VestingAccountStorageKey;
use cosmwasm_std::{Addr, Coin, OverflowError, StdError, Uint128}; use cosmwasm_std::{Addr, Coin, OverflowError, StdError, Uint128};
use mixnet_contract_common::MixId; use mixnet_contract_common::MixId;
use thiserror::Error; use thiserror::Error;
#[derive(Error, Debug, PartialEq)] #[derive(Error, Debug, PartialEq)]
pub enum ContractError { pub enum VestingContractError {
#[error("VESTING ({}): {0}", line!())] #[error("VESTING ({}): {0}", line!())]
Std(#[from] StdError), Std(#[from] StdError),
@@ -27,7 +30,7 @@ pub enum ContractError {
InsufficientSpendable(String, u128), InsufficientSpendable(String, u128),
#[error( #[error(
"VESTING ({}):Only delegation owner can perform delegation actions, {0} is not the delegation owner" "VESTING ({}):Only delegation owner can perform delegation actions, {0} is not the delegation owner"
, line!())] , line!())]
NotDelegate(String), NotDelegate(String),
@@ -91,7 +94,7 @@ pub enum ContractError {
#[error("VESTING: {address} ({acc_id} has already performed {num} individual delegations towards {mix_id}. No further delegations are allowed. Please consider consolidating those delegations instead. The current cap is {cap}.")] #[error("VESTING: {address} ({acc_id} has already performed {num} individual delegations towards {mix_id}. No further delegations are allowed. Please consider consolidating those delegations instead. The current cap is {cap}.")]
TooManyDelegations { TooManyDelegations {
address: Addr, address: Addr,
acc_id: AccountStorageKey, acc_id: VestingAccountStorageKey,
mix_id: MixId, mix_id: MixId,
num: u32, num: u32,
cap: u32, cap: u32,
@@ -4,83 +4,31 @@
#![warn(clippy::expect_used)] #![warn(clippy::expect_used)]
#![warn(clippy::unwrap_used)] #![warn(clippy::unwrap_used)]
use contracts_common::Percent; use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Addr, Coin, Timestamp, Uint128}; use cosmwasm_std::{Addr, Coin};
use mixnet_contract_common::MixId; use mixnet_contract_common::MixId;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::str::FromStr;
pub use messages::{ExecuteMsg, InitMsg, MigrateMsg, QueryMsg};
pub mod account;
pub mod error;
pub mod events; pub mod events;
pub mod messages; pub mod messages;
pub mod types;
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))] pub use account::Account;
#[cfg_attr( pub use error::VestingContractError;
feature = "generate-ts", pub use messages::{ExecuteMsg, InitMsg, MigrateMsg, QueryMsg};
ts(export_to = "ts-packages/types/src/types/rust/Period.ts") pub use types::*;
)]
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, JsonSchema)]
pub enum Period {
Before,
In(usize),
After,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] /// Details about the original vesting specification used when the account was created.
pub struct PledgeData { #[cw_serde]
pub amount: Coin,
pub block_time: Timestamp,
}
impl PledgeData {
pub fn amount(&self) -> Coin {
self.amount.clone()
}
pub fn block_time(&self) -> Timestamp {
self.block_time
}
pub fn new(amount: Coin, block_time: Timestamp) -> Self {
Self { amount, block_time }
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub enum PledgeCap {
Percent(Percent),
Absolute(Uint128), // This has to be in unym
}
impl FromStr for PledgeCap {
type Err = String;
fn from_str(cap: &str) -> Result<Self, Self::Err> {
let cap = cap.replace('_', "").replace(',', ".");
match Percent::from_str(&cap) {
Ok(p) => Ok(PledgeCap::Percent(p)),
Err(_) => match cap.parse::<u128>() {
Ok(i) => Ok(PledgeCap::Absolute(Uint128::from(i))),
Err(_e) => Err(format!("Could not parse {cap} as Percent or Uint128")),
},
}
}
}
impl Default for PledgeCap {
fn default() -> Self {
#[allow(clippy::expect_used)]
PledgeCap::Percent(Percent::from_percentage_value(10).expect("This can never fail!"))
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct OriginalVestingResponse { pub struct OriginalVestingResponse {
/// The original amount that was used for the creation of this vesting account
pub amount: Coin, pub amount: Coin,
/// The number of vesting periods that the account was created with
pub number_of_periods: usize, pub number_of_periods: usize,
/// Duration of each vesting period in seconds
pub period_duration: u64, pub period_duration: u64,
} }
@@ -106,57 +54,73 @@ impl OriginalVestingResponse {
} }
} }
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, JsonSchema)] /// Response containing timestamps of all delegations made towards particular mixnode by given vesting account.
pub struct VestingDelegation { #[cw_serde]
pub account_id: u32,
pub mix_id: MixId,
pub block_timestamp: u64,
pub amount: Uint128,
}
impl VestingDelegation {
pub fn storage_key(&self) -> (u32, MixId, u64) {
(self.account_id, self.mix_id, self.block_timestamp)
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, JsonSchema)]
pub struct DelegationTimesResponse { pub struct DelegationTimesResponse {
/// Address of this account's owner
pub owner: Addr, pub owner: Addr,
/// Id associated with this account
pub account_id: u32, pub account_id: u32,
/// Id of the mixnode towards which the delegation was made
pub mix_id: MixId, pub mix_id: MixId,
/// All timestamps where a delegation was made
pub delegation_timestamps: Vec<u64>, pub delegation_timestamps: Vec<u64>,
} }
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, JsonSchema)] /// Response containing paged list of all vesting delegations made using vesting coins.
#[cw_serde]
pub struct AllDelegationsResponse { pub struct AllDelegationsResponse {
/// The actual vesting delegations made.
pub delegations: Vec<VestingDelegation>, pub delegations: Vec<VestingDelegation>,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<(u32, MixId, u64)>, pub start_next_after: Option<(u32, MixId, u64)>,
} }
#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] /// Basic information regarding particular vesting account alongside the amount of vesting coins.
#[cw_serde]
pub struct AccountVestingCoins { pub struct AccountVestingCoins {
/// Id associated with this account
pub account_id: u32, pub account_id: u32,
/// Address of this account's owner
pub owner: Addr, pub owner: Addr,
/// Coins that are still vesting belonging to this account.
pub still_vesting: Coin, pub still_vesting: Coin,
} }
#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] /// Response containing vesting coins held in this contract
#[cw_serde]
pub struct VestingCoinsResponse { pub struct VestingCoinsResponse {
/// The actual accounts, and their vesting coins, returned by the query.
pub accounts: Vec<AccountVestingCoins>, pub accounts: Vec<AccountVestingCoins>,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<Addr>, pub start_next_after: Option<Addr>,
} }
#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] /// Basic information regarding particular vesting account
#[cw_serde]
pub struct BaseVestingAccountInfo { pub struct BaseVestingAccountInfo {
/// Id associated with this account
pub account_id: u32, pub account_id: u32,
/// Address of this account's owner
pub owner: Addr, pub owner: Addr,
// TODO: should this particular query/response expose anything else? // TODO: should this particular query/response expose anything else?
} }
#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] /// Response containing basic vesting account information
#[cw_serde]
pub struct AccountsResponse { pub struct AccountsResponse {
/// The actual accounts returned by the query.
pub accounts: Vec<BaseVestingAccountInfo>, pub accounts: Vec<BaseVestingAccountInfo>,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<Addr>, pub start_next_after: Option<Addr>,
} }
@@ -1,4 +1,9 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::{PledgeCap, VestingSpecification};
use contracts_common::signing::MessageSignature; use contracts_common::signing::MessageSignature;
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Coin, Timestamp}; use cosmwasm_std::{Coin, Timestamp};
use mixnet_contract_common::families::FamilyHead; use mixnet_contract_common::families::FamilyHead;
use mixnet_contract_common::{ use mixnet_contract_common::{
@@ -6,57 +11,30 @@ use mixnet_contract_common::{
mixnode::{MixNodeConfigUpdate, MixNodeCostParams}, mixnode::{MixNodeConfigUpdate, MixNodeCostParams},
Gateway, IdentityKey, MixId, MixNode, Gateway, IdentityKey, MixId, MixNode,
}; };
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::PledgeCap; #[cfg(feature = "schema")]
use contracts_common::ContractBuildInformation;
#[cfg(feature = "schema")]
use cosmwasm_schema::QueryResponses;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[cfg(feature = "schema")]
#[serde(rename_all = "snake_case")] use crate::{
account::Account,
types::{Period, PledgeData, VestingDelegation},
AccountsResponse, AllDelegationsResponse, DelegationTimesResponse, OriginalVestingResponse,
VestingCoinsResponse,
};
#[cw_serde]
pub struct InitMsg { pub struct InitMsg {
pub mixnet_contract_address: String, pub mixnet_contract_address: String,
pub mix_denom: String, pub mix_denom: String,
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[cw_serde]
#[serde(rename_all = "snake_case")]
pub struct MigrateMsg {} pub struct MigrateMsg {}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, Default)] #[cw_serde]
pub struct VestingSpecification {
start_time: Option<u64>,
period_seconds: Option<u64>,
num_periods: Option<u64>,
}
impl VestingSpecification {
pub fn new(
start_time: Option<u64>,
period_seconds: Option<u64>,
num_periods: Option<u64>,
) -> Self {
Self {
start_time,
period_seconds,
num_periods,
}
}
pub fn start_time(&self) -> Option<u64> {
self.start_time
}
pub fn period_seconds(&self) -> u64 {
self.period_seconds.unwrap_or(3 * 30 * 86400)
}
pub fn num_periods(&self) -> u64 {
self.num_periods.unwrap_or(8)
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg { pub enum ExecuteMsg {
// Families // Families
/// Only owner of the node can crate the family with node as head /// Only owner of the node can crate the family with node as head
@@ -197,93 +175,226 @@ impl ExecuteMsg {
} }
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] /// Queries exposed by this contract.
#[serde(rename_all = "snake_case")] #[cw_serde]
#[cfg_attr(feature = "schema", derive(QueryResponses))]
pub enum QueryMsg { pub enum QueryMsg {
/// Gets build information of this contract, such as the commit hash used for the build or rustc version.
#[cfg_attr(feature = "schema", returns(ContractBuildInformation))]
GetContractVersion {}, GetContractVersion {},
/// Gets the stored contract version information that's required by the CW2 spec interface for migrations.
#[serde(rename = "get_cw2_contract_version")] #[serde(rename = "get_cw2_contract_version")]
#[cfg_attr(feature = "schema", returns(cw2::ContractVersion))]
GetCW2ContractVersion {}, GetCW2ContractVersion {},
/// Gets the list of vesting accounts held in this contract.
#[cfg_attr(feature = "schema", returns(AccountsResponse))]
GetAccountsPaged { GetAccountsPaged {
/// Pagination control for the values returned by the query. Note that the provided value itself will **not** be used for the response.
start_next_after: Option<String>, start_next_after: Option<String>,
/// Controls the maximum number of entries returned by the query. Note that too large values will be overwritten by a saner default.
limit: Option<u32>, limit: Option<u32>,
}, },
/// Gets the list of coins that are still vesting for each account held in this contract.
#[cfg_attr(feature = "schema", returns(VestingCoinsResponse))]
GetAccountsVestingCoinsPaged { GetAccountsVestingCoinsPaged {
/// Pagination control for the values returned by the query. Note that the provided value itself will **not** be used for the response.
start_next_after: Option<String>, start_next_after: Option<String>,
/// Controls the maximum number of entries returned by the query. Note that too large values will be overwritten by a saner default.
limit: Option<u32>, limit: Option<u32>,
}, },
/// Returns the amount of locked coins for the provided vesting account,
/// i.e. coins that are still vesting but have not been staked.
/// `locked_coins = vesting_coins - staked_coins`
#[cfg_attr(feature = "schema", returns(Coin))]
LockedCoins { LockedCoins {
/// Address of the vesting account in question.
vesting_account_address: String, vesting_account_address: String,
/// (deprecated) Optional argument specifying that the query should be performed against non-current block.
block_time: Option<Timestamp>, block_time: Option<Timestamp>,
}, },
/// Returns the amount of spendable coins for the provided vesting account,
/// i.e. coins that could be withdrawn.
/// `spendable_coins = account_balance - locked_coins`
/// note: `account_balance` is the amount of coins still physically present in this contract, i.e. not withdrawn or staked.
#[cfg_attr(feature = "schema", returns(Coin))]
SpendableCoins { SpendableCoins {
/// Address of the vesting account in question.
vesting_account_address: String, vesting_account_address: String,
/// (deprecated) Optional argument specifying that the query should be performed against non-current block.
block_time: Option<Timestamp>, block_time: Option<Timestamp>,
}, },
/// Returns the amount of coins that have already vested for the provided vesting account address.
#[cfg_attr(feature = "schema", returns(Coin))]
GetVestedCoins { GetVestedCoins {
/// Address of the vesting account in question.
vesting_account_address: String, vesting_account_address: String,
/// (deprecated) Optional argument specifying that the query should be performed against non-current block.
block_time: Option<Timestamp>, block_time: Option<Timestamp>,
}, },
/// Returns the amount of coins that are still vesting for the provided vesting account address.
#[cfg_attr(feature = "schema", returns(Coin))]
GetVestingCoins { GetVestingCoins {
/// Address of the vesting account in question.
vesting_account_address: String, vesting_account_address: String,
/// (deprecated) Optional argument specifying that the query should be performed against non-current block.
block_time: Option<Timestamp>, block_time: Option<Timestamp>,
}, },
/// Returns the starting vesting time for the provided vesting account,
/// i.e. the beginning of the first vesting period.
#[cfg_attr(feature = "schema", returns(Timestamp))]
GetStartTime { GetStartTime {
/// Address of the vesting account in question.
vesting_account_address: String, vesting_account_address: String,
}, },
/// Returns the ending vesting time for the provided vesting account,
/// i.e. the end of the last vesting period.
#[cfg_attr(feature = "schema", returns(Timestamp))]
GetEndTime { GetEndTime {
/// Address of the vesting account in question.
vesting_account_address: String, vesting_account_address: String,
}, },
/// Returns the initial vesting specification used for the provided vesting account address.
#[cfg_attr(feature = "schema", returns(OriginalVestingResponse))]
GetOriginalVesting { GetOriginalVesting {
/// Address of the vesting account in question.
vesting_account_address: String, vesting_account_address: String,
}, },
/// Returns the total amount of coins accrued through claimed staking rewards by the provided vesting account.
#[cfg_attr(feature = "schema", returns(Coin))]
GetHistoricalVestingStakingReward { GetHistoricalVestingStakingReward {
/// Address of the vesting account in question.
vesting_account_address: String, vesting_account_address: String,
}, },
/// Returns the amount of spendable vesting coins for the provided vesting account,
/// i.e. coins that could be withdrawn that originated from the vesting specification.
#[cfg_attr(feature = "schema", returns(Coin))]
GetSpendableVestedCoins { GetSpendableVestedCoins {
/// Address of the vesting account in question.
vesting_account_address: String, vesting_account_address: String,
}, },
/// Returns the amount of spendable reward coins for the provided vesting account,
/// i.e. coins that could be withdrawn that originated from the claimed staking rewards.
#[cfg_attr(feature = "schema", returns(Coin))]
GetSpendableRewardCoins { GetSpendableRewardCoins {
/// Address of the vesting account in question.
vesting_account_address: String, vesting_account_address: String,
}, },
/// Returns the amount of coins that are currently delegated for the provided vesting account address.
#[cfg_attr(feature = "schema", returns(Coin))]
GetDelegatedCoins { GetDelegatedCoins {
/// Address of the vesting account in question.
vesting_account_address: String, vesting_account_address: String,
}, },
/// Returns the amount of coins that are currently pledged for the provided vesting account address.
#[cfg_attr(feature = "schema", returns(Coin))]
GetPledgedCoins { GetPledgedCoins {
/// Address of the vesting account in question.
vesting_account_address: String, vesting_account_address: String,
}, },
/// Returns the amount of coins that are currently staked (i.e. delegations + pledges) for the provided vesting account address.
#[cfg_attr(feature = "schema", returns(Coin))]
GetStakedCoins { GetStakedCoins {
/// Address of the vesting account in question.
vesting_account_address: String, vesting_account_address: String,
}, },
/// Returns the amount of coins that got withdrawn for the provided vesting account address.
#[cfg_attr(feature = "schema", returns(Coin))]
GetWithdrawnCoins { GetWithdrawnCoins {
/// Address of the vesting account in question.
vesting_account_address: String, vesting_account_address: String,
}, },
/// Returns detailed information associated with the account for the provided vesting account address.
#[cfg_attr(feature = "schema", returns(Account))]
GetAccount { GetAccount {
/// Address of the vesting account in question.
address: String, address: String,
}, },
/// Returns pledge information (if applicable) for bonded mixnode for the provided vesting account address.
#[cfg_attr(feature = "schema", returns(Option<PledgeData>))]
GetMixnode { GetMixnode {
/// Address of the vesting account in question.
address: String, address: String,
}, },
/// Returns pledge information (if applicable) for bonded gateway for the provided vesting account address.
#[cfg_attr(feature = "schema", returns(Option<PledgeData>))]
GetGateway { GetGateway {
/// Address of the vesting account in question.
address: String, address: String,
}, },
/// Returns the current vesting period for the provided vesting account address.
#[cfg_attr(feature = "schema", returns(Period))]
GetCurrentVestingPeriod { GetCurrentVestingPeriod {
/// Address of the vesting account in question.
address: String, address: String,
}, },
/// Returns the information about particular vesting delegation.
#[cfg_attr(feature = "schema", returns(VestingDelegation))]
GetDelegation { GetDelegation {
/// Address of the vesting account in question.
address: String, address: String,
/// Id of the mixnode towards which the delegation has been made.
mix_id: MixId, mix_id: MixId,
/// Block timestamp of the delegation.
block_timestamp_secs: u64, block_timestamp_secs: u64,
}, },
/// Returns the total amount of coins delegated towards particular mixnode by the provided vesting account address.
#[cfg_attr(feature = "schema", returns(Coin))]
GetTotalDelegationAmount { GetTotalDelegationAmount {
/// Address of the vesting account in question.
address: String, address: String,
/// Id of the mixnode towards which the delegations have been made.
mix_id: MixId, mix_id: MixId,
}, },
/// Returns timestamps of delegations made towards particular mixnode by the provided vesting account address.
#[cfg_attr(feature = "schema", returns(DelegationTimesResponse))]
GetDelegationTimes { GetDelegationTimes {
/// Address of the vesting account in question.
address: String, address: String,
/// Id of the mixnode towards which the delegations have been made.
mix_id: MixId, mix_id: MixId,
}, },
/// Returns all active delegations made with vesting tokens stored in this contract.
#[cfg_attr(feature = "schema", returns(AllDelegationsResponse))]
GetAllDelegations { GetAllDelegations {
/// Pagination control for the values returned by the query. Note that the provided value itself will **not** be used for the response.
start_after: Option<(u32, MixId, u64)>, start_after: Option<(u32, MixId, u64)>,
/// Controls the maximum number of entries returned by the query. Note that too large values will be overwritten by a saner default.
limit: Option<u32>, limit: Option<u32>,
}, },
} }
@@ -0,0 +1,166 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use contracts_common::Percent;
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Coin, Timestamp, Uint128};
use mixnet_contract_common::MixId;
use std::str::FromStr;
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr(
feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/Period.ts")
)]
#[cw_serde]
/// The vesting period.
pub enum Period {
/// Defines a pre-vesting period.
Before,
/// Defines currently active vesting period.
In(usize),
/// Defines a post-vesting period.
After,
}
/// Information regarding pledge (i.e. mixnode or gateway bonding) made with vesting tokens.
#[cw_serde]
pub struct PledgeData {
/// The amount pledged.
pub amount: Coin,
/// The block timestamp where the pledge occurred.
pub block_time: Timestamp,
}
impl PledgeData {
pub fn amount(&self) -> Coin {
self.amount.clone()
}
pub fn block_time(&self) -> Timestamp {
self.block_time
}
pub fn new(amount: Coin, block_time: Timestamp) -> Self {
Self { amount, block_time }
}
}
/// Defines cap for pleding/staking tokens.
#[cw_serde]
pub enum PledgeCap {
/// Specifies a percent-based pledge cap, i.e. only given % of tokens could be pledged/staked.
Percent(Percent),
/// Specifies an absolute pledge cap, i.e. an explicit value that could be pledged/staked.
Absolute(Uint128), // This has to be in unym
}
impl FromStr for PledgeCap {
type Err = String;
fn from_str(cap: &str) -> Result<Self, Self::Err> {
let cap = cap.replace('_', "").replace(',', ".");
match Percent::from_str(&cap) {
Ok(p) => Ok(PledgeCap::Percent(p)),
Err(_) => match cap.parse::<u128>() {
Ok(i) => Ok(PledgeCap::Absolute(Uint128::from(i))),
Err(_e) => Err(format!("Could not parse {cap} as Percent or Uint128")),
},
}
}
}
impl Default for PledgeCap {
fn default() -> Self {
#[allow(clippy::expect_used)]
PledgeCap::Percent(Percent::from_percentage_value(10).expect("This can never fail!"))
}
}
/// Vesting period details.
#[cw_serde]
pub struct VestingPeriod {
/// The start time of this vesting period, as unix timestamp.
pub start_time: u64,
/// The duration (in seconds) of the vesting period.
pub period_seconds: u64,
}
impl VestingPeriod {
pub fn end_time(&self) -> Timestamp {
Timestamp::from_seconds(self.start_time + self.period_seconds)
}
}
#[cw_serde]
#[derive(Default)]
pub struct VestingSpecification {
start_time: Option<u64>,
period_seconds: Option<u64>,
num_periods: Option<u64>,
}
impl VestingSpecification {
pub fn new(
start_time: Option<u64>,
period_seconds: Option<u64>,
num_periods: Option<u64>,
) -> Self {
Self {
start_time,
period_seconds,
num_periods,
}
}
pub fn start_time(&self) -> Option<u64> {
self.start_time
}
pub fn period_seconds(&self) -> u64 {
self.period_seconds.unwrap_or(3 * 30 * 86400)
}
pub fn num_periods(&self) -> u64 {
self.num_periods.unwrap_or(8)
}
pub fn populate_vesting_periods(&self, start_time: u64) -> Vec<VestingPeriod> {
let mut periods = Vec::with_capacity(self.num_periods() as usize);
for i in 0..self.num_periods() {
let period = VestingPeriod {
start_time: start_time + i * self.period_seconds(),
period_seconds: self.period_seconds(),
};
periods.push(period);
}
periods
}
}
/// Details about particular vesting delegation.
#[cw_serde]
pub struct VestingDelegation {
/// The id of the vesting account that has made the delegation.
pub account_id: u32,
/// The id of the mixnode towards which the delegation has been made.
pub mix_id: MixId,
/// The block timestamp when the delegation has been made.
pub block_timestamp: u64,
/// The raw amount delegated (interpreted to be in the same denom as the underlying vesting specification)
pub amount: Uint128,
}
impl VestingDelegation {
pub fn storage_key(&self) -> (u32, MixId, u64) {
(self.account_id, self.mix_id, self.block_timestamp)
}
}
+4 -1
View File
@@ -27,14 +27,17 @@ thiserror = "1.0.37"
zeroize = { workspace = true, optional = true, features = ["zeroize_derive"] } zeroize = { workspace = true, optional = true, features = ["zeroize_derive"] }
# internal # internal
nym-sphinx-types = { path = "../nymsphinx/types", version = "0.2.0" } nym-sphinx-types = { path = "../nymsphinx/types", version = "0.2.0", default-features = false }
nym-pemstore = { path = "../../common/pemstore", version = "0.3.0" } nym-pemstore = { path = "../../common/pemstore", version = "0.3.0" }
[dev-dependencies] [dev-dependencies]
rand_chacha = "0.2" rand_chacha = "0.2"
[features] [features]
default = ["sphinx"]
serde = ["serde_crate", "serde_bytes", "ed25519-dalek/serde", "x25519-dalek/serde"] serde = ["serde_crate", "serde_bytes", "ed25519-dalek/serde", "x25519-dalek/serde"]
asymmetric = ["x25519-dalek", "ed25519-dalek", "zeroize"] asymmetric = ["x25519-dalek", "ed25519-dalek", "zeroize"]
hashing = ["blake3", "digest", "hkdf", "hmac", "generic-array"] hashing = ["blake3", "digest", "hkdf", "hmac", "generic-array"]
symmetric = ["aes", "ctr", "cipher", "generic-array"] symmetric = ["aes", "ctr", "cipher", "generic-array"]
sphinx = ["nym-sphinx-types/sphinx"]
outfox = ["nym-sphinx-types/outfox"]
@@ -273,36 +273,42 @@ impl PemStorableKey for PrivateKey {
} }
// compatibility with sphinx keys: // compatibility with sphinx keys:
#[cfg(feature = "sphinx")]
impl From<PublicKey> for nym_sphinx_types::PublicKey { impl From<PublicKey> for nym_sphinx_types::PublicKey {
fn from(key: PublicKey) -> Self { fn from(key: PublicKey) -> Self {
nym_sphinx_types::PublicKey::from(key.to_bytes()) nym_sphinx_types::PublicKey::from(key.to_bytes())
} }
} }
#[cfg(feature = "sphinx")]
impl<'a> From<&'a PublicKey> for nym_sphinx_types::PublicKey { impl<'a> From<&'a PublicKey> for nym_sphinx_types::PublicKey {
fn from(key: &'a PublicKey) -> Self { fn from(key: &'a PublicKey) -> Self {
nym_sphinx_types::PublicKey::from((*key).to_bytes()) nym_sphinx_types::PublicKey::from((*key).to_bytes())
} }
} }
#[cfg(feature = "sphinx")]
impl From<nym_sphinx_types::PublicKey> for PublicKey { impl From<nym_sphinx_types::PublicKey> for PublicKey {
fn from(pub_key: nym_sphinx_types::PublicKey) -> Self { fn from(pub_key: nym_sphinx_types::PublicKey) -> Self {
Self(x25519_dalek::PublicKey::from(*pub_key.as_bytes())) Self(x25519_dalek::PublicKey::from(*pub_key.as_bytes()))
} }
} }
#[cfg(feature = "sphinx")]
impl From<PrivateKey> for nym_sphinx_types::PrivateKey { impl From<PrivateKey> for nym_sphinx_types::PrivateKey {
fn from(key: PrivateKey) -> Self { fn from(key: PrivateKey) -> Self {
nym_sphinx_types::PrivateKey::from(key.to_bytes()) nym_sphinx_types::PrivateKey::from(key.to_bytes())
} }
} }
#[cfg(feature = "sphinx")]
impl<'a> From<&'a PrivateKey> for nym_sphinx_types::PrivateKey { impl<'a> From<&'a PrivateKey> for nym_sphinx_types::PrivateKey {
fn from(key: &'a PrivateKey) -> Self { fn from(key: &'a PrivateKey) -> Self {
nym_sphinx_types::PrivateKey::from(key.to_bytes()) nym_sphinx_types::PrivateKey::from(key.to_bytes())
} }
} }
#[cfg(feature = "sphinx")]
impl From<nym_sphinx_types::PrivateKey> for PrivateKey { impl From<nym_sphinx_types::PrivateKey> for PrivateKey {
fn from(private_key: nym_sphinx_types::PrivateKey) -> Self { fn from(private_key: nym_sphinx_types::PrivateKey) -> Self {
let private_key_bytes = private_key.to_bytes(); let private_key_bytes = private_key.to_bytes();
@@ -5,6 +5,7 @@ pub use ed25519_dalek::ed25519::signature::Signature as SignatureTrait;
pub use ed25519_dalek::SignatureError; pub use ed25519_dalek::SignatureError;
pub use ed25519_dalek::{Verifier, PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, SIGNATURE_LENGTH}; pub use ed25519_dalek::{Verifier, PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, SIGNATURE_LENGTH};
use nym_pemstore::traits::{PemStorableKey, PemStorableKeyPair}; use nym_pemstore::traits::{PemStorableKey, PemStorableKeyPair};
#[cfg(feature = "sphinx")]
use nym_sphinx_types::{DestinationAddressBytes, DESTINATION_ADDRESS_LENGTH}; use nym_sphinx_types::{DestinationAddressBytes, DESTINATION_ADDRESS_LENGTH};
use std::fmt::{self, Display, Formatter}; use std::fmt::{self, Display, Formatter};
use std::str::FromStr; use std::str::FromStr;
@@ -113,6 +114,7 @@ impl Display for PublicKey {
} }
impl PublicKey { impl PublicKey {
#[cfg(feature = "sphinx")]
pub fn derive_destination_address(&self) -> DestinationAddressBytes { pub fn derive_destination_address(&self) -> DestinationAddressBytes {
let mut temporary_address = [0u8; DESTINATION_ADDRESS_LENGTH]; let mut temporary_address = [0u8; DESTINATION_ADDRESS_LENGTH];
let public_key_bytes = self.to_bytes(); let public_key_bytes = self.to_bytes();
+9 -9
View File
@@ -7,16 +7,16 @@ 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
[dependencies] [dependencies]
tokio = { version = "1.24.1", features = [] }
tokio-stream = "0.1.11" # this one seems to be a thing until `Stream` trait is stabilised in stdlib tokio-stream = "0.1.11" # this one seems to be a thing until `Stream` trait is stabilised in stdlib
tokio-util = { version = "0.7.4", features = ["time"] }
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-timer] [target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio]
git = "https://github.com/mmsinclair/wasm-timer" workspace = true
rev = "b9d1a54ad514c2f230a026afe0dde341e98cd7b6"
[target."cfg(target_arch = \"wasm32\")".dependencies.slab] [target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-util]
version = "0.4.4" version = "0.7.4"
features = ["time"]
[target."cfg(target_arch = \"wasm32\")".dependencies.wasmtimer]
workspace = true
features = ["tokio", "tokio-util"]
[target."cfg(target_arch = \"wasm32\")".dependencies.futures-core]
version = "0.3.0"
+4 -8
View File
@@ -6,12 +6,8 @@ use std::task::{Context, Poll, Waker};
use std::time::Duration; use std::time::Duration;
use tokio_stream::Stream; use tokio_stream::Stream;
pub use tokio::time::error::Error as TimerError;
// this is a copy of tokio-util delay_queue with `Sleep` and `Instant` being replaced with // this is a copy of tokio-util delay_queue with `Sleep` and `Instant` being replaced with
// `wasm_timer` equivalents // `wasm_timer` equivalents
#[cfg(target_arch = "wasm32")]
mod wasm_delay_queue;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
type DelayQueue<T> = tokio_util::time::DelayQueue<T>; type DelayQueue<T> = tokio_util::time::DelayQueue<T>;
@@ -23,13 +19,13 @@ pub type QueueKey = tokio_util::time::delay_queue::Key;
use tokio::time::Instant; use tokio::time::Instant;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
type DelayQueue<T> = crate::wasm_delay_queue::DelayQueue<T>; type DelayQueue<T> = wasmtimer::tokio_util::DelayQueue<T>;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
pub use crate::wasm_delay_queue::delay_queue::Expired; pub use wasmtimer::tokio_util::delay_queue::Expired;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
pub type QueueKey = crate::wasm_delay_queue::delay_queue::Key; pub type QueueKey = wasmtimer::tokio_util::delay_queue::Key;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use wasm_timer::Instant; use wasmtimer::std::Instant;
/// A variant of tokio's `DelayQueue`, such that its `Stream` implementation will never return a 'None'. /// A variant of tokio's `DelayQueue`, such that its `Stream` implementation will never return a 'None'.
pub struct NonExhaustiveDelayQueue<T> { pub struct NonExhaustiveDelayQueue<T> {
File diff suppressed because it is too large Load Diff
@@ -1,42 +0,0 @@
use std::time::Duration;
mod wheel;
pub mod delay_queue;
#[doc(inline)]
pub use delay_queue::DelayQueue;
// ===== Internal utils =====
enum Round {
Up,
Down,
}
/// Convert a `Duration` to milliseconds, rounding up and saturating at
/// `u64::MAX`.
///
/// The saturating is fine because `u64::MAX` milliseconds are still many
/// million years.
#[inline]
fn ms(duration: Duration, round: Round) -> u64 {
const NANOS_PER_MILLI: u32 = 1_000_000;
const MILLIS_PER_SEC: u64 = 1_000;
// Round up.
let millis = match round {
Round::Up => (duration.subsec_nanos() + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI,
Round::Down => duration.subsec_millis(),
};
duration
.as_secs()
.saturating_mul(MILLIS_PER_SEC)
.saturating_add(u64::from(millis))
}
#[inline]
fn sleep_until(deadline: wasm_timer::Instant) -> wasm_timer::Delay {
wasm_timer::Delay::new_at(deadline)
}
@@ -1,253 +0,0 @@
use crate::wasm_delay_queue::wheel::Stack;
use std::fmt;
/// Wheel for a single level in the timer. This wheel contains 64 slots.
pub(crate) struct Level<T> {
level: usize,
/// Bit field tracking which slots currently contain entries.
///
/// Using a bit field to track slots that contain entries allows avoiding a
/// scan to find entries. This field is updated when entries are added or
/// removed from a slot.
///
/// The least-significant bit represents slot zero.
occupied: u64,
/// Slots
slot: [T; LEVEL_MULT],
}
/// Indicates when a slot must be processed next.
#[derive(Debug)]
pub(crate) struct Expiration {
/// The level containing the slot.
pub(crate) level: usize,
/// The slot index.
pub(crate) slot: usize,
/// The instant at which the slot needs to be processed.
pub(crate) deadline: u64,
}
/// Level multiplier.
///
/// Being a power of 2 is very important.
const LEVEL_MULT: usize = 64;
impl<T: Stack> Level<T> {
pub(crate) fn new(level: usize) -> Level<T> {
// Rust's derived implementations for arrays require that the value
// contained by the array be `Copy`. So, here we have to manually
// initialize every single slot.
macro_rules! s {
() => {
T::default()
};
}
Level {
level,
occupied: 0,
slot: [
// It does not look like the necessary traits are
// derived for [T; 64].
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
s!(),
],
}
}
/// Finds the slot that needs to be processed next and returns the slot and
/// `Instant` at which this slot must be processed.
pub(crate) fn next_expiration(&self, now: u64) -> Option<Expiration> {
// Use the `occupied` bit field to get the index of the next slot that
// needs to be processed.
let slot = match self.next_occupied_slot(now) {
Some(slot) => slot,
None => return None,
};
// From the slot index, calculate the `Instant` at which it needs to be
// processed. This value *must* be in the future with respect to `now`.
let level_range = level_range(self.level);
let slot_range = slot_range(self.level);
// TODO: This can probably be simplified w/ power of 2 math
let level_start = now - (now % level_range);
let deadline = level_start + slot as u64 * slot_range;
debug_assert!(
deadline >= now,
"deadline={}; now={}; level={}; slot={}; occupied={:b}",
deadline,
now,
self.level,
slot,
self.occupied
);
Some(Expiration {
level: self.level,
slot,
deadline,
})
}
fn next_occupied_slot(&self, now: u64) -> Option<usize> {
if self.occupied == 0 {
return None;
}
// Get the slot for now using Maths
let now_slot = (now / slot_range(self.level)) as usize;
let occupied = self.occupied.rotate_right(now_slot as u32);
let zeros = occupied.trailing_zeros() as usize;
let slot = (zeros + now_slot) % 64;
Some(slot)
}
pub(crate) fn add_entry(&mut self, when: u64, item: T::Owned, store: &mut T::Store) {
let slot = slot_for(when, self.level);
self.slot[slot].push(item, store);
self.occupied |= occupied_bit(slot);
}
pub(crate) fn remove_entry(&mut self, when: u64, item: &T::Borrowed, store: &mut T::Store) {
let slot = slot_for(when, self.level);
self.slot[slot].remove(item, store);
if self.slot[slot].is_empty() {
// The bit is currently set
debug_assert!(self.occupied & occupied_bit(slot) != 0);
// Unset the bit
self.occupied ^= occupied_bit(slot);
}
}
pub(crate) fn pop_entry_slot(&mut self, slot: usize, store: &mut T::Store) -> Option<T::Owned> {
let ret = self.slot[slot].pop(store);
if ret.is_some() && self.slot[slot].is_empty() {
// The bit is currently set
debug_assert!(self.occupied & occupied_bit(slot) != 0);
self.occupied ^= occupied_bit(slot);
}
ret
}
}
impl<T> fmt::Debug for Level<T> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("Level")
.field("occupied", &self.occupied)
.finish()
}
}
fn occupied_bit(slot: usize) -> u64 {
1 << slot
}
fn slot_range(level: usize) -> u64 {
LEVEL_MULT.pow(level as u32) as u64
}
fn level_range(level: usize) -> u64 {
LEVEL_MULT as u64 * slot_range(level)
}
/// Convert a duration (milliseconds) and a level to a slot position
fn slot_for(duration: u64, level: usize) -> usize {
((duration >> (level * 6)) % LEVEL_MULT as u64) as usize
}
#[cfg(all(test, not(loom)))]
mod test {
use super::*;
#[test]
fn test_slot_for() {
for pos in 0..64 {
assert_eq!(pos as usize, slot_for(pos, 0));
}
for level in 1..5 {
for pos in level..64 {
let a = pos * 64_usize.pow(level as u32);
assert_eq!(pos as usize, slot_for(a as u64, level));
}
}
}
}

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