Compare commits

...

116 Commits

Author SHA1 Message Date
Bogdan-Ștefan Neacșu 51576c2b3b Add gateway id to stats data 2022-06-29 16:38:05 +03:00
Bogdan-Ștefan Neacșu db8730d13a Update with the mainnet stats domain 2022-06-29 15:51:07 +03:00
Jon Häggblad f2afb42daf github: clippy review annotations for the workspace too (#1416)
* github: clippy review annotations for the workspace too

* client-libs: remove unused imports

* client-libs: tweak use dep

* client-libs: try to regroup cfg conditional use items
2022-06-29 08:47:12 +02:00
Bogdan-Ștefan Neacşu 03a78c04ef Get auto fee values for payer different then signer (#1414) 2022-06-29 09:34:19 +03:00
Jon Häggblad ea22a6f80f connect: allow user select gateway on backend (#1415)
* connect: allow user selected gateway

* rustfmt
2022-06-28 17:39:33 +02:00
Fouad bb0c3d251e Merge pull request #1357 from nymtech/feature/wallet-delegation-fees
Wallet: simulated delegation fees
2022-06-28 16:13:50 +01:00
Jon Häggblad 3e2c54c283 connect: expose tauri get_config_file_location (#1413)
* connect: expose get_config_file_location

* rustfmt
2022-06-28 17:11:03 +02:00
Mark Sinclair 6c9c961152 GitHub Actions: Nym Connect - fix filename 2022-06-28 16:07:56 +01:00
Jon Häggblad 64c3009aa9 connect: reuse the same id (#1412)
* connect: reuse the same id

* changelog: add note

* rustfmt

* clippy
2022-06-28 16:32:15 +02:00
Jędrzej Stuczyński a2409c0a84 Chore/network config (#1335)
* Definition of NymNetworkDetails

* Initial attempt at changing network usage for nymd client

* Removed deprecated denom call and added constructor for custom network

* Cargo fmt
2022-06-28 15:10:20 +01:00
Mark Sinclair a646f84221 GitHub Actions: fix up and adjust retention time 2022-06-28 14:53:59 +01:00
Mark Sinclair 33a6cb1f3e GitHub Actions: fix up Nym Connect output package paths 2022-06-28 13:55:56 +01:00
Jon Häggblad f8ceb0881f connect: update the hardcoded provider 2022-06-28 12:26:45 +02:00
Jon Häggblad a05830304f wallet-recovery-cli: add raw mode (#1411) 2022-06-28 07:46:11 +02:00
Mark Sinclair 8c25bc47c4 GitHub Actions: Nym Connect troubleshooting 2022-06-27 22:18:35 +01:00
Mark Sinclair c39046c4aa GitHub Actions: fix check 2022-06-27 21:05:14 +01:00
Mark Sinclair c2e4309212 GitHub Actions: add manual build steps and artifact uploads 2022-06-27 20:58:03 +01:00
Mark Sinclair 11d1397906 Nym Connect: add GitHub Actions to build signed binary 2022-06-27 20:54:07 +01:00
Jon Häggblad 479cc20083 connect: add tauri methods to get and set provider (#1406) 2022-06-27 20:54:58 +02:00
Jon Häggblad 97f77c4549 client: consolidate and de-duplicate initialization between clients and nym-connect (#1405)
* clients: consolidate and dedup init logic between clients and nym-connect

* changelog: add note

* connect: tweak print
2022-06-27 18:03:56 +02:00
Jon Häggblad 1de8b2abe9 explorer-api: add apy values to mix_nodes endpoint (#1401)
* explorer-api: add apy fields to PrettyDetailedMixNodeBond

* explorer-api: clippy warnings

* explorer-api: use uptime from mixnodes endpoint

* changelog: add note

* rustfmt
2022-06-27 16:18:56 +02:00
Mark Sinclair 70b01783bf ts-packages/react: Fix currency amount display key bug 2022-06-27 12:21:45 +01:00
Raphaël Walther c2375850f9 Changed cron time of nightly builds 2022-06-27 09:17:01 +02:00
Bogdan-Ștefan Neacşu 0df801ab4e Feature/expose validator cosmos address (#1404)
* Move coconut validator api req out of coconut interface

and expose a new cosmos-address endpoint

* Finish cosmos address endpoint

* Guard under coconut feature gateway & validator-api code

* Update CHANGELOG
2022-06-24 18:36:13 +03:00
Bogdan-Ștefan Neacşu fe9cb8a4e6 Feature/fix validator api (#1403)
* Include CoconutSigner in build for template completion

* Use dummy mnemonic for validator-api
2022-06-24 16:28:45 +03:00
fmtabbara 6f5878b6a7 add fees to operations 2022-06-24 12:49:07 +01:00
fmtabbara f4b15a8976 update type 2022-06-24 09:49:36 +01:00
fmtabbara bae495249c Merge branch 'develop' into feature/wallet-delegation-fees 2022-06-23 20:18:05 +01:00
Jędrzej Stuczyński aa3310fb9c Feature/wallet sim gas adjustment (#1388)
* Incorporating GasAdjustment into wallet fee simulation

* Adjusting the gas only a single time

* Hacky implementation of ts_rs on FeeDetails

* changelog
2022-06-23 17:31:02 +01:00
Jon Häggblad bfcc49ab78 validator-api: parametrized node reward endpoint (#1400)
* validator-api: initial work on compute reward endpoint

* validator-api: dedup and clean up

* cargo.lock
2022-06-23 13:54:45 +02:00
Jon Häggblad 3bd21300e0 validator-api: add apy data to mixnodes endpoint (#1393)
* validator-api: compute and return APY for all mixnode bonds

* validator-api: tidy

* validator-api: handle the absence of storage

* validator-api: some comments

* validator-api: refinements to apy calc

* validator-api: extract out some calculations

* changelog: add note
2022-06-23 13:42:29 +02:00
Mark Sinclair 63692eb30d GitHub Actions: fix paths 2022-06-23 11:58:16 +01:00
Mark Sinclair 6172f03ada GitHub Actions: fix typo 2022-06-23 11:57:20 +01:00
Mark Sinclair 5bb631fe8f GitHub Actions: new action to build release version of the smart contracts 2022-06-23 11:55:45 +01:00
Jędrzej Stuczyński 03aec96592 Defined DenomDetails that explicitly sets base and display names (#1389)
* Defined DenomDetails that explicitly sets base and display names

* missed substitutions

* Unused imports
2022-06-23 11:31:59 +01:00
Jon Häggblad 8c3d6fa54b wallet: fix error in unit test on windows (#1399) 2022-06-23 11:57:32 +02:00
Bogdan-Ștefan Neacşu ae88e25300 Feature/include nymd client in gateway (#1398)
* Reinclude custom validators in coconut

* Check mnemonic validity early

* Include nymd client in coconut verifier

and simplify the erc20 bridge part
2022-06-23 12:28:40 +03:00
Jon Häggblad 6b07f31a87 wallet: remove broken platform constants (#1395)
Due to a bug (typo) these constants were actually never used, and at
this point we can't fix it without breaking backwards compatibility.
2022-06-23 11:08:31 +02:00
Jon Häggblad 736fcafa9b rustfmt 2022-06-22 22:14:55 +02:00
Jędrzej Stuczyński 64687e9656 Removed mixnet contract migration 2022-06-22 17:55:14 +01:00
Jędrzej Stuczyński 49718e724e Removed mixnet contract migration 2022-06-22 17:51:38 +01:00
Jędrzej Stuczyński 8bce52f9a9 bump contract versions and update changelog 2022-06-22 17:02:07 +01:00
Mark Sinclair babc18d491 GitHub Actions: revert trigger changes 2022-06-21 19:02:51 +01:00
Mark Sinclair a5da6ccdab Update CHANGELOG for wallet release v1.0.6 2022-06-21 19:01:09 +01:00
Mark Sinclair 8dd10a5e10 GitHub Actions: wallet trigger 2022-06-21 18:52:49 +01:00
Mark Sinclair f9d3a60c32 GitHub Actions: triggers and Windows .env file 2022-06-21 18:50:08 +01:00
Drazen Urch 1178902634 Fix rewards bounds (#1391)
* Fix rewards bounds

* Fix operator reward calculation
2022-06-21 18:27:26 +02:00
Mark Sinclair c39527c841 GitHub Actions: generate wallet .env from base64 string 2022-06-21 17:04:46 +01:00
Mark Sinclair 2fecde8f19 Wallet: update copy on mixnode saturation delegation warning modal 2022-06-21 17:04:01 +01:00
Bogdan-Ștefan Neacşu 03b484dbdf Fix eth feature enabled build (#1379) 2022-06-21 15:16:17 +03:00
Drazen Urch f3a926375a Change epoch length to 10 minutes (#1345)
* Change epoch length to 10 minutes

* Derive operator cost, and reward params from epoch length

* Fix tests

* Migrate back to hourly

* Remove length migration

* Push everything
2022-06-21 14:04:27 +02:00
Drazen Urch 66b5f50ad0 Add locked token pledge limit (#1331)
* Add locked token pledge limit

* Add messages for interacting with the locked pledge cap

* Add locked pledge controls to the nymd client
2022-06-21 10:25:00 +02:00
Mark Sinclair f9cc21dce9 GitHub Actions: fix filenames in readme 2022-06-20 20:47:18 +01:00
Mark Sinclair a693195b57 Update nym-wallet-release.yml 2022-06-20 20:44:45 +01:00
Mark Sinclair c89c66b174 GitHub Actions - an action to create a wallet release 2022-06-20 20:42:43 +01:00
Jędrzej Stuczyński 42ef2eb98c Bugfix/correct reward stake supply (#1373)
* Constructing `EpochRewardParams` with proper staking_supply

* Query for current staking supply

* More crate visibility on epoch reward params

* unused import

* Remove duplicate save of epoch_reward_params

* test fixes

* Changelog

* Moved PR references to correct section

* cargo fmt

* Removed old migration code
2022-06-20 18:25:22 +01:00
Pierre Dommerc b2df4ca4fd feat(wallet): style changes to match new design (#1333)
* feat(wallet): style changes to match new design

* fix(wallet): style

* feat(wallet): style changes to match new design

* fix(wallet): style

* feat(wallet): style adjustment create mnemonic

* feat(wallet): style adjustment create mnemonic
2022-06-20 16:22:23 +01:00
Gala 608ef779d2 changing avg uptime name and tooltip (#1386) 2022-06-20 16:20:59 +01:00
Jędrzej Stuczyński c0e178fdf7 Feature/bond queries (#1369)
* Added queries to get bond details by identity key

* Added relevant calls in the nymd client

* Changelog

* Removed unused import
2022-06-20 11:25:00 +01:00
Fouad 60a58b30a1 bring back the modal (#1381) 2022-06-20 10:19:05 +01:00
Dave Hrycyszyn 135c818fee Feature/report node hardware info (#1308)
* Adding simple hardware info reporting to the mixnode HTTP API

* Adding sgx availability as another example field

* Added sysinfo crate for addtitional simple hardware reporting

* Added reporting on number of cpu cores and available ram

* Cleanup of unused struct

* Fixing merge conflict

* Checking for supported system before using sysinfo

* Breaking commit containing additional types

...and a painfully wrong implementation of the SMT processor cores type.

* Handling unavailable brand string

* Fixed getting SMT logical processor count

* Rebase with develop + cleaned up changelog

* unused import

Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
2022-06-20 09:49:32 +01:00
Raphaël Walther b4f3a48550 Fixed disk space issue with Ubuntu runner 2022-06-20 09:41:25 +02:00
fmtabbara 3e5aeefbb8 Merge branch 'develop' into feature/wallet-delegation-fees 2022-06-17 10:43:53 +01:00
fmtabbara 8cc244cf9c include vesting fees for delegate and undelegate 2022-06-17 10:43:22 +01:00
Jon Häggblad 56b1dba66a cargo upgrade rocket --workspace (#1330) 2022-06-16 17:59:46 +02:00
Fouad 6bd0ff796a archive password when new paasword is created (#1380) 2022-06-16 16:02:36 +01:00
Jon Häggblad 287c45d6b5 ci: add nym-connect rust to build (#1378)
* ci: add nym-connect rust to build

* rustfmt

* connect: add gitkeep in dist dir

* wallet: dont trigger connect on pull_request

* github: libayatana-indicator3-dev

* github: libayatana-appindicator3-dev
2022-06-16 16:45:33 +02:00
Bogdan-Ștefan Neacșu 3aff419a76 Fix imports for macos 2022-06-16 16:26:51 +02:00
Bogdan-Ștefan Neacşu 4f46e36aa8 Feature/gateway direct stats (#1376)
* Make gateway mnemonic optional

* Remove unnecessary timer struct

* Prepare for code reuse

* Use trait for stats collector

* Put trait definition in common crate

* Gateway stats runner

* Custom statistics url arg

* Build & send stats req to url

* Storage support for new stats type

* Make gateway stats opt in

* Test&clippy fixes

* CHANGELOG update
2022-06-16 15:24:31 +02:00
Mark Sinclair c59e8086a6 GitHub Actions: fix up .env file generation 2022-06-16 14:14:20 +01:00
Mark Sinclair f8c8b1a85e GitHub Actions: adjust generating .env file and add conditional to release upload 2022-06-16 14:09:42 +01:00
Mark Sinclair c926e0e652 GitHub Actions: fix syntax error 2022-06-16 13:43:54 +01:00
Mark Sinclair 2689de2334 GitHub Actions: fix up condition 2022-06-16 13:42:46 +01:00
Mark Sinclair 92f154fde5 GitHub Actions: generate wallet .env file and add manual trigger for MacOS build 2022-06-16 13:35:07 +01:00
Mark Sinclair eaf207b667 GitHub Actions: delete test file 2022-06-16 13:22:25 +01:00
Mark Sinclair 13d74200e2 GitHub Actions: add test workflow 2022-06-16 13:19:51 +01:00
fmtabbara 3816c94ee5 merge develop 2022-06-16 13:05:47 +01:00
Pierre Dommerc b42472486f feat(wallet): add a custom link component to match new design (#1355)
* feat(wallet): add custom link component

* feat(wallet): uniformize links

* feat(wallet): move link component to ts-packages

* feat(wallet): post merge fix

* ts-packages: build theme first, then react components

* Update README.md

Co-authored-by: Mark Sinclair <mmsinclair@gmail.com>
2022-06-16 12:36:30 +01:00
Mark Sinclair 661a1420c1 Wallet: add error checking when switching networks and determining admin mode 2022-06-16 12:12:44 +01:00
Jon Häggblad 784f6d0939 wallet: dont try archive if file doesnt exist (#1377) 2022-06-16 11:52:23 +01:00
Jon Häggblad 5b715acc4e client: allow rerun init for gateway config (#1353)
* socks5: reuse existing gateway configuration instead of failing on init

* socks5: rework setting and registering gateway logic

* rustfmt

* client/native: port same changes here

* changelog: add note about re-running init for clients

* client-core/config: add with_gateway_endpoint_from_config

* clients: pass GatewayEndpoint

* clients: add warning note onf force-register-gateway

* connect: fix with_gateway_endpoint call
2022-06-16 12:24:19 +02:00
Gala 8eae2e3136 Wallet: Sending again the NodeId to fetch the saturation (#1375)
* Sending again the identity key when fetching the saturation

* Remove non-null assertion
2022-06-16 10:39:23 +01:00
Mark Sinclair e1a1b70832 Wallet: remove pre from version to try to fix Windows build failing on candle.exe 2022-06-16 10:38:20 +01:00
Mark Sinclair dc0cb3f68b GitHub Actions - make node version install regular and install NodeJS v16 2022-06-16 09:36:18 +01:00
Raphaël Walther 216b5535b3 Fixed nightly build windows storage issue 2022-06-16 08:58:04 +02:00
Mark Sinclair 8819e81393 Wallet: add env var ENABLE_QA_MODE to show QA network in built wallet versions 2022-06-15 19:03:49 +01:00
Mark Sinclair ce26c3cf76 Wallet: create main context mock to fix up delegation page stories 2022-06-15 18:19:22 +01:00
Mark Sinclair b826b5d957 Wallet: Fix up stories and linting 2022-06-15 18:18:58 +01:00
Mark Sinclair a4ec7e4912 Wallet: handle redeem and compound 2022-06-15 17:40:33 +01:00
Mark Sinclair a67a80d28d Derive debug for wallet types 2022-06-15 17:34:54 +01:00
Gala 1ad458b2be Wallet: Avoid oversaturated node delegation or compound (#1356)
* wip checking ts-package

* adding the validation to the identity form field

* changing the error message

* changing node oversaturated error mss

* adding oversaturated modal blocker

* adding error colour to palette, and styles to basic modal

* wip

* wip

* some refactor

* dont validate field till we have api response

* fix typo

* adding line break

* catch error when node is not valid

* handle error out of the field component

* removing logs

* Adding disableCompoundRewards prop in DelegationsActionsMenu

* Adding disableCompoundRewards to DelegationsActionsMenu

* refactor validation

* Revert some not needed changes

* adding line break

* adding stories

Co-authored-by: fmtabbara <fmtabbara@hotmail.co.uk>
2022-06-15 16:51:57 +01:00
Mark Sinclair 937ae22e6b Wallet - fix redeeming, compounding and undelegating with vesting contract (#1372)
* Add TODO reminders to implement vesting contract checks for operator reward compounding and redemption

* Add tauri operation to compound and redeem for locked and unlocked tokens

* Remove rewards from delegations context

* Claim and compound rewards for rewards context

* Delegations modal handles multiple transactions and can show the vested token balance (when present)

* Integrate changes to reward and delegation contexts

* Remove unused files

* Fix eslint errors

* Regenerate types

* Add tauri operation to undelegate using the mixnet and vesting contracts for a mixnode, producing two txs

* Fix up undelegation for mixed mixnet and vesting contract delegations

* Changelog grooming

* Update changelog
2022-06-15 16:51:37 +01:00
Fouad e6ffbc468b Wallet: create forgot password page (#1367)
* create forgot password page

* navigate back

* add rust work

* pr update
2022-06-15 16:50:35 +01:00
Jon Häggblad 8a3f7a869b wallet: add archive_wallet_file (#1370)
* wallet: add archive_wallet_file

* wallet: fix append filename test

* wallet: simplify exit logic

* rustfmt

* changelog: add entry

* wallet: fix append filename test
2022-06-15 16:57:11 +02:00
Jon Häggblad 4240a88be3 connect: remove webdriver directory (#1371) 2022-06-15 16:40:15 +02:00
dependabot[bot] cc293dc166 build(deps): bump simple-get from 3.1.0 to 3.1.1 in /nym-connect
Bumps [simple-get](https://github.com/feross/simple-get) from 3.1.0 to 3.1.1.
- [Release notes](https://github.com/feross/simple-get/releases)
- [Commits](https://github.com/feross/simple-get/compare/v3.1.0...v3.1.1)

---
updated-dependencies:
- dependency-name: simple-get
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-15 10:46:55 +01:00
dependabot[bot] 01f9871d1f build(deps): bump follow-redirects from 1.14.5 to 1.15.1 in /nym-connect (#1361)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.5 to 1.15.1.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.5...v1.15.1)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-15 10:23:25 +01:00
dependabot[bot] 244410f69d build(deps): bump async from 3.2.1 to 3.2.4 in /nym-connect/webdriver (#1359)
Bumps [async](https://github.com/caolan/async) from 3.2.1 to 3.2.4.
- [Release notes](https://github.com/caolan/async/releases)
- [Changelog](https://github.com/caolan/async/blob/master/CHANGELOG.md)
- [Commits](https://github.com/caolan/async/compare/v3.2.1...v3.2.4)

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

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-15 10:23:17 +01:00
Raphaël Walther b0517705ba Merge pull request #1364 from nymtech/chore/lock-dkg-tests-in-CI
Ignored most of expensive dkg tests and made them run only on PRs to develop/master
2022-06-15 09:29:53 +02:00
Jędrzej Stuczyński c7b480f488 Added expensive tests to nightly CI 2022-06-14 17:07:04 +01:00
Jędrzej Stuczyński 088b7ab16d Ignored most of expensive dkg tests and made them run only on PRs to develop/master 2022-06-14 17:03:35 +01:00
fmtabbara 660c813c0a remove duplicate function 2022-06-14 11:57:04 +01:00
Jędrzej Stuczyński ba8a8cbfa4 Added simulation endpoints for vesting delegation 2022-06-14 11:25:24 +01:00
fmtabbara 0702968f3a merge develop 2022-06-14 10:08:38 +01:00
fmtabbara ce7d02220f refactor 2022-06-13 17:17:26 +01:00
fmtabbara 70011d0592 add fees for claim and compound 2022-06-13 11:35:34 +01:00
fmtabbara 0a632599cd make subheader optional 2022-06-11 00:22:50 +01:00
fmtabbara a9ff98418c update modals 2022-06-11 00:19:00 +01:00
fmtabbara 7d4f6c0bbd give SimpleModal component a secondary action 2022-06-10 21:49:26 +01:00
fmtabbara b731aa0bcf update modals 2022-06-10 21:48:43 +01:00
fmtabbara 89d4910e6f update simulation functions 2022-06-10 21:47:17 +01:00
fmtabbara 4ea9bb7dc6 fix spelling error 2022-06-10 21:41:09 +01:00
fmtabbara cfc7e6df77 widen delegation modals 2022-06-10 21:40:49 +01:00
fmtabbara a7a39526b4 move modal list item to shared dir 2022-06-10 21:40:28 +01:00
fmtabbara 70a9bd0f6d fix heading bug 2022-06-10 21:39:44 +01:00
fmtabbara 4cbbead359 create new tx confirmation modal 2022-06-10 21:38:53 +01:00
341 changed files with 6261 additions and 6614 deletions
+2 -2
View File
@@ -13,9 +13,9 @@ jobs:
- name: Install rsync - name: Install rsync
run: sudo apt-get install rsync run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v2 - uses: actions/setup-node@v3
with: with:
node-version: '16' node-version: 16
- name: Setup yarn - name: Setup yarn
run: npm install -g yarn run: npm install -g yarn
- name: Build - name: Build
+8 -1
View File
@@ -41,6 +41,13 @@ jobs:
command: test command: test
args: --workspace --all-features args: --workspace --all-features
- name: Run expensive tests
if: github.ref == 'refs/heads/develop' || github.event.pull_request.base.ref == 'develop' || github.event.pull_request.base.ref == 'master'
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace --all-features -- --ignored
- name: Check formatting - name: Check formatting
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
@@ -51,7 +58,7 @@ jobs:
name: Clippy checks name: Clippy checks
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
args: --all-features args: --workspace --all-features
- name: Run clippy - name: Run clippy
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
+56
View File
@@ -0,0 +1,56 @@
name: Nym Connect (rust)
on:
push:
paths-ignore:
- 'explorer/**'
jobs:
build:
runs-on: [ self-hosted, custom-linux ]
env:
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
steps:
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools libayatana-appindicator3-dev
- name: Check out repository code
uses: actions/checkout@v2
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt, clippy
- name: Build all binaries
uses: actions-rs/cargo@v1
with:
command: build
args: --manifest-path nym-connect/Cargo.toml --workspace
- name: Run all tests
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path nym-connect/Cargo.toml --workspace
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path nym-connect/Cargo.toml --all -- --check
- uses: actions-rs/clippy-check@v1
name: Clippy checks
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --manifest-path nym-connect/Cargo.toml --workspace --all-features
- name: Run clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --manifest-path nym-connect/Cargo.toml --workspace --all-features -- -D warnings
+38
View File
@@ -0,0 +1,38 @@
name: Build release of Nym smart contracts
on:
workflow_dispatch:
defaults:
run:
working-directory: contracts
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: wasm32-unknown-unknown
override: true
components: rustfmt, clippy
- name: Build release contracts
run: RUSTFLAGS='-C link-arg=-s' cargo build --release --target wasm32-unknown-unknown
- name: Upload Mixnet Contract Artifact
uses: actions/upload-artifact@v3
with:
name: mixnet_contract.wasm
path: contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm
retention-days: 5
- name: Upload Vesting Contract Artifact
uses: actions/upload-artifact@v3
with:
name: vesting_contract.wasm
path: contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm
retention-days: 5
+2 -2
View File
@@ -14,9 +14,9 @@ jobs:
runs-on: custom-runner-linux runs-on: custom-runner-linux
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/setup-node@v2 - uses: actions/setup-node@v3
with: with:
node-version: '16' node-version: 16
- name: Setup yarn - name: Setup yarn
run: npm install -g yarn run: npm install -g yarn
- name: Run ESLint - name: Run ESLint
+2 -2
View File
@@ -17,9 +17,9 @@ jobs:
- name: Install rsync - name: Install rsync
run: sudo apt-get install rsync run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v2 - uses: actions/setup-node@v3
with: with:
node-version: '16' node-version: 16
- name: Setup yarn - name: Setup yarn
run: npm install -g yarn run: npm install -g yarn
continue-on-error: true continue-on-error: true
+16 -3
View File
@@ -2,7 +2,7 @@ name: Nightly builds
on: on:
schedule: schedule:
- cron: '14 4 * * *' - cron: '14 1 * * *'
jobs: jobs:
matrix_prep: matrix_prep:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -50,6 +50,19 @@ jobs:
command: test command: test
args: --workspace args: --workspace
- name: Reclaim some disk space (because Windows is being annoying)
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' }}
with:
command: clean
- name: Run expensive tests
if: github.ref == 'refs/heads/develop' || github.event.pull_request.base.ref == 'develop' || github.event.pull_request.base.ref == 'master'
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace --all-features -- --ignored
- name: Check formatting - name: Check formatting
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
@@ -75,9 +88,9 @@ jobs:
command: clippy command: clippy
args: --workspace --all-targets -- -D warnings args: --workspace --all-targets -- -D warnings
- name: Reclaim some disk space (because Windows is being annoying) - name: Reclaim some disk space
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' }} if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-latest' }}
with: with:
command: clean command: clean
@@ -0,0 +1,96 @@
name: Publish Nym Connect (MacOS)
on:
workflow_dispatch:
release:
types: [created]
defaults:
run:
working-directory: nym-connect
jobs:
publish-tauri:
strategy:
fail-fast: false
matrix:
platform: [macos-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v2
- name: Check the release tag starts with `nym-connect-`
if: startsWith(github.ref, 'refs/tags/nym-connect-') == false && github.event_name != 'workflow_dispatch'
uses: actions/github-script@v3
with:
script: |
core.setFailed('Release tag did not start with nym-connect-...')
- name: Node v16
uses: actions/setup-node@v3
with:
node-version: 16
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install the Apple developer certificate for code signing
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
# create variables
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
# import certificate and provisioning profile from secrets
echo -n "$APPLE_CERTIFICATE" | base64 --decode --output $CERTIFICATE_PATH
# create temporary keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# import certificate to keychain
security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
- name: Create env file
uses: timheuer/base64-to-file@v1.1
with:
fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Install app dependencies and build it
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ENABLE_CODE_SIGNING: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_IDENTITY_ID }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
run: yarn && yarn build
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: nym-connect_1.0.0_x64.dmg
path: nym-connect/target/release/bundle/dmg/nym-connect_1.0.0_x64.dmg
retention-days: 30
- name: Clean up keychain
if: ${{ always() }}
run: |
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
nym-connect/target/release/bundle/dmg/*.dmg
nym-connect/target/release/bundle/macos/*.app.tar.gz*
@@ -0,0 +1,68 @@
name: Publish Nym Connect (Ubuntu)
on:
workflow_dispatch:
release:
types: [created]
defaults:
run:
working-directory: nym-connect
jobs:
publish-tauri:
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v2
- name: Tauri dependencies
run: >
sudo apt-get update &&
sudo apt-get install -y webkit2gtk-4.0 libayatana-appindicator3-dev
- name: Check the release tag starts with `nym-connect-`
if: startsWith(github.ref, 'refs/tags/nym-connect-') == false && github.event_name != 'workflow_dispatch'
uses: actions/github-script@v3
with:
script: |
core.setFailed('Release tag did not start with nym-connect-...')
- name: Node v16
uses: actions/setup-node@v3
with:
node-version: 16
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install app dependencies
run: yarn
- name: Create env file
uses: timheuer/base64-to-file@v1.1
with:
fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Build app
run: yarn build
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: nym-connect.AppImage.tar.gz
path: nym-connect/target/release/bundle/appimage/nym-connect_1.0.0_amd64.AppImage
retention-days: 30
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
nym-connect/target/release/bundle/appimage/*.AppImage
nym-connect/target/release/bundle/appimage/*.AppImage.tar.gz*
@@ -0,0 +1,90 @@
name: Publish Nym Connect (Windows 10)
on:
workflow_dispatch:
release:
types: [created]
defaults:
run:
working-directory: nym-connect
jobs:
publish-tauri:
strategy:
fail-fast: false
matrix:
platform: [windows10]
runs-on: ${{ matrix.platform }}
steps:
- name: Clean up first
continue-on-error: true
working-directory: .
run: |
cd ..
del /s /q /A:H nym
rmdir /s /q nym
- uses: actions/checkout@v3
- name: Check the release tag starts with `nym-connect-`
if: startsWith(github.ref, 'refs/tags/nym-connect-') == false && github.event_name != 'workflow_dispatch'
uses: actions/github-script@v3
with:
script: |
core.setFailed('Release tag did not start with nym-connect-...')
- name: Import signing certificate
env:
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
run: |
New-Item -ItemType directory -Path certificate
Set-Content -Path certificate/tempCert.txt -Value $env:WINDOWS_CERTIFICATE
certutil -decode certificate/tempCert.txt certificate/certificate.pfx
Remove-Item -path certificate -include tempCert.txt
Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
- name: Node v16
uses: actions/setup-node@v3
with:
node-version: 16
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Create env file
uses: timheuer/base64-to-file@v1.1
with:
fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Install app dependencies
run: yarn
- name: Build and sign it
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }}
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
run: yarn build
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: nym-connect_1.0.0_x64_en-US.msi
path: nym-connect/target/release/bundle/msi/nym-connect_1.0.0_x64_en-US.msi
retention-days: 30
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
nym-connect/target/release/bundle/msi/*.msi
nym-connect/target/release/bundle/msi/*.msi.zip*
+2 -2
View File
@@ -17,9 +17,9 @@ jobs:
- name: Install rsync - name: Install rsync
run: sudo apt-get install rsync run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v2 - uses: actions/setup-node@v3
with: with:
node-version: '16' node-version: 16
- name: Install Yarn - name: Install Yarn
run: npm install -g yarn run: npm install -g yarn
- run: yarn - run: yarn
+23 -9
View File
@@ -1,5 +1,6 @@
name: Publish Nym Wallet (MacOS) name: Publish Nym Wallet (MacOS)
on: on:
workflow_dispatch:
release: release:
types: [created] types: [created]
@@ -19,16 +20,16 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Check the release tag starts with `nym-wallet-` - name: Check the release tag starts with `nym-wallet-`
if: startsWith(github.ref, 'refs/tags/nym-wallet-') == false if: startsWith(github.ref, 'refs/tags/nym-wallet-') == false && github.event_name != 'workflow_dispatch'
uses: actions/github-script@v3 uses: actions/github-script@v3
with: with:
script: | script: |
core.setFailed('Release tag did not start with nym-wallet-...') core.setFailed('Release tag did not start with nym-wallet-...')
- name: Node v16 - name: Node v16
uses: actions/setup-node@v1 uses: actions/setup-node@v3
with: with:
node-version: 16.x node-version: 16
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
@@ -55,6 +56,12 @@ jobs:
security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH security list-keychain -d user -s $KEYCHAIN_PATH
- name: Create env file
uses: timheuer/base64-to-file@v1.1
with:
fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Install app dependencies and build it - name: Install app dependencies and build it
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -66,17 +73,24 @@ jobs:
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
ADMIN_ADDRESS: ${{ secrets.WALLET_ADMIN_ADDRESS }}
run: yarn && yarn build run: yarn && yarn build
- name: Upload to release based on tag name - name: Upload Artifact
uses: softprops/action-gh-release@v1 uses: actions/upload-artifact@v3
with: with:
files: | name: nym-wallet.app.tar.gz
nym-wallet/target/release/bundle/dmg/*.dmg path: nym-wallet/target/release/bundle/macos/nym-wallet.app.tar.gz
nym-wallet/target/release/bundle/macos/*.app.tar.gz* retention-days: 5
- name: Clean up keychain - name: Clean up keychain
if: ${{ always() }} if: ${{ always() }}
run: | run: |
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
nym-wallet/target/release/bundle/dmg/*.dmg
nym-wallet/target/release/bundle/macos/*.app.tar.gz*
@@ -30,21 +30,26 @@ jobs:
core.setFailed('Release tag did not start with nym-wallet-...') core.setFailed('Release tag did not start with nym-wallet-...')
- name: Node v16 - name: Node v16
uses: actions/setup-node@v1 uses: actions/setup-node@v3
with: with:
node-version: 16.x node-version: 16
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
- name: Install app dependencies - name: Install app dependencies
run: yarn run: yarn
- name: Create env file
uses: timheuer/base64-to-file@v1.1
with:
fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Build app - name: Build app
run: yarn build run: yarn build
env: env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
ADMIN_ADDRESS: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Upload to release based on tag name - name: Upload to release based on tag name
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
with: with:
@@ -45,15 +45,21 @@ jobs:
Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText) Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
- name: Node v16 - name: Node v16
uses: actions/setup-node@v1 uses: actions/setup-node@v3
with: with:
node-version: 16.x node-version: 16
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
- name: Create env file
uses: timheuer/base64-to-file@v1.1
with:
fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Install app dependencies - name: Install app dependencies
run: yarn run: yarn
@@ -65,7 +71,6 @@ jobs:
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }} WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
ADMIN_ADDRESS: ${{ secrets.WALLET_ADMIN_ADDRESS }}
run: yarn build run: yarn build
- name: Upload to release based on tag name - name: Upload to release based on tag name
+32
View File
@@ -0,0 +1,32 @@
name: Release Nym Wallet
on:
workflow_dispatch:
inputs:
nym_wallet_version:
description: 'The version of the Nym Wallet to release'
default: '1.0.x'
required: true
type: string
jobs:
create-release:
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v2
- name: Create release
uses: softprops/action-gh-release@v1
with:
body: >-
This is a pre-release
Download the wallet for your platform:
- [Linux](https://github.com/nymtech/nym/releases/download/nym-wallet-v${{ inputs.nym_wallet_version}}/nym-wallet_v${{ inputs.nym_wallet_version}}_amd64_ubuntu20.04.AppImage)
- [MacOS](https://github.com/nymtech/nym/releases/download/nym-wallet-v${{ inputs.nym_wallet_version}}/nym-wallet_v${{ inputs.nym_wallet_version}}_x64_macos_11.dmg)
- [Windows](https://github.com/nymtech/nym/releases/download/nym-wallet-v${{ inputs.nym_wallet_version}}/nym-wallet_v${{ inputs.nym_wallet_version}}_x64_windows.msi)
prerelease: true
name: Nym Wallet v${{ inputs.nym_wallet_version}}
tag_name: nym-wallet-v${{ inputs.nym_wallet_version}}
+2 -2
View File
@@ -13,9 +13,9 @@ jobs:
- name: Install rsync - name: Install rsync
run: sudo apt-get install rsync run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v2 - uses: actions/setup-node@v3
with: with:
node-version: '16' node-version: 16
- name: Setup yarn - name: Setup yarn
run: npm install -g yarn run: npm install -g yarn
- name: Build dependencies - name: Build dependencies
+2 -2
View File
@@ -34,9 +34,9 @@ jobs:
toolchain: stable toolchain: stable
- name: Node v16 - name: Node v16
uses: actions/setup-node@v1 uses: actions/setup-node@v3
with: with:
node-version: 16.x node-version: 16
- name: Install yarn for building application - name: Install yarn for building application
run: yarn install run: yarn install
+74 -29
View File
@@ -2,25 +2,78 @@
Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased] ## [Unreleased]
### Added ### Added
- nym-connect: initial proof-of-concept of a UI around the socks5 client was added. - socks5 client/websocket client: add `--force-register-gateway` flag, useful when rerunning init ([#1353])
- nym-connect: initial proof-of-concept of a UI around the socks5 client was added
- all: added network compilation target to `--help` (or `--version`) commands ([#1256]). - all: added network compilation target to `--help` (or `--version`) commands ([#1256]).
- explorer-api: learned how to sum the delegations by owner in a new endpoint. - explorer-api: learned how to sum the delegations by owner in a new endpoint.
- explorer-api: add apy values to `mix_nodes` endpoint
- gateway: Added gateway coconut verifications and validator-api communication for double spending protection ([#1261]) - gateway: Added gateway coconut verifications and validator-api communication for double spending protection ([#1261])
- mixnet-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
- mixnet-contract: Replace all naked `-` with `saturating_sub`.
- mixnet-contrat: Added staking_supply field to ContractStateParams.
- network-explorer-ui: Upgrade to React Router 6 - network-explorer-ui: Upgrade to React Router 6
- rewarding: replace circulating supply with staking supply in reward calculations ([#1324]) - rewarding: replace circulating supply with staking supply in reward calculations ([#1324])
- validator-api: add `estimated_node_profit` and `estimated_operator_cost` to `reward-estimate` endpoint ([#1284]) - validator-api: add `estimated_node_profit` and `estimated_operator_cost` to `reward-estimate` endpoint ([#1284])
- validator-api: add detailed mixnode bond endpoints, and explorer-api makes use of that data to append stake saturation. - validator-api: add detailed mixnode bond endpoints, and explorer-api makes use of that data to append stake saturation
- validator-api: add Swagger to document the REST API ([#1249]). - validator-api: add Swagger to document the REST API ([#1249]).
- validator-api: Added new endpoints for coconut spending flow and communications with coconut & multisig contracts ([#1261]) - validator-api: Added new endpoints for coconut spending flow and communications with coconut & multisig contracts ([#1261])
- vesting-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292]) - validator-api: add `uptime`, `estimated_operator_apy`, `estimated_delegators_apy` to `/mixnodes/detailed` endpoint ([#1393])
- network-statistics: a new mixnet service that aggregates and exposes anonymized data about mixnet services ([#1328]) - network-statistics: a new mixnet service that aggregates and exposes anonymized data about mixnet services ([#1328])
- wallet: when simulating gas costs, an automatic adjustment is being used ([#1388]).
- mixnode: Added basic mixnode hardware reporting to the HTTP API ([#1308]).
- validator-api: endpoint, in coconut mode, for returning the validator-api cosmos address ([#1404]).
### Fixed
- mixnode, gateway: attempting to determine reconnection backoff to persistently failing mixnode could result in a crash ([#1260])
- mixnode: the mixnode learned how to shutdown gracefully
- native & socks5 clients: fail early when clients try to re-init with a different gateway, which is not supported yet ([#1322])
- native & socks5 clients: rerun init will now reuse previous gateway configuration instead of failing ([#1353])
- native & socks5 clients: deduplicate big chunks of init logic
- validator: fixed local docker-compose setup to work on Apple M1 ([#1329])
### Changed
- nym-connect: reuse config id instead of creating a new id on each connection.
- validator-client: created internal `Coin` type that replaces coins from `cosmrs` and `cosmwasm` for API entrypoints [[#1295]]
- all: updated all `cosmwasm`-related dependencies to `1.0.0` and `cw-storage-plus` to `0.13.4` [[#1318]]
- all: updated `rocket` to `0.5.0-rc.2`.
- network-requester: allow to voluntarily store and send statistical data about the number of bytes the proxied server serves ([#1328])
- gateway: allow to voluntarily send statistical data about the number of active inboxes served by a gateway ([#1376])
[#1249]: https://github.com/nymtech/nym/pull/1249
[#1256]: https://github.com/nymtech/nym/pull/1256
[#1260]: https://github.com/nymtech/nym/pull/1260
[#1261]: https://github.com/nymtech/nym/pull/1261
[#1267]: https://github.com/nymtech/nym/pull/1267
[#1278]: https://github.com/nymtech/nym/pull/1278
[#1295]: https://github.com/nymtech/nym/pull/1295
[#1302]: https://github.com/nymtech/nym/pull/1302
[#1308]: https://github.com/nymtech/nym/pull/1308
[#1318]: https://github.com/nymtech/nym/pull/1318
[#1322]: https://github.com/nymtech/nym/pull/1322
[#1324]: https://github.com/nymtech/nym/pull/1324
[#1328]: https://github.com/nymtech/nym/pull/1328
[#1329]: https://github.com/nymtech/nym/pull/1329
[#1353]: https://github.com/nymtech/nym/pull/1353
[#1376]: https://github.com/nymtech/nym/pull/1376
[#1388]: https://github.com/nymtech/nym/pull/1388
[#1393]: https://github.com/nymtech/nym/pull/1393
[#1404]: https://github.com/nymtech/nym/pull/1404
## [nym-contracts-v1.0.1](https://github.com/nymtech/nym/tree/nym-contracts-v1.0.1) (2022-06-22)
### Added
- mixnet-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
- mixnet-contract: Replace all naked `-` with `saturating_sub`.
- mixnet-contract: Added staking_supply field to ContractStateParams.
- mixnet-contract: Added a query to get MixnodeBond by identity key ([#1369]).
- mixnet-contract: Added a query to get GatewayBond by identity key ([#1369]).
- vesting-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
- vesting-contract: Added limit to the amount of tokens one can pledge ([#1331])
### Fixed ### Fixed
@@ -29,37 +82,26 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
- mixnet-contract: removed `expect` in `query_delegator_reward` and queries containing invalid proxy address should now return a more human-readable error ([#1257]) - mixnet-contract: removed `expect` in `query_delegator_reward` and queries containing invalid proxy address should now return a more human-readable error ([#1257])
- mixnet-contract: replaced integer division with fixed for performance calculations ([#1284]) - mixnet-contract: replaced integer division with fixed for performance calculations ([#1284])
- mixnet-contract: Under certain circumstances nodes could not be unbonded ([#1255](https://github.com/nymtech/nym/issues/1255)) ([#1258]) - mixnet-contract: Under certain circumstances nodes could not be unbonded ([#1255](https://github.com/nymtech/nym/issues/1255)) ([#1258])
- mixnode, gateway: attempting to determine reconnection backoff to persistently failing mixnode could result in a crash ([#1260]) - mixnet-contract: Using correct staking supply when distributing rewards. ([#1373])
- mixnode: the mixnode learned how to shutdown gracefully.
- vesting-contract: replaced `checked_sub` with `saturating_sub` to fix the underflow in `get_vesting_tokens` ([#1275]) - vesting-contract: replaced `checked_sub` with `saturating_sub` to fix the underflow in `get_vesting_tokens` ([#1275])
- native & socks5 clients: fail early when clients try to re-init with a different gateway, which is not supported yet ([#1322])
- validator: fixed local docker-compose setup to work on Apple M1 ([#1329])
### Changed
- validator-client: created internal `Coin` type that replaces coins from `cosmrs` and `cosmwasm` for API entrypoints [[#1295]] [#1255]: https://github.com/nymtech/nym/pull/1255
- all: updated all `cosmwasm`-related dependencies to `1.0.0` and `cw-storage-plus` to `0.13.4` [[#1318]]
- network-requester: allow to voluntarily store and send statistical data about the number of bytes the proxied server serves ([#1328])
[#1249]: https://github.com/nymtech/nym/pull/1249
[#1256]: https://github.com/nymtech/nym/pull/1256
[#1257]: https://github.com/nymtech/nym/pull/1257 [#1257]: https://github.com/nymtech/nym/pull/1257
[#1258]: https://github.com/nymtech/nym/pull/1258 [#1258]: https://github.com/nymtech/nym/pull/1258
[#1260]: https://github.com/nymtech/nym/pull/1260
[#1261]: https://github.com/nymtech/nym/pull/1261
[#1265]: https://github.com/nymtech/nym/pull/1265
[#1267]: https://github.com/nymtech/nym/pull/1267
[#1275]: https://github.com/nymtech/nym/pull/1275 [#1275]: https://github.com/nymtech/nym/pull/1275
[#1278]: https://github.com/nymtech/nym/pull/1278
[#1284]: https://github.com/nymtech/nym/pull/1284 [#1284]: https://github.com/nymtech/nym/pull/1284
[#1292]: https://github.com/nymtech/nym/pull/1292 [#1292]: https://github.com/nymtech/nym/pull/1292
[#1295]: https://github.com/nymtech/nym/pull/1295 [#1331]: https://github.com/nymtech/nym/pull/1331
[#1302]: https://github.com/nymtech/nym/pull/1302 [#1369]: https://github.com/nymtech/nym/pull/1369
[#1318]: https://github.com/nymtech/nym/pull/1318 [#1373]: https://github.com/nymtech/nym/pull/1373
[#1322]: https://github.com/nymtech/nym/pull/1322
[#1324]: https://github.com/nymtech/nym/pull/1324 ## [nym-wallet-v1.0.6](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.6) (2022-06-21)
[#1328]: https://github.com/nymtech/nym/pull/1328
[#1329]: https://github.com/nymtech/nym/pull/1329 - wallet: undelegating now uses either the mixnet or vesting contract, or both, depending on how delegations were made
- wallet: redeeming and compounding now uses both the mixnet and vesting contract
- wallet: the wallet backend learned how to archive wallet files
- wallet: add ENABLE_QA_MODE environment variable to enable QA mode on built wallet
## [nym-wallet-v1.0.5](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.5) (2022-06-14) ## [nym-wallet-v1.0.5](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.5) (2022-06-14)
@@ -74,6 +116,9 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
- wallet: staking_supply field to StateParams - wallet: staking_supply field to StateParams
- wallet: show transaction hash for redeeming or compounding rewards - wallet: show transaction hash for redeeming or compounding rewards
[#1265]: https://github.com/nymtech/nym/pull/1265
[#1302]: https://github.com/nymtech/nym/pull/1302
## [nym-wallet-v1.0.4](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.4) (2022-05-04) ## [nym-wallet-v1.0.4](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.4) (2022-05-04)
### Changed ### Changed
Generated
+168 -185
View File
@@ -14,6 +14,15 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aead"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877"
dependencies = [
"generic-array 0.14.5",
]
[[package]] [[package]]
name = "aes" name = "aes"
version = "0.7.5" version = "0.7.5"
@@ -38,6 +47,20 @@ dependencies = [
"cpufeatures", "cpufeatures",
] ]
[[package]]
name = "aes-gcm"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6"
dependencies = [
"aead",
"aes 0.7.5",
"cipher 0.3.0",
"ctr 0.8.0",
"ghash",
"subtle 2.4.1",
]
[[package]] [[package]]
name = "ahash" name = "ahash"
version = "0.7.6" version = "0.7.6"
@@ -198,12 +221,6 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "base-x"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b"
[[package]] [[package]]
name = "base16ct" name = "base16ct"
version = "0.1.1" version = "0.1.1"
@@ -250,7 +267,7 @@ dependencies = [
"pbkdf2", "pbkdf2",
"rand_core 0.6.3", "rand_core 0.6.3",
"ripemd160", "ripemd160",
"sha2", "sha2 0.9.9",
"subtle 2.4.1", "subtle 2.4.1",
"zeroize", "zeroize",
] ]
@@ -410,7 +427,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3"
dependencies = [ dependencies = [
"sha2", "sha2 0.9.9",
] ]
[[package]] [[package]]
@@ -701,12 +718,6 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3"
[[package]]
name = "const_fn"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935"
[[package]] [[package]]
name = "constant_time_eq" name = "constant_time_eq"
version = "0.1.5" version = "0.1.5"
@@ -728,12 +739,19 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
[[package]] [[package]]
name = "cookie" name = "cookie"
version = "0.15.1" version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5f1c7727e460397e56abc4bddc1d49e07a1ad78fc98eb2e1c8f032a58a2f80d" checksum = "94d4706de1b0fa5b132270cddffa8585166037822e260a944fe161acd137ca05"
dependencies = [ dependencies = [
"aes-gcm",
"base64",
"hkdf 0.12.3",
"hmac 0.12.1",
"percent-encoding", "percent-encoding",
"time 0.2.27", "rand 0.8.5",
"sha2 0.10.2",
"subtle 2.4.1",
"time 0.3.9",
"version_check", "version_check",
] ]
@@ -906,6 +924,7 @@ dependencies = [
"rand 0.7.3", "rand 0.7.3",
"thiserror", "thiserror",
"url", "url",
"validator-api-requests",
"validator-client", "validator-client",
] ]
@@ -1122,6 +1141,16 @@ dependencies = [
"cipher 0.4.3", "cipher 0.4.3",
] ]
[[package]]
name = "cupid"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bad352a84b567cc38a5854e3aa8ee903cb8519a25d0b799b739bafffd1f91a1"
dependencies = [
"gcc",
"rustc_version 0.2.3",
]
[[package]] [[package]]
name = "curve25519-dalek" name = "curve25519-dalek"
version = "3.2.0" version = "3.2.0"
@@ -1332,12 +1361,6 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "discard"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
[[package]] [[package]]
name = "dkg" name = "dkg"
version = "0.1.0" version = "0.1.0"
@@ -1354,7 +1377,7 @@ dependencies = [
"rand_core 0.6.3", "rand_core 0.6.3",
"serde", "serde",
"serde_derive", "serde_derive",
"sha2", "sha2 0.9.9",
"thiserror", "thiserror",
"zeroize", "zeroize",
] ]
@@ -1410,7 +1433,7 @@ dependencies = [
"rand 0.7.3", "rand 0.7.3",
"serde", "serde",
"serde_bytes", "serde_bytes",
"sha2", "sha2 0.9.9",
"zeroize", "zeroize",
] ]
@@ -1424,7 +1447,7 @@ dependencies = [
"hex", "hex",
"rand_core 0.6.3", "rand_core 0.6.3",
"serde", "serde",
"sha2", "sha2 0.9.9",
"thiserror", "thiserror",
"zeroize", "zeroize",
] ]
@@ -1641,9 +1664,9 @@ dependencies = [
[[package]] [[package]]
name = "fixed" name = "fixed"
version = "1.14.0" version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86d3f4dd10ddfcb0bd2b2efe9f18aff37ed48265fda3e20e5d53f046aba9d50a" checksum = "36a65312835c1097a0c926ff3702df965285fadc33d948b87397ff8961bad881"
dependencies = [ dependencies = [
"az", "az",
"bytemuck", "bytemuck",
@@ -1954,6 +1977,12 @@ dependencies = [
"tungstenite", "tungstenite",
] ]
[[package]]
name = "gcc"
version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
[[package]] [[package]]
name = "generator" name = "generator"
version = "0.7.0" version = "0.7.0"
@@ -2024,6 +2053,16 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "ghash"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99"
dependencies = [
"opaque-debug 0.3.0",
"polyval",
]
[[package]] [[package]]
name = "git2" name = "git2"
version = "0.14.2" version = "0.14.2"
@@ -2596,7 +2635,7 @@ dependencies = [
"ecdsa", "ecdsa",
"elliptic-curve", "elliptic-curve",
"sec1", "sec1",
"sha2", "sha2 0.9.9",
"sha3", "sha3",
] ]
@@ -3074,6 +3113,7 @@ dependencies = [
"rand 0.7.3", "rand 0.7.3",
"serde", "serde",
"sqlx", "sqlx",
"statistics-common",
"subtle-encoding", "subtle-encoding",
"thiserror", "thiserror",
"tokio", "tokio",
@@ -3081,6 +3121,7 @@ dependencies = [
"tokio-tungstenite", "tokio-tungstenite",
"tokio-util 0.7.3", "tokio-util 0.7.3",
"url", "url",
"validator-api-requests",
"validator-client", "validator-client",
"vergen", "vergen",
"version-checker", "version-checker",
@@ -3097,6 +3138,7 @@ dependencies = [
"colored", "colored",
"config", "config",
"crypto", "crypto",
"cupid",
"dirs", "dirs",
"dotenv", "dotenv",
"futures", "futures",
@@ -3115,6 +3157,7 @@ dependencies = [
"rocket", "rocket",
"serde", "serde",
"serial_test", "serial_test",
"sysinfo",
"task", "task",
"tokio", "tokio",
"tokio-util 0.7.3", "tokio-util 0.7.3",
@@ -3130,6 +3173,7 @@ dependencies = [
name = "nym-network-requester" name = "nym-network-requester"
version = "1.0.1" version = "1.0.1"
dependencies = [ dependencies = [
"async-trait",
"clap 2.34.0", "clap 2.34.0",
"dirs", "dirs",
"futures", "futures",
@@ -3146,7 +3190,7 @@ dependencies = [
"serde", "serde",
"socks5-requests", "socks5-requests",
"sqlx", "sqlx",
"statistics", "statistics-common",
"thiserror", "thiserror",
"tokio", "tokio",
"tokio-tungstenite", "tokio-tungstenite",
@@ -3163,7 +3207,7 @@ dependencies = [
"rocket", "rocket",
"serde", "serde",
"sqlx", "sqlx",
"statistics", "statistics-common",
"thiserror", "thiserror",
"tokio", "tokio",
"tokio-tungstenite", "tokio-tungstenite",
@@ -3321,7 +3365,7 @@ dependencies = [
"rand 0.8.5", "rand 0.8.5",
"serde", "serde",
"serde_derive", "serde_derive",
"sha2", "sha2 0.9.9",
"thiserror", "thiserror",
] ]
@@ -3852,6 +3896,18 @@ dependencies = [
"plotters-backend", "plotters-backend",
] ]
[[package]]
name = "polyval"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1"
dependencies = [
"cfg-if 1.0.0",
"cpufeatures",
"opaque-debug 0.3.0",
"universal-hash",
]
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.16" version = "0.2.16"
@@ -3915,12 +3971,6 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.37" version = "1.0.37"
@@ -4482,9 +4532,9 @@ dependencies = [
[[package]] [[package]]
name = "rocket" name = "rocket"
version = "0.5.0-rc.1" version = "0.5.0-rc.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a71c18c42a0eb15bf3816831caf0dad11e7966f2a41aaf486a701979c4dd1f2" checksum = "98ead083fce4a405feb349cf09abdf64471c6077f14e0ce59364aa90d4b99317"
dependencies = [ dependencies = [
"async-stream", "async-stream",
"async-trait", "async-trait",
@@ -4500,7 +4550,7 @@ dependencies = [
"memchr", "memchr",
"multer", "multer",
"num_cpus", "num_cpus",
"parking_lot 0.11.2", "parking_lot 0.12.0",
"pin-project-lite", "pin-project-lite",
"rand 0.8.5", "rand 0.8.5",
"ref-cast", "ref-cast",
@@ -4510,10 +4560,10 @@ dependencies = [
"serde_json", "serde_json",
"state", "state",
"tempfile", "tempfile",
"time 0.2.27", "time 0.3.9",
"tokio", "tokio",
"tokio-stream", "tokio-stream",
"tokio-util 0.6.9", "tokio-util 0.7.3",
"ubyte", "ubyte",
"version_check", "version_check",
"yansi", "yansi",
@@ -4521,9 +4571,9 @@ dependencies = [
[[package]] [[package]]
name = "rocket_codegen" name = "rocket_codegen"
version = "0.5.0-rc.1" version = "0.5.0-rc.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66f5fa462f7eb958bba8710c17c5d774bbbd59809fa76fb1957af7e545aea8bb" checksum = "d6aeb6bb9c61e9cd2c00d70ea267bf36f76a4cc615e5908b349c2f9d93999b47"
dependencies = [ dependencies = [
"devise", "devise",
"glob", "glob",
@@ -4552,19 +4602,18 @@ dependencies = [
[[package]] [[package]]
name = "rocket_http" name = "rocket_http"
version = "0.5.0-rc.1" version = "0.5.0-rc.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23c8b7d512d2fcac2316ebe590cde67573844b99e6cc9ee0f53375fa16e25ebd" checksum = "2ded65d127954de3c12471630bf4b81a2792f065984461e65b91d0fdaafc17a2"
dependencies = [ dependencies = [
"cookie", "cookie",
"either", "either",
"futures",
"http", "http",
"hyper", "hyper",
"indexmap", "indexmap",
"log", "log",
"memchr", "memchr",
"mime",
"parking_lot 0.11.2",
"pear", "pear",
"percent-encoding", "percent-encoding",
"pin-project-lite", "pin-project-lite",
@@ -4573,16 +4622,16 @@ dependencies = [
"smallvec 1.8.0", "smallvec 1.8.0",
"stable-pattern", "stable-pattern",
"state", "state",
"time 0.2.27", "time 0.3.9",
"tokio", "tokio",
"uncased", "uncased",
] ]
[[package]] [[package]]
name = "rocket_okapi" name = "rocket_okapi"
version = "0.8.0-rc.1" version = "0.8.0-rc.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0025aa04994af8cd8e1fcdd5a73579a395c941ae090ecb0a39b41cca7e237a20" checksum = "489f4f5b120762f7974e65b919fc462d0660fd8b839026d8985b850fe5acccb0"
dependencies = [ dependencies = [
"either", "either",
"log", "log",
@@ -4596,9 +4645,9 @@ dependencies = [
[[package]] [[package]]
name = "rocket_okapi_codegen" name = "rocket_okapi_codegen"
version = "0.8.0-rc.1" version = "0.8.0-rc.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc114779fc27afb78179233e966f469e47fd7a98dc15181cff2574cdddb65612" checksum = "54f94d1ffe41472e08463d7a2674f1db04dc4df745285e8369b33d3cfd6b0308"
dependencies = [ dependencies = [
"darling", "darling",
"proc-macro2", "proc-macro2",
@@ -4609,9 +4658,9 @@ dependencies = [
[[package]] [[package]]
name = "rocket_sync_db_pools" name = "rocket_sync_db_pools"
version = "0.1.0-rc.1" version = "0.1.0-rc.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38cfdfebd552d075c368e641c88a5cd6ce1c58c5c710548aeb777abb48830f4b" checksum = "5fa48b6ab25013e9812f1b0c592741900b3a2a83c0936292e0565c0ac842f558"
dependencies = [ dependencies = [
"r2d2", "r2d2",
"rocket", "rocket",
@@ -4622,9 +4671,9 @@ dependencies = [
[[package]] [[package]]
name = "rocket_sync_db_pools_codegen" name = "rocket_sync_db_pools_codegen"
version = "0.1.0-rc.1" version = "0.1.0-rc.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267808c094db5366e1d8925aaf9f2ce05ff9b3bd92cb18c7040a1fe219c2e25" checksum = "280ef2d232923e69cb93da156972eb5476a7cce5ba44843f6608f46a4abf7aab"
dependencies = [ dependencies = [
"devise", "devise",
"quote", "quote",
@@ -4721,9 +4770,9 @@ dependencies = [
[[package]] [[package]]
name = "schemars" name = "schemars"
version = "0.8.8" version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6b5a3c80cea1ab61f4260238409510e814e38b4b563c06044edf91e7dc070e3" checksum = "1847b767a3d62d95cbf3d8a9f0e421cf57a0d8aa4f411d4b16525afb0284d4ed"
dependencies = [ dependencies = [
"dyn-clone", "dyn-clone",
"indexmap", "indexmap",
@@ -4734,9 +4783,9 @@ dependencies = [
[[package]] [[package]]
name = "schemars_derive" name = "schemars_derive"
version = "0.8.8" version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41ae4dce13e8614c46ac3c38ef1c0d668b101df6ac39817aebdaa26642ddae9b" checksum = "af4d7e1b012cb3d9129567661a63755ea4b8a7386d339dc945ae187e403c6743"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -4915,9 +4964,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive_internals" name = "serde_derive_internals"
version = "0.25.0" version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -5028,21 +5077,6 @@ dependencies = [
"digest 0.10.3", "digest 0.10.3",
] ]
[[package]]
name = "sha1"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770"
dependencies = [
"sha1_smol",
]
[[package]]
name = "sha1_smol"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
[[package]] [[package]]
name = "sha2" name = "sha2"
version = "0.9.9" version = "0.9.9"
@@ -5056,6 +5090,17 @@ dependencies = [
"opaque-debug 0.3.0", "opaque-debug 0.3.0",
] ]
[[package]]
name = "sha2"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676"
dependencies = [
"cfg-if 1.0.0",
"cpufeatures",
"digest 0.10.3",
]
[[package]] [[package]]
name = "sha3" name = "sha3"
version = "0.9.1" version = "0.9.1"
@@ -5206,7 +5251,7 @@ dependencies = [
"log", "log",
"rand 0.7.3", "rand 0.7.3",
"rand_distr", "rand_distr",
"sha2", "sha2 0.9.9",
"subtle 2.4.1", "subtle 2.4.1",
] ]
@@ -5289,7 +5334,7 @@ dependencies = [
"paste", "paste",
"percent-encoding", "percent-encoding",
"rustls", "rustls",
"sha2", "sha2 0.9.9",
"smallvec 1.8.0", "smallvec 1.8.0",
"sqlformat", "sqlformat",
"sqlx-rt", "sqlx-rt",
@@ -5313,7 +5358,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"sha2", "sha2 0.9.9",
"sqlx-core", "sqlx-core",
"sqlx-rt", "sqlx-rt",
"syn", "syn",
@@ -5340,20 +5385,11 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "standback"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff"
dependencies = [
"version_check",
]
[[package]] [[package]]
name = "state" name = "state"
version = "0.5.2" version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87cf4f5369e6d3044b5e365c9690f451516ac8f0954084622b49ea3fde2f6de5" checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b"
dependencies = [ dependencies = [
"loom", "loom",
] ]
@@ -5365,64 +5401,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]] [[package]]
name = "statistics" name = "statistics-common"
version = "1.0.1" version = "1.0.1"
dependencies = [ dependencies = [
"async-trait",
"log",
"network-defaults",
"reqwest", "reqwest",
"serde", "serde",
"serde_json", "serde_json",
"sqlx",
"thiserror", "thiserror",
"tokio",
] ]
[[package]]
name = "stdweb"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5"
dependencies = [
"discard",
"rustc_version 0.2.3",
"stdweb-derive",
"stdweb-internal-macros",
"stdweb-internal-runtime",
"wasm-bindgen",
]
[[package]]
name = "stdweb-derive"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
dependencies = [
"proc-macro2",
"quote",
"serde",
"serde_derive",
"syn",
]
[[package]]
name = "stdweb-internal-macros"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11"
dependencies = [
"base-x",
"proc-macro2",
"quote",
"serde",
"serde_derive",
"serde_json",
"sha1",
"syn",
]
[[package]]
name = "stdweb-internal-runtime"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
[[package]] [[package]]
name = "stringprep" name = "stringprep"
version = "0.1.2" version = "0.1.2"
@@ -5511,6 +5503,21 @@ dependencies = [
"unicode-xid", "unicode-xid",
] ]
[[package]]
name = "sysinfo"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6a8e71535da31837213ac114531d31def75d7aebd133264e420a3451fa7f703"
dependencies = [
"cfg-if 1.0.0",
"core-foundation-sys",
"libc",
"ntapi",
"once_cell",
"rayon",
"winapi",
]
[[package]] [[package]]
name = "tap" name = "tap"
version = "1.0.1" version = "1.0.1"
@@ -5562,7 +5569,7 @@ dependencies = [
"serde_bytes", "serde_bytes",
"serde_json", "serde_json",
"serde_repr", "serde_repr",
"sha2", "sha2 0.9.9",
"signature", "signature",
"subtle 2.4.1", "subtle 2.4.1",
"subtle-encoding", "subtle-encoding",
@@ -5700,21 +5707,6 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "time"
version = "0.2.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242"
dependencies = [
"const_fn",
"libc",
"standback",
"stdweb",
"time-macros 0.1.1",
"version_check",
"winapi",
]
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.9" version = "0.3.9"
@@ -5725,17 +5717,7 @@ dependencies = [
"libc", "libc",
"num_threads", "num_threads",
"serde", "serde",
"time-macros 0.2.4", "time-macros",
]
[[package]]
name = "time-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1"
dependencies = [
"proc-macro-hack",
"time-macros-impl",
] ]
[[package]] [[package]]
@@ -5744,19 +5726,6 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792"
[[package]]
name = "time-macros-impl"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f"
dependencies = [
"proc-macro-hack",
"proc-macro2",
"quote",
"standback",
"syn",
]
[[package]] [[package]]
name = "tiny-keccak" name = "tiny-keccak"
version = "2.0.2" version = "2.0.2"
@@ -6242,6 +6211,16 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
[[package]]
name = "universal-hash"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05"
dependencies = [
"generic-array 0.14.5",
"subtle 2.4.1",
]
[[package]] [[package]]
name = "untrusted" name = "untrusted"
version = "0.7.1" version = "0.7.1"
@@ -6277,6 +6256,10 @@ checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
name = "validator-api-requests" name = "validator-api-requests"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bs58",
"coconut-interface",
"cosmrs",
"getset",
"mixnet-contract-common", "mixnet-contract-common",
"schemars", "schemars",
"serde", "serde",
@@ -6309,7 +6292,7 @@ dependencies = [
"reqwest", "reqwest",
"serde", "serde",
"serde_json", "serde_json",
"sha2", "sha2 0.9.9",
"thiserror", "thiserror",
"tokio", "tokio",
"ts-rs", "ts-rs",
@@ -6369,7 +6352,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]] [[package]]
name = "vesting-contract" name = "vesting-contract"
version = "1.0.0" version = "1.0.1"
dependencies = [ dependencies = [
"config", "config",
"cosmwasm-std", "cosmwasm-std",
+14
View File
@@ -1,9 +1,11 @@
test-all: test cargo-test-expensive
test: build clippy-all cargo-test wasm fmt test: build clippy-all cargo-test wasm fmt
no-clippy: build cargo-test wasm fmt no-clippy: build cargo-test wasm fmt
happy: fmt clippy-happy test happy: fmt clippy-happy test
clippy-all: clippy-all-main clippy-all-contracts clippy-all-wallet clippy-all-connect clippy-all: clippy-all-main clippy-all-contracts clippy-all-wallet clippy-all-connect
clippy-happy: clippy-happy-main clippy-happy-contracts clippy-happy-wallet clippy-happy-connect clippy-happy: clippy-happy-main clippy-happy-contracts clippy-happy-wallet clippy-happy-connect
cargo-test: test-main test-contracts test-wallet test-connect cargo-test: test-main test-contracts test-wallet test-connect
cargo-test-expensive: test-main-expensive test-contracts-expensive test-wallet-expensive test-connect-expensive
build: build-contracts build-wallet build-main build-connect build: build-contracts build-wallet build-main build-connect
fmt: fmt-main fmt-contracts fmt-wallet fmt-connect fmt: fmt-main fmt-contracts fmt-wallet fmt-connect
@@ -34,15 +36,27 @@ clippy-all-connect:
test-main: test-main:
cargo test --all-features --workspace cargo test --all-features --workspace
test-main-expensive:
cargo test --all-features --workspace -- --ignored
test-contracts: test-contracts:
cargo test --manifest-path contracts/Cargo.toml --all-features cargo test --manifest-path contracts/Cargo.toml --all-features
test-contracts-expensive:
cargo test --manifest-path contracts/Cargo.toml --all-features -- --ignored
test-wallet: test-wallet:
cargo test --manifest-path nym-wallet/Cargo.toml --all-features cargo test --manifest-path nym-wallet/Cargo.toml --all-features
test-wallet-expensive:
cargo test --manifest-path nym-wallet/Cargo.toml --all-features -- --ignored
test-connect: test-connect:
cargo test --manifest-path nym-connect/Cargo.toml --all-features cargo test --manifest-path nym-connect/Cargo.toml --all-features
test-connect-expensive:
cargo test --manifest-path nym-connect/Cargo.toml --all-features -- --ignored
build-main: build-main:
cargo build --workspace cargo build --workspace
+1 -1
View File
@@ -32,4 +32,4 @@ validator-client = { path = "../../common/client-libs/validator-client" }
tempfile = "3.1.0" tempfile = "3.1.0"
[features] [features]
coconut = ["gateway-client/coconut", "gateway-requests/coconut"] coconut = ["gateway-client/coconut", "gateway-requests/coconut"]
+23 -12
View File
@@ -114,12 +114,8 @@ impl<T: NymConfig> Config<T> {
self.client.disabled_credentials_mode = disabled_credentials_mode; self.client.disabled_credentials_mode = disabled_credentials_mode;
} }
pub fn with_gateway_endpoint<S: Into<String>>(&mut self, id: S, owner: S, listener: S) { pub fn with_gateway_endpoint(&mut self, gateway_endpoint: GatewayEndpoint) {
self.client.gateway_endpoint = GatewayEndpoint { self.client.gateway_endpoint = gateway_endpoint;
gateway_id: id.into(),
gateway_owner: owner.into(),
gateway_listener: listener.into(),
};
} }
pub fn with_gateway_id<S: Into<String>>(&mut self, id: S) { pub fn with_gateway_id<S: Into<String>>(&mut self, id: S) {
@@ -142,7 +138,7 @@ impl<T: NymConfig> Config<T> {
pub fn set_high_default_traffic_volume(&mut self) { pub fn set_high_default_traffic_volume(&mut self) {
self.debug.average_packet_delay = Duration::from_millis(10); self.debug.average_packet_delay = Duration::from_millis(10);
self.debug.loop_cover_traffic_average_delay = Duration::from_millis(2000000); // basically don't really send cover messages self.debug.loop_cover_traffic_average_delay = Duration::from_millis(2_000_000); // basically don't really send cover messages
self.debug.message_sending_average_delay = Duration::from_millis(4); // 250 "real" messages / s self.debug.message_sending_average_delay = Duration::from_millis(4); // 250 "real" messages / s
} }
@@ -206,6 +202,10 @@ impl<T: NymConfig> Config<T> {
self.client.gateway_endpoint.gateway_listener.clone() self.client.gateway_endpoint.gateway_listener.clone()
} }
pub fn get_gateway_endpoint(&self) -> &GatewayEndpoint {
&self.client.gateway_endpoint
}
pub fn get_database_path(&self) -> PathBuf { pub fn get_database_path(&self) -> PathBuf {
self.client.database_path.clone() self.client.database_path.clone()
} }
@@ -272,17 +272,28 @@ impl<T: NymConfig> Default for Config<T> {
} }
} }
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)] #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
struct GatewayEndpoint { pub struct GatewayEndpoint {
/// gateway_id specifies ID of the gateway to which the client should send messages. /// gateway_id specifies ID of the gateway to which the client should send messages.
/// If initially omitted, a random gateway will be chosen from the available topology. /// If initially omitted, a random gateway will be chosen from the available topology.
gateway_id: String, pub gateway_id: String,
/// Address of the gateway owner to which the client should send messages. /// Address of the gateway owner to which the client should send messages.
gateway_owner: String, pub gateway_owner: String,
/// Address of the gateway listener to which all client requests should be sent. /// Address of the gateway listener to which all client requests should be sent.
gateway_listener: String, pub gateway_listener: String,
}
impl From<topology::gateway::Node> for GatewayEndpoint {
fn from(node: topology::gateway::Node) -> GatewayEndpoint {
let gateway_listener = node.clients_address();
GatewayEndpoint {
gateway_id: node.identity_key.to_base58_string(),
gateway_owner: node.owner,
gateway_listener,
}
}
} }
#[derive(Debug, Deserialize, PartialEq, Serialize)] #[derive(Debug, Deserialize, PartialEq, Serialize)]
+137
View File
@@ -0,0 +1,137 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
//! Collection of initialization steps used by client implementations
use std::{sync::Arc, time::Duration};
use config::NymConfig;
use crypto::asymmetric::{encryption, identity};
use gateway_client::GatewayClient;
use gateway_requests::registration::handshake::SharedKeys;
use nymsphinx::addressing::clients::Recipient;
use nymsphinx::addressing::nodes::NodeIdentity;
use rand::rngs::OsRng;
use rand::seq::SliceRandom;
use rand::thread_rng;
use topology::{filter::VersionFilterable, gateway};
use url::Url;
use crate::{
client::key_manager::KeyManager,
config::{persistence::key_pathfinder::ClientKeyPathfinder, Config},
};
pub async fn query_gateway_details(
validator_servers: Vec<Url>,
chosen_gateway_id: Option<&str>,
) -> gateway::Node {
let validator_api = validator_servers
.choose(&mut thread_rng())
.expect("The list of validator apis is empty");
let validator_client = validator_client::ApiClient::new(validator_api.clone());
log::trace!("Fetching list of gateways from: {}", validator_api);
let gateways = validator_client.get_cached_gateways().await.unwrap();
let valid_gateways = gateways
.into_iter()
.filter_map(|gateway| gateway.try_into().ok())
.collect::<Vec<gateway::Node>>();
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
// if we have chosen particular gateway - use it, otherwise choose a random one.
// (remember that in active topology all gateways have at least 100 reputation so should
// be working correctly)
if let Some(gateway_id) = chosen_gateway_id {
filtered_gateways
.iter()
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
.expect(&*format!("no gateway with id {} exists!", gateway_id))
.clone()
} else {
filtered_gateways
.choose(&mut rand::thread_rng())
.expect("there are no gateways on the network!")
.clone()
}
}
pub async fn register_with_gateway_and_store_keys<T>(
gateway_details: gateway::Node,
config: &Config<T>,
) where
T: NymConfig,
{
let mut rng = OsRng;
let mut key_manager = KeyManager::new(&mut rng);
let shared_keys = register_with_gateway(&gateway_details, key_manager.identity_keypair()).await;
key_manager.insert_gateway_shared_key(shared_keys);
let pathfinder = ClientKeyPathfinder::new_from_config(config);
key_manager
.store_keys(&pathfinder)
.expect("Failed to generated keys");
}
async fn register_with_gateway(
gateway: &gateway::Node,
our_identity: Arc<identity::KeyPair>,
) -> Arc<SharedKeys> {
let timeout = Duration::from_millis(1500);
let mut gateway_client = GatewayClient::new_init(
gateway.clients_address(),
gateway.identity_key,
gateway.owner.clone(),
our_identity.clone(),
timeout,
);
gateway_client
.establish_connection()
.await
.expect("failed to establish connection with the gateway!");
gateway_client
.perform_initial_authentication()
.await
.expect("failed to register with the gateway!")
}
pub fn show_address<T>(config: &Config<T>)
where
T: config::NymConfig,
{
fn load_identity_keys(pathfinder: &ClientKeyPathfinder) -> identity::KeyPair {
let identity_keypair: identity::KeyPair =
pemstore::load_keypair(&pemstore::KeyPairPath::new(
pathfinder.private_identity_key().to_owned(),
pathfinder.public_identity_key().to_owned(),
))
.expect("Failed to read stored identity key files");
identity_keypair
}
fn load_sphinx_keys(pathfinder: &ClientKeyPathfinder) -> encryption::KeyPair {
let sphinx_keypair: encryption::KeyPair =
pemstore::load_keypair(&pemstore::KeyPairPath::new(
pathfinder.private_encryption_key().to_owned(),
pathfinder.public_encryption_key().to_owned(),
))
.expect("Failed to read stored sphinx key files");
sphinx_keypair
}
let pathfinder = ClientKeyPathfinder::new_from_config(config);
let identity_keypair = load_identity_keys(&pathfinder);
let sphinx_keypair = load_sphinx_keys(&pathfinder);
let client_recipient = Recipient::new(
*identity_keypair.public_key(),
*sphinx_keypair.public_key(),
// TODO: below only works under assumption that gateway address == gateway id
// (which currently is true)
NodeIdentity::from_base58_string(config.get_gateway_id()).unwrap(),
);
println!("\nThe address of this client is: {}", client_recipient);
}
+1
View File
@@ -1,2 +1,3 @@
pub mod client; pub mod client;
pub mod config; pub mod config;
pub mod init;
+1 -1
View File
@@ -26,4 +26,4 @@ pemstore = { path = "../../common/pemstore" }
validator-client = { path = "../../common/client-libs/validator-client", features = ["nymd-client"] } validator-client = { path = "../../common/client-libs/validator-client", features = ["nymd-client"] }
[features] [features]
coconut = ["credentials/coconut"] coconut = ["credentials/coconut"]
+9 -9
View File
@@ -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 bip39::Mnemonic;
use std::str::FromStr;
use url::Url;
use crate::error::Result; use crate::error::Result;
use crate::{MNEMONIC, NYMD_URL}; use crate::{MNEMONIC, NYMD_URL};
use bip39::Mnemonic;
use network_defaults::{DEFAULT_NETWORK, DENOM, VOUCHER_INFO}; use network_defaults::{DEFAULT_NETWORK, MIX_DENOM, VOUCHER_INFO};
use std::str::FromStr;
use url::Url;
use validator_client::nymd;
use validator_client::nymd::traits::CoconutBandwidthSigningClient; use validator_client::nymd::traits::CoconutBandwidthSigningClient;
use validator_client::nymd::{Coin, Fee, NymdClient, SigningNymdClient}; use validator_client::nymd::{Coin, Fee, NymdClient, SigningNymdClient};
@@ -20,9 +19,10 @@ impl Client {
pub fn new() -> Self { pub fn new() -> Self {
let nymd_url = Url::from_str(NYMD_URL).unwrap(); let nymd_url = Url::from_str(NYMD_URL).unwrap();
let mnemonic = Mnemonic::from_str(MNEMONIC).unwrap(); let mnemonic = Mnemonic::from_str(MNEMONIC).unwrap();
let config = nymd::Config::try_from_nym_network_details(&DEFAULT_NETWORK.details())
.expect("failed to construct valid validator client config with the provided network");
let nymd_client = let nymd_client =
NymdClient::connect_with_mnemonic(DEFAULT_NETWORK, nymd_url.as_ref(), mnemonic, None) NymdClient::connect_with_mnemonic(config, nymd_url.as_ref(), mnemonic, None).unwrap();
.unwrap();
Client { nymd_client } Client { nymd_client }
} }
@@ -34,7 +34,7 @@ impl Client {
encryption_key: String, encryption_key: String,
fee: Option<Fee>, fee: Option<Fee>,
) -> Result<String> { ) -> Result<String> {
let amount = Coin::new(amount as u128, DENOM.to_string()); let amount = Coin::new(amount as u128, MIX_DENOM.base.to_string());
Ok(self Ok(self
.nymd_client .nymd_client
.deposit( .deposit(
+1 -1
View File
@@ -55,4 +55,4 @@ eth = []
serde_json = "1.0" # for the "textsend" example serde_json = "1.0" # for the "textsend" example
[build-dependencies] [build-dependencies]
vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] } vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] }
+83 -153
View File
@@ -2,22 +2,8 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use clap::{App, Arg, ArgMatches}; use clap::{App, Arg, ArgMatches};
use client_core::client::key_manager::KeyManager; use client_core::config::GatewayEndpoint;
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
use config::NymConfig; use config::NymConfig;
use crypto::asymmetric::{encryption, identity};
use gateway_client::GatewayClient;
use gateway_requests::registration::handshake::SharedKeys;
use nymsphinx::addressing::clients::Recipient;
use nymsphinx::addressing::nodes::NodeIdentity;
use rand::rngs::OsRng;
use rand::seq::SliceRandom;
use rand::thread_rng;
use std::convert::TryInto;
use std::sync::Arc;
use std::time::Duration;
use topology::{filter::VersionFilterable, gateway};
use url::Url;
use crate::client::config::Config; use crate::client::config::Config;
use crate::commands::override_config; use crate::commands::override_config;
@@ -42,6 +28,11 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
.help("Id of the gateway we are going to connect to.") .help("Id of the gateway we are going to connect to.")
.takes_value(true) .takes_value(true)
) )
.arg(Arg::with_name("force-register-gateway")
.long("force-register-gateway")
.help("Force register gateway. WARNING: this will overwrite any existing keys for the given id, potentially causing loss of access.")
.takes_value(false)
)
.arg(Arg::with_name("validators") .arg(Arg::with_name("validators")
.long("validators") .long("validators")
.help("Comma separated list of rest endpoints of the validators") .help("Comma separated list of rest endpoints of the validators")
@@ -88,161 +79,47 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
app app
} }
async fn register_with_gateway(
gateway: &gateway::Node,
our_identity: Arc<identity::KeyPair>,
) -> Arc<SharedKeys> {
let timeout = Duration::from_millis(1500);
let mut gateway_client = GatewayClient::new_init(
gateway.clients_address(),
gateway.identity_key,
gateway.owner.clone(),
our_identity.clone(),
timeout,
);
gateway_client
.establish_connection()
.await
.expect("failed to establish connection with the gateway!");
gateway_client
.perform_initial_authentication()
.await
.expect("failed to register with the gateway!")
}
async fn gateway_details(
validator_servers: Vec<Url>,
chosen_gateway_id: Option<&str>,
) -> gateway::Node {
let validator_api = validator_servers
.choose(&mut thread_rng())
.expect("The list of validator apis is empty");
let validator_client = validator_client::ApiClient::new(validator_api.clone());
log::trace!("Fetching list of gateways from: {}", validator_api);
let gateways = validator_client.get_cached_gateways().await.unwrap();
let valid_gateways = gateways
.into_iter()
.filter_map(|gateway| gateway.try_into().ok())
.collect::<Vec<gateway::Node>>();
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
// if we have chosen particular gateway - use it, otherwise choose a random one.
// (remember that in active topology all gateways have at least 100 reputation so should
// be working correctly)
if let Some(gateway_id) = chosen_gateway_id {
filtered_gateways
.iter()
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
.expect(&*format!("no gateway with id {} exists!", gateway_id))
.clone()
} else {
filtered_gateways
.choose(&mut rand::thread_rng())
.expect("there are no gateways on the network!")
.clone()
}
}
fn show_address(config: &Config) {
fn load_identity_keys(pathfinder: &ClientKeyPathfinder) -> identity::KeyPair {
let identity_keypair: identity::KeyPair =
pemstore::load_keypair(&pemstore::KeyPairPath::new(
pathfinder.private_identity_key().to_owned(),
pathfinder.public_identity_key().to_owned(),
))
.expect("Failed to read stored identity key files");
identity_keypair
}
fn load_sphinx_keys(pathfinder: &ClientKeyPathfinder) -> encryption::KeyPair {
let sphinx_keypair: encryption::KeyPair =
pemstore::load_keypair(&pemstore::KeyPairPath::new(
pathfinder.private_encryption_key().to_owned(),
pathfinder.public_encryption_key().to_owned(),
))
.expect("Failed to read stored sphinx key files");
sphinx_keypair
}
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
let identity_keypair = load_identity_keys(&pathfinder);
let sphinx_keypair = load_sphinx_keys(&pathfinder);
let client_recipient = Recipient::new(
*identity_keypair.public_key(),
*sphinx_keypair.public_key(),
// TODO: below only works under assumption that gateway address == gateway id
// (which currently is true)
NodeIdentity::from_base58_string(config.get_base().get_gateway_id()).unwrap(),
);
println!("\nThe address of this client is: {}", client_recipient);
}
pub async fn execute(matches: ArgMatches<'static>) { pub async fn execute(matches: ArgMatches<'static>) {
println!("Initialising client..."); println!("Initialising client...");
let id = matches.value_of("id").unwrap(); // required for now let id = matches.value_of("id").unwrap(); // required for now
let already_init = if Config::default_config_file_path(Some(id)).exists() { let already_init = Config::default_config_file_path(Some(id)).exists();
if matches.is_present("gateway") { if already_init {
panic!("At the moment, gateway information can't be overwritten. If you want to point to a different gateway, client {}'s directory will need to be manually removed", id); println!(
} "Client \"{}\" was already initialised before! \
println!("Client \"{}\" was already initialised before! Config information will be overwritten (but keys will be kept)!", id); Config information will be overwritten (but keys will be kept)!",
true id
} else { );
false }
};
// Usually you only register with the gateway on the first init, however you can force
// re-registering if wanted.
let user_wants_force_register = matches.is_present("force-register-gateway");
// If the client was already initialized, don't generate new keys and don't re-register with
// the gateway (because this would create a new shared key).
// Unless the user really wants to.
let register_gateway = !already_init || user_wants_force_register;
// Attempt to use a user-provided gateway, if possible
let user_chosen_gateway_id = matches.value_of("gateway");
let mut config = Config::new(id); let mut config = Config::new(id);
let mut rng = OsRng;
// TODO: ideally that should be the last thing that's being done to config.
// However, we are later further overriding it with gateway id
config = override_config(config, &matches); config = override_config(config, &matches);
if matches.is_present("fastmode") { if matches.is_present("fastmode") {
config.get_base_mut().set_high_default_traffic_volume(); config.get_base_mut().set_high_default_traffic_volume();
} }
// if client was already initialised, don't generate new keys, not re-register with gateway let gateway = setup_gateway(id, register_gateway, user_chosen_gateway_id, &config).await;
// (because this would create new shared key) config.get_base_mut().with_gateway_endpoint(gateway);
if !already_init {
// create identity, encryption and ack keys.
let mut key_manager = KeyManager::new(&mut rng);
let chosen_gateway_id = matches.value_of("gateway");
log::trace!("Chosen gateway: {:?}", chosen_gateway_id);
let gateway_details = gateway_details(
config.get_base().get_validator_api_endpoints(),
chosen_gateway_id,
)
.await;
log::trace!("Used gateway: {}", gateway_details);
let shared_keys =
register_with_gateway(&gateway_details, key_manager.identity_keypair()).await;
config.get_base_mut().with_gateway_endpoint(
gateway_details.identity_key.to_base58_string(),
gateway_details.owner.clone(),
gateway_details.clients_address(),
);
key_manager.insert_gateway_shared_key(shared_keys);
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
key_manager
.store_keys(&pathfinder)
.expect("Failed to generated keys");
println!("Saved all generated keys");
}
let config_save_location = config.get_config_file_save_location(); let config_save_location = config.get_config_file_save_location();
config config
.save_to_file(None) .save_to_file(None)
.expect("Failed to save the config file"); .expect("Failed to save the config file");
println!("Saved configuration file to {:?}", config_save_location); println!("Saved configuration file to {:?}", config_save_location);
println!("Using gateway: {}", config.get_base().get_gateway_id()); println!("Using gateway: {}", config.get_base().get_gateway_id());
log::debug!("Gateway id: {}", config.get_base().get_gateway_id()); log::debug!("Gateway id: {}", config.get_base().get_gateway_id());
@@ -253,5 +130,58 @@ pub async fn execute(matches: ArgMatches<'static>) {
); );
println!("Client configuration completed."); println!("Client configuration completed.");
show_address(&config); client_core::init::show_address(config.get_base());
}
async fn setup_gateway(
id: &str,
register: bool,
user_chosen_gateway_id: Option<&str>,
config: &Config,
) -> GatewayEndpoint {
if register {
// Get the gateway details by querying the validator-api. Either pick one at random or use
// the chosen one if it's among the available ones.
println!("Configuring gateway");
let gateway = client_core::init::query_gateway_details(
config.get_base().get_validator_api_endpoints(),
user_chosen_gateway_id,
)
.await;
log::debug!("Querying gateway gives: {}", gateway);
// Registering with gateway by setting up and writing shared keys to disk
log::trace!("Registering gateway");
client_core::init::register_with_gateway_and_store_keys(gateway.clone(), config.get_base())
.await;
println!("Saved all generated keys");
gateway.into()
} else if user_chosen_gateway_id.is_some() {
// Just set the config, don't register or create any keys
// This assumes that the user knows what they are doing, and that the existing keys are
// valid for the gateway being used
println!("Using gateway provided by user, keeping existing keys");
let gateway = client_core::init::query_gateway_details(
config.get_base().get_validator_api_endpoints(),
user_chosen_gateway_id,
)
.await;
log::debug!("Querying gateway gives: {}", gateway);
gateway.into()
} else {
println!("Not registering gateway, will reuse existing config and keys");
match Config::load_from_file(Some(id)) {
Ok(existing_config) => existing_config.get_base().get_gateway_endpoint().clone(),
Err(err) => {
panic!(
"Unable to configure gateway: {err}. \n
Seems like the client was already initialized but it was not possible to read \
the existing configuration file. \n
CAUTION: Consider backing up your gateway keys and try force gateway registration, or \
removing the existing configuration and starting over."
)
}
}
}
} }
+1 -1
View File
@@ -10,4 +10,4 @@ edition = "2021"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
nymsphinx = { path = "../../../common/nymsphinx" } nymsphinx = { path = "../../../common/nymsphinx" }
+1 -1
View File
@@ -47,4 +47,4 @@ coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gate
eth = [] eth = []
[build-dependencies] [build-dependencies]
vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] } vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] }
+92 -154
View File
@@ -2,20 +2,8 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use clap::{App, Arg, ArgMatches}; use clap::{App, Arg, ArgMatches};
use client_core::client::key_manager::KeyManager; use client_core::config::GatewayEndpoint;
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
use config::NymConfig; use config::NymConfig;
use crypto::asymmetric::{encryption, identity};
use gateway_client::GatewayClient;
use gateway_requests::registration::handshake::SharedKeys;
use nymsphinx::addressing::clients::Recipient;
use nymsphinx::addressing::nodes::NodeIdentity;
use rand::{prelude::SliceRandom, rngs::OsRng, thread_rng};
use std::convert::TryInto;
use std::sync::Arc;
use std::time::Duration;
use topology::{filter::VersionFilterable, gateway};
use url::Url;
use crate::client::config::Config; use crate::client::config::Config;
use crate::commands::override_config; use crate::commands::override_config;
@@ -46,6 +34,11 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
.help("Id of the gateway we are going to connect to.") .help("Id of the gateway we are going to connect to.")
.takes_value(true) .takes_value(true)
) )
.arg(Arg::with_name("force-register-gateway")
.long("force-register-gateway")
.help("Force register gateway. WARNING: this will overwrite any existing keys for the given id, potentially causing loss of access.")
.takes_value(false)
)
.arg(Arg::with_name("validators") .arg(Arg::with_name("validators")
.long("validators") .long("validators")
.help("Comma separated list of rest endpoints of the validators") .help("Comma separated list of rest endpoints of the validators")
@@ -88,165 +81,110 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
app app
} }
// TODO: make this private again after refactoring the config setup
pub async fn register_with_gateway(
gateway: &gateway::Node,
our_identity: Arc<identity::KeyPair>,
) -> Arc<SharedKeys> {
let timeout = Duration::from_millis(1500);
let mut gateway_client = GatewayClient::new_init(
gateway.clients_address(),
gateway.identity_key,
gateway.owner.clone(),
our_identity.clone(),
timeout,
);
gateway_client
.establish_connection()
.await
.expect("failed to establish connection with the gateway!");
gateway_client
.perform_initial_authentication()
.await
.expect("failed to register with the gateway!")
}
// TODO: make this private again after refactoring the config setup
pub async fn gateway_details(
validator_servers: Vec<Url>,
chosen_gateway_id: Option<&str>,
) -> gateway::Node {
let validator_api = validator_servers
.choose(&mut thread_rng())
.expect("The list of validator apis is empty");
let validator_client = validator_client::ApiClient::new(validator_api.clone());
let gateways = validator_client.get_cached_gateways().await.unwrap();
let valid_gateways = gateways
.into_iter()
.filter_map(|gateway| gateway.try_into().ok())
.collect::<Vec<gateway::Node>>();
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
// if we have chosen particular gateway - use it, otherwise choose a random one.
// (remember that in active topology all gateways have at least 100 reputation so should
// be working correctly)
if let Some(gateway_id) = chosen_gateway_id {
filtered_gateways
.iter()
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
.expect(&*format!("no gateway with id {} exists!", gateway_id))
.clone()
} else {
filtered_gateways
.choose(&mut rand::thread_rng())
.expect("there are no gateways on the network!")
.clone()
}
}
// TODO: make this private again after refactoring the config setup
pub fn show_address(config: &Config) {
fn load_identity_keys(pathfinder: &ClientKeyPathfinder) -> identity::KeyPair {
let identity_keypair: identity::KeyPair =
pemstore::load_keypair(&pemstore::KeyPairPath::new(
pathfinder.private_identity_key().to_owned(),
pathfinder.public_identity_key().to_owned(),
))
.expect("Failed to read stored identity key files");
identity_keypair
}
fn load_sphinx_keys(pathfinder: &ClientKeyPathfinder) -> encryption::KeyPair {
let sphinx_keypair: encryption::KeyPair =
pemstore::load_keypair(&pemstore::KeyPairPath::new(
pathfinder.private_encryption_key().to_owned(),
pathfinder.public_encryption_key().to_owned(),
))
.expect("Failed to read stored sphinx key files");
sphinx_keypair
}
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
let identity_keypair = load_identity_keys(&pathfinder);
let sphinx_keypair = load_sphinx_keys(&pathfinder);
let client_recipient = Recipient::new(
*identity_keypair.public_key(),
*sphinx_keypair.public_key(),
// TODO: below only works under assumption that gateway address == gateway id
// (which currently is true)
NodeIdentity::from_base58_string(config.get_base().get_gateway_id()).unwrap(),
);
println!("\nThe address of this client is: {}", client_recipient);
}
pub async fn execute(matches: ArgMatches<'static>) { pub async fn execute(matches: ArgMatches<'static>) {
println!("Initialising client..."); println!("Initialising client...");
let id = matches.value_of("id").unwrap(); // required for now let id = matches.value_of("id").unwrap(); // required for now
let provider_address = matches.value_of("provider").unwrap(); let provider_address = matches.value_of("provider").unwrap();
let already_init = if Config::default_config_file_path(Some(id)).exists() { let already_init = Config::default_config_file_path(Some(id)).exists();
if matches.is_present("gateway") { if already_init {
panic!("At the moment, gateway information can't be overwritten. If you want to point to a different gateway, client {}'s directory will need to be manually removed", id); println!(
} "SOCKS5 client \"{}\" was already initialised before! \
println!("Socks5 client \"{}\" was already initialised before! Config information will be overwritten (but keys will be kept)!", id); Config information will be overwritten (but keys will be kept)!",
true id
} else { );
false }
};
// Usually you only register with the gateway on the first init, however you can force
// re-registering if wanted.
let user_wants_force_register = matches.is_present("force-register-gateway");
// If the client was already initialized, don't generate new keys and don't re-register with
// the gateway (because this would create a new shared key).
// Unless the user really wants to.
let register_gateway = !already_init || user_wants_force_register;
// Attempt to use a user-provided gateway, if possible
let user_chosen_gateway_id = matches.value_of("gateway");
let mut config = Config::new(id, provider_address); let mut config = Config::new(id, provider_address);
let mut rng = OsRng;
// TODO: ideally that should be the last thing that's being done to config.
// However, we are later further overriding it with gateway id
config = override_config(config, &matches); config = override_config(config, &matches);
if matches.is_present("fastmode") { if matches.is_present("fastmode") {
config.get_base_mut().set_high_default_traffic_volume(); config.get_base_mut().set_high_default_traffic_volume();
} }
// if client was already initialised, don't generate new keys, not re-register with gateway let gateway = setup_gateway(id, register_gateway, user_chosen_gateway_id, &config).await;
// (because this would create new shared key) config.get_base_mut().with_gateway_endpoint(gateway);
if !already_init {
// create identity, encryption and ack keys.
let mut key_manager = KeyManager::new(&mut rng);
let chosen_gateway_id = matches.value_of("gateway");
let gateway_details = gateway_details(
config.get_base().get_validator_api_endpoints(),
chosen_gateway_id,
)
.await;
let shared_keys =
register_with_gateway(&gateway_details, key_manager.identity_keypair()).await;
config.get_base_mut().with_gateway_endpoint(
gateway_details.identity_key.to_base58_string(),
gateway_details.owner.clone(),
gateway_details.clients_address(),
);
key_manager.insert_gateway_shared_key(shared_keys);
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
key_manager
.store_keys(&pathfinder)
.expect("Failed to generated keys");
println!("Saved all generated keys");
}
let config_save_location = config.get_config_file_save_location(); let config_save_location = config.get_config_file_save_location();
config config
.save_to_file(None) .save_to_file(None)
.expect("Failed to save the config file"); .expect("Failed to save the config file");
println!("Saved configuration file to {:?}", config_save_location);
println!("Using gateway: {}", config.get_base().get_gateway_id(),);
println!("Client configuration completed.\n\n\n");
show_address(&config); println!("Saved configuration file to {:?}", config_save_location);
println!("Using gateway: {}", config.get_base().get_gateway_id());
log::debug!("Gateway id: {}", config.get_base().get_gateway_id());
log::debug!("Gateway owner: {}", config.get_base().get_gateway_owner());
log::debug!(
"Gateway listener: {}",
config.get_base().get_gateway_listener()
);
println!("Client configuration completed.");
client_core::init::show_address(config.get_base());
}
async fn setup_gateway(
id: &str,
register: bool,
user_chosen_gateway_id: Option<&str>,
config: &Config,
) -> GatewayEndpoint {
if register {
// Get the gateway details by querying the validator-api. Either pick one at random or use
// the chosen one if it's among the available ones.
println!("Configuring gateway");
let gateway = client_core::init::query_gateway_details(
config.get_base().get_validator_api_endpoints(),
user_chosen_gateway_id,
)
.await;
log::debug!("Querying gateway gives: {}", gateway);
// Registering with gateway by setting up and writing shared keys to disk
log::trace!("Registering gateway");
client_core::init::register_with_gateway_and_store_keys(gateway.clone(), config.get_base())
.await;
println!("Saved all generated keys");
gateway.into()
} else if user_chosen_gateway_id.is_some() {
// Just set the config, don't register or create any keys
// This assumes that the user knows what they are doing, and that the existing keys are
// valid for the gateway being used
println!("Using gateway provided by user, keeping existing keys");
let gateway = client_core::init::query_gateway_details(
config.get_base().get_validator_api_endpoints(),
user_chosen_gateway_id,
)
.await;
log::debug!("Querying gateway gives: {}", gateway);
gateway.into()
} else {
println!("Not registering gateway, will reuse existing config and keys");
match Config::load_from_file(Some(id)) {
Ok(existing_config) => existing_config.get_base().get_gateway_endpoint().clone(),
Err(err) => {
panic!(
"Unable to configure gateway: {err}. \n
Seems like the client was already initialized but it was not possible to read \
the existing configuration file. \n
CAUTION: Consider backing up your gateway keys and try force gateway registration, or \
removing the existing configuration and starting over."
)
}
}
}
} }
+5 -5
View File
@@ -34,16 +34,16 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
.help("Address of the socks5 provider to send messages to.") .help("Address of the socks5 provider to send messages to.")
.takes_value(true) .takes_value(true)
) )
.arg(Arg::with_name("validators")
.long("validators")
.help("Comma separated list of rest endpoints of the validators")
.takes_value(true),
)
.arg(Arg::with_name("gateway") .arg(Arg::with_name("gateway")
.long("gateway") .long("gateway")
.help("Id of the gateway we want to connect to. If overridden, it is user's responsibility to ensure prior registration happened") .help("Id of the gateway we want to connect to. If overridden, it is user's responsibility to ensure prior registration happened")
.takes_value(true) .takes_value(true)
) )
.arg(Arg::with_name("validators")
.long("validators")
.help("Comma separated list of rest endpoints of the validators")
.takes_value(true),
)
.arg(Arg::with_name("port") .arg(Arg::with_name("port")
.short("p") .short("p")
.long("port") .long("port")
+2 -1
View File
@@ -24,7 +24,8 @@
}, },
"../pkg": { "../pkg": {
"name": "@nymproject/nym-client-wasm", "name": "@nymproject/nym-client-wasm",
"version": "0.0.1" "version": "1.0.1",
"license": "Apache-2.0"
}, },
"node_modules/@discoveryjs/json-ext": { "node_modules/@discoveryjs/json-ext": {
"version": "0.5.7", "version": "0.5.7",
+1 -1
View File
@@ -74,4 +74,4 @@ features = ["js"]
[features] [features]
coconut = ["gateway-requests/coconut", "coconut-interface", "validator-client", "credentials/coconut"] coconut = ["gateway-requests/coconut", "coconut-interface", "validator-client", "credentials/coconut"]
wasm = ["web3/wasm", "web3/http", "web3/signing"] wasm = ["web3/wasm", "web3/http", "web3/signing"]
default = ["web3/default"] default = ["web3/default"]
@@ -1,47 +1,49 @@
// 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 crate::error::GatewayClientError;
use std::str::FromStr;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use crate::wasm_storage::{Storage, StorageError}; use crate::wasm_storage::Storage;
#[cfg(feature = "coconut")]
use coconut_interface::Base58;
#[cfg(feature = "coconut")]
#[cfg(not(target_arch = "wasm32"))]
use credential_storage::error::StorageError;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use credential_storage::storage::Storage; use credential_storage::storage::Storage;
#[cfg(all(target_arch = "wasm32", feature = "coconut"))]
use crate::wasm_storage::StorageError;
#[cfg(all(not(target_arch = "wasm32"), feature = "coconut"))]
use credential_storage::error::StorageError;
#[cfg(feature = "coconut")] #[cfg(feature = "coconut")]
use credentials::coconut::{ use {
bandwidth::prepare_for_spending, utils::obtain_aggregate_verification_key, coconut_interface::Base58,
}; credentials::coconut::{
#[cfg(not(feature = "coconut"))] bandwidth::prepare_for_spending, utils::obtain_aggregate_verification_key,
use credentials::token::bandwidth::TokenCredential; },
#[cfg(not(feature = "coconut"))]
use crypto::asymmetric::identity;
#[cfg(not(feature = "coconut"))]
use network_defaults::{
eth_contract::ETH_ERC20_JSON_ABI, eth_contract::ETH_JSON_ABI, BANDWIDTH_VALUE,
ETH_BURN_FUNCTION_NAME, ETH_CONTRACT_ADDRESS, ETH_ERC20_APPROVE_FUNCTION_NAME,
ETH_ERC20_CONTRACT_ADDRESS, ETH_MIN_BLOCK_DEPTH, TOKENS_TO_BURN, UTOKENS_TO_BURN,
};
#[cfg(not(feature = "coconut"))]
use pemstore::traits::PemStorableKeyPair;
#[cfg(not(feature = "coconut"))]
use rand::rngs::OsRng;
#[cfg(not(feature = "coconut"))]
use secp256k1::SecretKey;
use std::str::FromStr;
#[cfg(not(feature = "coconut"))]
use web3::{
contract::{Contract, Options},
ethabi::Token,
signing::{Key, SecretKeyRef},
transports::Http,
types::{Address, U256, U64},
Web3,
}; };
use crate::error::GatewayClientError; #[cfg(not(feature = "coconut"))]
use {
credentials::token::bandwidth::TokenCredential,
crypto::asymmetric::identity,
network_defaults::{
eth_contract::ETH_ERC20_JSON_ABI, eth_contract::ETH_JSON_ABI, BANDWIDTH_VALUE,
ETH_BURN_FUNCTION_NAME, ETH_CONTRACT_ADDRESS, ETH_ERC20_APPROVE_FUNCTION_NAME,
ETH_ERC20_CONTRACT_ADDRESS, ETH_MIN_BLOCK_DEPTH, TOKENS_TO_BURN, UTOKENS_TO_BURN,
},
pemstore::traits::PemStorableKeyPair,
rand::rngs::OsRng,
secp256k1::SecretKey,
web3::{
contract::{Contract, Options},
ethabi::Token,
signing::{Key, SecretKeyRef},
transports::Http,
types::{Address, U256, U64},
Web3,
},
};
#[cfg(not(feature = "coconut"))] #[cfg(not(feature = "coconut"))]
pub fn eth_contract(web3: Web3<Http>) -> Contract<Http> { pub fn eth_contract(web3: Web3<Http>) -> Contract<Http> {
@@ -27,7 +27,7 @@ futures = "0.3"
coconut-interface = { path = "../../coconut-interface" } coconut-interface = { path = "../../coconut-interface" }
network-defaults = { path = "../../network-defaults" } network-defaults = { path = "../../network-defaults" }
validator-api-requests = { path = "../../../validator-api/validator-api-requests" } validator-api-requests = { path = "../../../validator-api/validator-api-requests", features = ["coconut"] }
# required for nymd-client # required for nymd-client
# at some point it might be possible to make it wasm-compatible # at some point it might be possible to make it wasm-compatible
@@ -2,27 +2,24 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::{validator_api, ValidatorClientError}; use crate::{validator_api, ValidatorClientError};
use coconut_interface::{ use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
use url::Url;
use validator_api_requests::coconut::{
BlindSignRequestBody, BlindedSignatureResponse, ExecuteReleaseFundsRequestBody, BlindSignRequestBody, BlindedSignatureResponse, ExecuteReleaseFundsRequestBody,
ProposeReleaseFundsRequestBody, ProposeReleaseFundsResponse, VerificationKeyResponse, ProposeReleaseFundsRequestBody, ProposeReleaseFundsResponse, VerificationKeyResponse,
VerifyCredentialBody, VerifyCredentialResponse, VerifyCredentialBody, VerifyCredentialResponse,
}; };
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
use url::Url;
use validator_api_requests::models::{ use validator_api_requests::models::{
CoreNodeStatusResponse, MixnodeStatusResponse, RewardEstimationResponse, CoreNodeStatusResponse, MixnodeStatusResponse, RewardEstimationResponse,
StakeSaturationResponse, StakeSaturationResponse,
}; };
#[cfg(feature = "nymd-client")] #[cfg(feature = "nymd-client")]
use validator_api_requests::models::{MixNodeBondAnnotated, UptimeResponse}; use validator_api_requests::models::{MixNodeBondAnnotated, UptimeResponse};
#[cfg(feature = "nymd-client")]
use network_defaults::DEFAULT_NETWORK;
#[cfg(feature = "nymd-client")] #[cfg(feature = "nymd-client")]
use crate::nymd::{ use crate::nymd::{
error::NymdError, CosmWasmClient, NymdClient, QueryNymdClient, SigningNymdClient, self, error::NymdError, CosmWasmClient, NymdClient, QueryNymdClient, SigningNymdClient,
}; };
#[cfg(feature = "nymd-client")] #[cfg(feature = "nymd-client")]
@@ -32,18 +29,18 @@ use mixnet_contract_common::{
RewardedSetUpdateDetails, RewardedSetUpdateDetails,
}; };
#[cfg(feature = "nymd-client")] #[cfg(feature = "nymd-client")]
use network_defaults::{all::Network, NymNetworkDetails};
#[cfg(feature = "nymd-client")]
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
#[cfg(feature = "nymd-client")] #[cfg(feature = "nymd-client")]
#[must_use] #[must_use]
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Config { pub struct Config {
network: network_defaults::all::Network,
api_url: Url, api_url: Url,
nymd_url: Url, nymd_url: Url,
mixnet_contract_address: cosmrs::AccountId,
vesting_contract_address: cosmrs::AccountId, nymd_config: nymd::Config,
bandwidth_claim_contract_address: cosmrs::AccountId,
mixnode_page_limit: Option<u32>, mixnode_page_limit: Option<u32>,
gateway_page_limit: Option<u32>, gateway_page_limit: Option<u32>,
@@ -53,42 +50,44 @@ pub struct Config {
#[cfg(feature = "nymd-client")] #[cfg(feature = "nymd-client")]
impl Config { impl Config {
pub fn new(network: network_defaults::all::Network, nymd_url: Url, api_url: Url) -> Self { pub fn try_from_nym_network_details(
Config { details: &NymNetworkDetails,
network, ) -> Result<Self, ValidatorClientError> {
nymd_url, let mut api_url = details
mixnet_contract_address: DEFAULT_NETWORK .endpoints
.mixnet_contract_address() .iter()
.filter_map(|d| d.api_url.as_ref())
.map(|url| Url::parse(url))
.collect::<Result<Vec<_>, _>>()?;
if api_url.is_empty() {
return Err(ValidatorClientError::NoAPIUrlAvailable);
}
Ok(Config {
api_url: api_url.pop().unwrap(),
nymd_url: details.endpoints[0]
.nymd_url
.parse() .parse()
.expect("Error parsing mixnet contract address"), .map_err(ValidatorClientError::MalformedUrlProvided)?,
vesting_contract_address: DEFAULT_NETWORK nymd_config: nymd::Config::try_from_nym_network_details(details)?,
.vesting_contract_address()
.parse()
.expect("Error parsing vesting contract address"),
bandwidth_claim_contract_address: DEFAULT_NETWORK
.bandwidth_claim_contract_address()
.parse()
.expect("Error parsing bandwidth claim contract address"),
api_url,
mixnode_page_limit: None, mixnode_page_limit: None,
gateway_page_limit: None, gateway_page_limit: None,
mixnode_delegations_page_limit: None, mixnode_delegations_page_limit: None,
rewarded_set_page_limit: None, rewarded_set_page_limit: None,
} })
} }
pub fn with_mixnode_contract_address(mut self, address: cosmrs::AccountId) -> Self { // TODO: this method shouldn't really exist as all information should be included immediately
self.mixnet_contract_address = address; // via `from_nym_network_details`, but it's here for, you guessed it, legacy compatibility
pub fn with_urls(mut self, nymd_url: Url, api_url: Url) -> Self {
self.nymd_url = nymd_url;
self.api_url = api_url;
self self
} }
pub fn with_vesting_contract_address(mut self, address: cosmrs::AccountId) -> Self { pub fn with_nymd_url(mut self, nymd_url: Url) -> Self {
self.vesting_contract_address = address; self.nymd_url = nymd_url;
self
}
pub fn with_bandwidth_claim_contract_address(mut self, address: cosmrs::AccountId) -> Self {
self.bandwidth_claim_contract_address = address;
self self
} }
@@ -115,10 +114,11 @@ impl Config {
#[cfg(feature = "nymd-client")] #[cfg(feature = "nymd-client")]
pub struct Client<C> { pub struct Client<C> {
pub network: network_defaults::all::Network, // compatibility : (
mixnet_contract_address: cosmrs::AccountId, pub network: Network,
vesting_contract_address: cosmrs::AccountId,
bandwidth_claim_contract_address: cosmrs::AccountId, // TODO: we really shouldn't be storing a mnemonic here, but removing it would be
// non-trivial amount of work and it's out of scope of the current branch
mnemonic: Option<bip39::Mnemonic>, mnemonic: Option<bip39::Mnemonic>,
mixnode_page_limit: Option<u32>, mixnode_page_limit: Option<u32>,
@@ -135,29 +135,26 @@ pub struct Client<C> {
impl Client<SigningNymdClient> { impl Client<SigningNymdClient> {
pub fn new_signing( pub fn new_signing(
config: Config, config: Config,
// we need to provide network argument due to compatibility with other components (wallet...)
// that rely on its existence...
network: Network,
mnemonic: bip39::Mnemonic, mnemonic: bip39::Mnemonic,
) -> Result<Client<SigningNymdClient>, ValidatorClientError> { ) -> Result<Client<SigningNymdClient>, ValidatorClientError> {
let validator_api_client = validator_api::Client::new(config.api_url.clone()); let validator_api_client = validator_api::Client::new(config.api_url.clone());
let nymd_client = NymdClient::connect_with_mnemonic( let nymd_client = NymdClient::connect_with_mnemonic(
config.network, config.nymd_config.clone(),
config.nymd_url.as_str(), config.nymd_url.as_str(),
mnemonic.clone(), mnemonic.clone(),
None, None,
)? )?;
.with_mixnet_contract_address(config.mixnet_contract_address.clone())
.with_vesting_contract_address(config.vesting_contract_address.clone())
.with_bandwidth_claim_contract_address(config.bandwidth_claim_contract_address.clone());
Ok(Client { Ok(Client {
network: config.network, network,
mixnet_contract_address: config.mixnet_contract_address,
vesting_contract_address: config.vesting_contract_address,
bandwidth_claim_contract_address: config.bandwidth_claim_contract_address,
mnemonic: Some(mnemonic), mnemonic: Some(mnemonic),
mixnode_page_limit: config.mixnode_page_limit, mixnode_page_limit: config.mixnode_page_limit,
gateway_page_limit: config.gateway_page_limit, gateway_page_limit: config.gateway_page_limit,
mixnode_delegations_page_limit: config.mixnode_delegations_page_limit, mixnode_delegations_page_limit: config.mixnode_delegations_page_limit,
rewarded_set_page_limit: None, rewarded_set_page_limit: config.rewarded_set_page_limit,
validator_api: validator_api_client, validator_api: validator_api_client,
nymd: nymd_client, nymd: nymd_client,
}) })
@@ -165,14 +162,11 @@ impl Client<SigningNymdClient> {
pub fn change_nymd(&mut self, new_endpoint: Url) -> Result<(), ValidatorClientError> { pub fn change_nymd(&mut self, new_endpoint: Url) -> Result<(), ValidatorClientError> {
self.nymd = NymdClient::connect_with_mnemonic( self.nymd = NymdClient::connect_with_mnemonic(
self.network, self.nymd.current_config().clone(),
new_endpoint.as_ref(), new_endpoint.as_ref(),
self.mnemonic.clone().unwrap(), self.mnemonic.clone().unwrap(),
None, None,
)? )?;
.with_mixnet_contract_address(self.mixnet_contract_address.clone())
.with_vesting_contract_address(self.vesting_contract_address.clone())
.with_bandwidth_claim_contract_address(self.bandwidth_claim_contract_address.clone());
Ok(()) Ok(())
} }
@@ -183,17 +177,18 @@ impl Client<SigningNymdClient> {
#[cfg(feature = "nymd-client")] #[cfg(feature = "nymd-client")]
impl Client<QueryNymdClient> { impl Client<QueryNymdClient> {
pub fn new_query(config: Config) -> Result<Client<QueryNymdClient>, ValidatorClientError> { pub fn new_query(
config: Config,
// we need to provide network argument due to compatibility with other components (wallet...)
// that rely on its existence...
network: Network,
) -> Result<Client<QueryNymdClient>, ValidatorClientError> {
let validator_api_client = validator_api::Client::new(config.api_url.clone()); let validator_api_client = validator_api::Client::new(config.api_url.clone());
let nymd_client = NymdClient::connect(config.nymd_url.as_str())? let nymd_client =
.with_mixnet_contract_address(config.mixnet_contract_address.clone()) NymdClient::connect(config.nymd_config.clone(), config.nymd_url.as_str())?;
.with_vesting_contract_address(config.vesting_contract_address.clone());
Ok(Client { Ok(Client {
network: config.network, network,
mixnet_contract_address: config.mixnet_contract_address,
vesting_contract_address: config.vesting_contract_address,
bandwidth_claim_contract_address: config.bandwidth_claim_contract_address,
mnemonic: None, mnemonic: None,
mixnode_page_limit: config.mixnode_page_limit, mixnode_page_limit: config.mixnode_page_limit,
gateway_page_limit: config.gateway_page_limit, gateway_page_limit: config.gateway_page_limit,
@@ -205,10 +200,7 @@ impl Client<QueryNymdClient> {
} }
pub fn change_nymd(&mut self, new_endpoint: Url) -> Result<(), ValidatorClientError> { pub fn change_nymd(&mut self, new_endpoint: Url) -> Result<(), ValidatorClientError> {
self.nymd = NymdClient::connect(new_endpoint.as_ref())? self.nymd = NymdClient::connect(self.nymd.current_config().clone(), new_endpoint.as_ref())?;
.with_mixnet_contract_address(self.mixnet_contract_address.clone())
.with_vesting_contract_address(self.vesting_contract_address.clone())
.with_bandwidth_claim_contract_address(self.bandwidth_claim_contract_address.clone());
Ok(()) Ok(())
} }
} }
@@ -222,11 +214,12 @@ impl<C> Client<C> {
// use case: somebody initialised client without a contract in order to upload and initialise one // use case: somebody initialised client without a contract in order to upload and initialise one
// and now they want to actually use it without making new client // and now they want to actually use it without making new client
pub fn set_mixnet_contract_address(&mut self, mixnet_contract_address: cosmrs::AccountId) { pub fn set_mixnet_contract_address(&mut self, mixnet_contract_address: cosmrs::AccountId) {
self.mixnet_contract_address = mixnet_contract_address self.nymd
.set_mixnet_contract_address(mixnet_contract_address)
} }
pub fn get_mixnet_contract_address(&self) -> cosmrs::AccountId { pub fn get_mixnet_contract_address(&self) -> cosmrs::AccountId {
self.mixnet_contract_address.clone() self.nymd.mixnet_contract_address().clone()
} }
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError> { pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
@@ -318,6 +311,13 @@ impl<C> Client<C> {
Ok(self.nymd.get_current_epoch().await?) Ok(self.nymd.get_current_epoch().await?)
} }
pub async fn get_current_operator_cost(&self) -> Result<u64, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
Ok(self.nymd.get_current_operator_cost().await?)
}
pub async fn get_mixnet_contract_version(&self) -> Result<MixnetContractVersion, NymdError> pub async fn get_mixnet_contract_version(&self) -> Result<MixnetContractVersion, NymdError>
where where
C: CosmWasmClient + Sync, C: CosmWasmClient + Sync,
@@ -1,5 +1,5 @@
use crate::nymd::error::NymdError; use crate::nymd::error::NymdError;
use crate::nymd::{NymdClient, QueryNymdClient}; use crate::nymd::{Config as ClientConfig, NymdClient, QueryNymdClient};
use crate::ApiClient; use crate::ApiClient;
use network_defaults::all::Network; use network_defaults::all::Network;
@@ -54,10 +54,20 @@ fn setup_connection_tests<H: BuildHasher + 'static>(
.get(&network) .get(&network)
.expect("No configured contract address") .expect("No configured contract address")
.clone(); .clone();
NymdClient::<QueryNymdClient>::connect(url.as_str()) let config = ClientConfig::try_from_nym_network_details(&network.details())
.map(|client| client.with_mixnet_contract_address(address)) .expect("failed to create valid nymd client config");
.map(move |client| ClientForConnectionTest::Nymd(network, url, Box::new(client)))
.ok() if let Ok(mut client) = NymdClient::<QueryNymdClient>::connect(config, url.as_str()) {
// possibly redundant, but lets just leave it here
client.set_mixnet_contract_address(address);
Some(ClientForConnectionTest::Nymd(
network,
url,
Box::new(client),
))
} else {
None
}
}); });
let api_connection_test_clients = api_urls.map(|(network, url)| { let api_connection_test_clients = api_urls.map(|(network, url)| {
@@ -76,7 +86,7 @@ fn extract_and_collect_results_into_map(
.filter(|c| &c.url_type() == url_type) .filter(|c| &c.url_type() == url_type)
.map(|c| { .map(|c| {
let (network, url, result) = c.result(); let (network, url, result) = c.result();
(*network, (url.clone(), *result)) (network.clone(), (url.clone(), *result))
}) })
.into_group_map() .into_group_map()
} }
@@ -18,4 +18,7 @@ pub enum ValidatorClientError {
#[cfg(feature = "nymd-client")] #[cfg(feature = "nymd-client")]
#[error("There was an issue with the Nymd client - {0}")] #[error("There was an issue with the Nymd client - {0}")]
NymdError(#[from] crate::nymd::error::NymdError), NymdError(#[from] crate::nymd::error::NymdError),
#[error("No validator API url has been provided")]
NoAPIUrlAvailable,
} }
@@ -8,7 +8,7 @@ use crate::nymd::cosmwasm_client::types::*;
use crate::nymd::error::NymdError; use crate::nymd::error::NymdError;
use crate::nymd::fee::{Fee, DEFAULT_SIMULATED_GAS_MULTIPLIER}; use crate::nymd::fee::{Fee, DEFAULT_SIMULATED_GAS_MULTIPLIER};
use crate::nymd::wallet::DirectSecp256k1HdWallet; use crate::nymd::wallet::DirectSecp256k1HdWallet;
use crate::nymd::{Coin, GasPrice, TxResponse}; use crate::nymd::{Coin, GasAdjustable, GasPrice, TxResponse};
use async_trait::async_trait; use async_trait::async_trait;
use cosmrs::bank::MsgSend; use cosmrs::bank::MsgSend;
use cosmrs::distribution::MsgWithdrawDelegatorReward; use cosmrs::distribution::MsgWithdrawDelegatorReward;
@@ -490,28 +490,35 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
fee: Fee, fee: Fee,
memo: &String, memo: &String,
) -> Result<tx::Fee, NymdError> { ) -> Result<tx::Fee, NymdError> {
let auto_fee = |multiplier: Option<f32>| async move {
debug!("Trying to simulate gas costs...");
// from what I've seen in manual testing, gas estimation does not exist if transaction
// fails to get executed (for example if you send 'BondMixnode" with invalid signature)
let gas_estimation = self
.simulate(signer_address, messages.to_vec(), memo.clone())
.await?
.gas_info
.ok_or(NymdError::GasEstimationFailure)?
.gas_used;
let multiplier = multiplier.unwrap_or(DEFAULT_SIMULATED_GAS_MULTIPLIER);
let gas = gas_estimation.adjust_gas(multiplier);
debug!("Gas estimation: {}", gas_estimation);
debug!("Multiplying the estimation by {}", multiplier);
debug!("Final gas limit used: {}", gas);
let fee = self.gas_price() * gas;
Ok::<tx::Fee, NymdError>(tx::Fee::from_amount_and_gas(fee, gas))
};
let fee = match fee { let fee = match fee {
Fee::Manual(fee) => fee, Fee::Manual(fee) => fee,
Fee::Auto(multiplier) => { Fee::Auto(multiplier) => auto_fee(multiplier).await?,
debug!("Trying to simulate gas costs..."); Fee::PayerGranterAuto(multiplier, payer, granter) => {
// from what I've seen in manual testing, gas estimation does not exist if transaction let mut fee = auto_fee(multiplier).await?;
// fails to get executed (for example if you send 'BondMixnode" with invalid signature) fee.payer = payer;
let gas_estimation = self fee.granter = granter;
.simulate(signer_address, messages.to_vec(), memo.clone()) fee
.await?
.gas_info
.ok_or(NymdError::GasEstimationFailure)?
.gas_used;
let multiplier = multiplier.unwrap_or(DEFAULT_SIMULATED_GAS_MULTIPLIER);
let gas = ((gas_estimation.value() as f32 * multiplier) as u64).into();
debug!("Gas estimation: {}", gas_estimation);
debug!("Multiplying the estimation by {}", multiplier);
debug!("Final gas limit used: {}", gas);
let fee = self.gas_price() * gas;
tx::Fee::from_amount_and_gas(fee, gas)
} }
}; };
debug!("Fee used for the transaction: {:?}", fee); debug!("Fee used for the transaction: {:?}", fee);
@@ -130,6 +130,9 @@ pub enum NymdError {
#[error("Coconut interface error: {0}")] #[error("Coconut interface error: {0}")]
CoconutInterfaceError(#[from] coconut_interface::error::CoconutInterfaceError), CoconutInterfaceError(#[from] coconut_interface::error::CoconutInterfaceError),
#[error("Account had an unexpected bech32 prefix. Expected: {expected}, got: {got}")]
UnexpectedBech32Prefix { got: String, expected: String },
} }
impl NymdError { impl NymdError {
@@ -1,17 +1,21 @@
// 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 cosmrs::tx; use crate::nymd::Gas;
use cosmrs::{tx, AccountId};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub mod gas_price; pub mod gas_price;
pub const DEFAULT_SIMULATED_GAS_MULTIPLIER: f32 = 1.3; pub type GasAdjustment = f32;
pub const DEFAULT_SIMULATED_GAS_MULTIPLIER: GasAdjustment = 1.3;
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Fee { pub enum Fee {
Manual(#[serde(with = "sealed::TxFee")] tx::Fee), Manual(#[serde(with = "sealed::TxFee")] tx::Fee),
Auto(Option<f32>), Auto(Option<GasAdjustment>),
PayerGranterAuto(Option<GasAdjustment>, Option<AccountId>, Option<AccountId>),
} }
impl From<tx::Fee> for Fee { impl From<tx::Fee> for Fee {
@@ -20,8 +24,8 @@ impl From<tx::Fee> for Fee {
} }
} }
impl From<f32> for Fee { impl From<GasAdjustment> for Fee {
fn from(multiplier: f32) -> Self { fn from(multiplier: GasAdjustment) -> Self {
Fee::Auto(Some(multiplier)) Fee::Auto(Some(multiplier))
} }
} }
@@ -32,6 +36,21 @@ impl Default for Fee {
} }
} }
pub trait GasAdjustable {
fn adjust_gas(&self, adjustment: GasAdjustment) -> Self;
}
impl GasAdjustable for Gas {
fn adjust_gas(&self, adjustment: GasAdjustment) -> Self {
if adjustment == 1.0 {
*self
} else {
let adjusted = (self.value() as f32 * adjustment).ceil();
(adjusted as u64).into()
}
}
}
// a workaround to provide serde implementation for tx::Fee. We don't want to ever expose any of those // 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 // types to the public and ideally they will get replaced by proper implementation inside comrs
mod sealed { mod sealed {
@@ -15,19 +15,19 @@ use cosmrs::rpc::HttpClientUrl;
use cosmrs::tx::Msg; use cosmrs::tx::Msg;
use cosmwasm_std::Uint128; use cosmwasm_std::Uint128;
use execute::execute; use execute::execute;
pub use fee::gas_price::GasPrice;
use mixnet_contract_common::mixnode::DelegationEvent; use mixnet_contract_common::mixnode::DelegationEvent;
use mixnet_contract_common::{ use mixnet_contract_common::{
ContractStateParams, Delegation, ExecuteMsg, Gateway, GatewayBond, GatewayOwnershipResponse, ContractStateParams, Delegation, ExecuteMsg, Gateway, GatewayBond, GatewayBondResponse,
IdentityKey, Interval, LayerDistribution, MixNode, MixNodeBond, MixOwnershipResponse, GatewayOwnershipResponse, IdentityKey, Interval, LayerDistribution, MixNode, MixNodeBond,
MixnetContractVersion, MixnodeRewardingStatusResponse, PagedDelegatorDelegationsResponse, MixOwnershipResponse, MixnetContractVersion, MixnodeBondResponse,
PagedGatewayResponse, PagedMixDelegationsResponse, PagedMixnodeResponse, MixnodeRewardingStatusResponse, PagedDelegatorDelegationsResponse, PagedGatewayResponse,
PagedRewardedSetResponse, QueryMsg, RewardedSetUpdateDetails, PagedMixDelegationsResponse, PagedMixnodeResponse, PagedRewardedSetResponse, QueryMsg,
RewardedSetUpdateDetails,
}; };
use network_defaults::DEFAULT_NETWORK;
use serde::Serialize; use serde::Serialize;
use std::convert::TryInto; use std::convert::TryInto;
use vesting_contract_common::ExecuteMsg as VestingExecuteMsg; use vesting_contract_common::ExecuteMsg as VestingExecuteMsg;
use vesting_contract_common::QueryMsg as VestingQueryMsg;
pub use crate::nymd::cosmwasm_client::client::CosmWasmClient; pub use crate::nymd::cosmwasm_client::client::CosmWasmClient;
pub use crate::nymd::cosmwasm_client::signing_client::SigningCosmWasmClient; pub use crate::nymd::cosmwasm_client::signing_client::SigningCosmWasmClient;
@@ -48,6 +48,8 @@ pub use cosmrs::tx::{self, Gas};
pub use cosmrs::Coin as CosmosCoin; pub use cosmrs::Coin as CosmosCoin;
pub use cosmrs::{bip32, AccountId, Decimal, Denom}; pub use cosmrs::{bip32, AccountId, Decimal, Denom};
pub use cosmwasm_std::Coin as CosmWasmCoin; pub use cosmwasm_std::Coin as CosmWasmCoin;
pub use fee::{gas_price::GasPrice, GasAdjustable, GasAdjustment};
use network_defaults::{ChainDetails, NymNetworkDetails};
pub use signing_client::Client as SigningNymdClient; pub use signing_client::Client as SigningNymdClient;
pub use traits::{VestingQueryClient, VestingSigningClient}; pub use traits::{VestingQueryClient, VestingSigningClient};
@@ -58,67 +60,92 @@ pub mod fee;
pub mod traits; pub mod traits;
pub mod wallet; pub mod wallet;
#[derive(Debug, Clone)]
pub struct Config {
pub(crate) chain_details: ChainDetails,
// I'd love to have used `NymContracts` struct directly here instead,
// however, I'd really prefer to use something more strongly typed (i.e. AccountId vs String)
pub(crate) mixnet_contract_address: Option<AccountId>,
pub(crate) vesting_contract_address: Option<AccountId>,
pub(crate) bandwidth_claim_contract_address: Option<AccountId>,
pub(crate) coconut_bandwidth_contract_address: Option<AccountId>,
pub(crate) multisig_contract_address: Option<AccountId>,
// TODO: add this in later commits
// pub(crate) gas_price: GasPrice,
}
impl Config {
fn parse_optional_account(
raw: Option<&String>,
expected_prefix: &str,
) -> Result<Option<AccountId>, NymdError> {
if let Some(address) = raw {
let parsed: AccountId = address
.parse()
.map_err(|_| NymdError::MalformedAccountAddress(address.clone()))?;
if parsed.prefix() != expected_prefix {
Err(NymdError::UnexpectedBech32Prefix {
got: parsed.prefix().into(),
expected: expected_prefix.into(),
})
} else {
Ok(Some(parsed))
}
} else {
Ok(None)
}
}
pub fn try_from_nym_network_details(details: &NymNetworkDetails) -> Result<Self, NymdError> {
let prefix = &details.chain_details.bech32_account_prefix;
Ok(Config {
chain_details: details.chain_details.clone(),
mixnet_contract_address: Self::parse_optional_account(
details.contracts.mixnet_contract_address.as_ref(),
prefix,
)?,
vesting_contract_address: Self::parse_optional_account(
details.contracts.vesting_contract_address.as_ref(),
prefix,
)?,
bandwidth_claim_contract_address: Self::parse_optional_account(
details.contracts.bandwidth_claim_contract_address.as_ref(),
prefix,
)?,
coconut_bandwidth_contract_address: Self::parse_optional_account(
details
.contracts
.coconut_bandwidth_contract_address
.as_ref(),
prefix,
)?,
multisig_contract_address: Self::parse_optional_account(
details.contracts.multisig_contract_address.as_ref(),
prefix,
)?,
})
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct NymdClient<C> { pub struct NymdClient<C> {
client: C, client: C,
mixnet_contract_address: AccountId, config: Config,
vesting_contract_address: AccountId,
bandwidth_claim_contract_address: AccountId,
coconut_bandwidth_contract_address: AccountId,
multisig_contract_address: AccountId,
client_address: Option<Vec<AccountId>>, client_address: Option<Vec<AccountId>>,
simulated_gas_multiplier: f32, simulated_gas_multiplier: f32,
} }
impl<C> NymdClient<C> {
pub fn with_mixnet_contract_address(mut self, address: AccountId) -> Self {
self.mixnet_contract_address = address;
self
}
pub fn with_vesting_contract_address(mut self, address: AccountId) -> Self {
self.vesting_contract_address = address;
self
}
pub fn with_bandwidth_claim_contract_address(mut self, address: AccountId) -> Self {
self.bandwidth_claim_contract_address = address;
self
}
pub fn with_coconut_bandwidth_contract_address(mut self, address: AccountId) -> Self {
self.coconut_bandwidth_contract_address = address;
self
}
pub fn with_multisig_contract_address(mut self, address: AccountId) -> Self {
self.multisig_contract_address = address;
self
}
}
impl NymdClient<QueryNymdClient> { impl NymdClient<QueryNymdClient> {
pub fn connect<U>(endpoint: U) -> Result<NymdClient<QueryNymdClient>, NymdError> pub fn connect<U>(config: Config, endpoint: U) -> Result<NymdClient<QueryNymdClient>, NymdError>
where where
U: TryInto<HttpClientUrl, Error = TendermintRpcError>, U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
{ {
Ok(NymdClient { Ok(NymdClient {
client: QueryNymdClient::new(endpoint)?, client: QueryNymdClient::new(endpoint)?,
config,
client_address: None, client_address: None,
simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER, simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER,
mixnet_contract_address: DEFAULT_NETWORK
.mixnet_contract_address()
.parse()
.expect("Error parsing mixnet contract address"),
vesting_contract_address: DEFAULT_NETWORK
.vesting_contract_address()
.parse()
.expect("Error parsing vesting contract address"),
bandwidth_claim_contract_address: DEFAULT_NETWORK
.bandwidth_claim_contract_address()
.parse()
.expect("Error parsing bandwidth claim contract address"),
coconut_bandwidth_contract_address: DEFAULT_NETWORK
.coconut_bandwidth_contract_address()
.parse()
.unwrap(),
multisig_contract_address: DEFAULT_NETWORK.multisig_contract_address().parse().unwrap(),
}) })
} }
} }
@@ -126,6 +153,7 @@ impl NymdClient<QueryNymdClient> {
impl NymdClient<SigningNymdClient> { impl NymdClient<SigningNymdClient> {
// maybe the wallet could be made into a generic, but for now, let's just have this one implementation // maybe the wallet could be made into a generic, but for now, let's just have this one implementation
pub fn connect_with_signer<U: Clone>( pub fn connect_with_signer<U: Clone>(
config: Config,
network: config::defaults::all::Network, network: config::defaults::all::Network,
endpoint: U, endpoint: U,
signer: DirectSecp256k1HdWallet, signer: DirectSecp256k1HdWallet,
@@ -134,40 +162,24 @@ impl NymdClient<SigningNymdClient> {
where where
U: TryInto<HttpClientUrl, Error = TendermintRpcError>, U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
{ {
let denom = network.denom(); let denom = network.base_mix_denom();
let client_address = signer let client_address = signer
.try_derive_accounts()? .try_derive_accounts()?
.into_iter() .into_iter()
.map(|account| account.address) .map(|account| account.address)
.collect(); .collect();
let gas_price = gas_price.unwrap_or(GasPrice::new_with_default_price(denom)?); let gas_price = gas_price.unwrap_or(GasPrice::new_with_default_price(&denom)?);
Ok(NymdClient { Ok(NymdClient {
client: SigningNymdClient::connect_with_signer(endpoint, signer, gas_price)?, client: SigningNymdClient::connect_with_signer(endpoint, signer, gas_price)?,
config,
client_address: Some(client_address), client_address: Some(client_address),
simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER, simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER,
mixnet_contract_address: DEFAULT_NETWORK
.mixnet_contract_address()
.parse()
.expect("Error parsing mixnet contract address"),
vesting_contract_address: DEFAULT_NETWORK
.vesting_contract_address()
.parse()
.expect("Error parsing vesting contract address"),
bandwidth_claim_contract_address: DEFAULT_NETWORK
.bandwidth_claim_contract_address()
.parse()
.expect("Error parsing bandwidth claim contract address"),
coconut_bandwidth_contract_address: DEFAULT_NETWORK
.coconut_bandwidth_contract_address()
.parse()
.unwrap(),
multisig_contract_address: DEFAULT_NETWORK.multisig_contract_address().parse().unwrap(),
}) })
} }
pub fn connect_with_mnemonic<U: Clone>( pub fn connect_with_mnemonic<U: Clone>(
network: config::defaults::all::Network, config: Config,
endpoint: U, endpoint: U,
mnemonic: bip39::Mnemonic, mnemonic: bip39::Mnemonic,
gas_price: Option<GasPrice>, gas_price: Option<GasPrice>,
@@ -175,8 +187,8 @@ impl NymdClient<SigningNymdClient> {
where where
U: TryInto<HttpClientUrl, Error = TendermintRpcError>, U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
{ {
let prefix = network.bech32_prefix(); let prefix = &config.chain_details.bech32_account_prefix;
let denom = network.denom(); let denom = &config.chain_details.mix_denom.base;
let wallet = DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic)?; let wallet = DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic)?;
let client_address = wallet let client_address = wallet
.try_derive_accounts()? .try_derive_accounts()?
@@ -187,48 +199,82 @@ impl NymdClient<SigningNymdClient> {
Ok(NymdClient { Ok(NymdClient {
client: SigningNymdClient::connect_with_signer(endpoint, wallet, gas_price)?, client: SigningNymdClient::connect_with_signer(endpoint, wallet, gas_price)?,
config,
client_address: Some(client_address), client_address: Some(client_address),
simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER, simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER,
mixnet_contract_address: network
.mixnet_contract_address()
.parse()
.expect("Error parsing mixnet contract address"),
vesting_contract_address: network
.vesting_contract_address()
.parse()
.expect("Error parsing vesting contract address"),
bandwidth_claim_contract_address: network
.bandwidth_claim_contract_address()
.parse()
.expect("Error parsing bandwidth claim contract address"),
coconut_bandwidth_contract_address: network
.coconut_bandwidth_contract_address()
.parse()
.unwrap(),
multisig_contract_address: network.multisig_contract_address().parse().unwrap(),
}) })
} }
} }
impl<C> NymdClient<C> { impl<C> NymdClient<C> {
pub fn current_config(&self) -> &Config {
&self.config
}
pub fn set_mixnet_contract_address(&mut self, address: AccountId) {
self.config.mixnet_contract_address = Some(address);
}
pub fn set_vesting_contract_address(&mut self, address: AccountId) {
self.config.vesting_contract_address = Some(address);
}
pub fn set_bandwidth_claim_contract_address(&mut self, address: AccountId) {
self.config.bandwidth_claim_contract_address = Some(address);
}
pub fn set_coconut_bandwidth_contract_address(&mut self, address: AccountId) {
self.config.coconut_bandwidth_contract_address = Some(address);
}
pub fn set_multisig_contract_address(&mut self, address: AccountId) {
self.config.multisig_contract_address = Some(address);
}
// TODO: this should get changed into Result<&AccountId, NymdError> (or Option<&AccountId> in future commits
// note: what unwrap is doing here is just moving a failure that would have normally
// occurred in `connect` when attempting to parse an empty address,
// so it's not introducing new source of failure (just moves it)
pub fn mixnet_contract_address(&self) -> &AccountId { pub fn mixnet_contract_address(&self) -> &AccountId {
&self.mixnet_contract_address self.config.mixnet_contract_address.as_ref().unwrap()
} }
// TODO: this should get changed into Result<&AccountId, NymdError> (or Option<&AccountId> in future commits
// note: what unwrap is doing here is just moving a failure that would have normally
// occurred in `connect` when attempting to parse an empty address,
// so it's not introducing new source of failure (just moves it)
pub fn vesting_contract_address(&self) -> &AccountId { pub fn vesting_contract_address(&self) -> &AccountId {
&self.vesting_contract_address self.config.vesting_contract_address.as_ref().unwrap()
} }
// TODO: this should get changed into Result<&AccountId, NymdError> (or Option<&AccountId> in future commits
// note: what unwrap is doing here is just moving a failure that would have normally
// occurred in `connect` when attempting to parse an empty address,
// so it's not introducing new source of failure (just moves it)
pub fn bandwidth_claim_contract_address(&self) -> &AccountId { pub fn bandwidth_claim_contract_address(&self) -> &AccountId {
&self.bandwidth_claim_contract_address self.config
.bandwidth_claim_contract_address
.as_ref()
.unwrap()
} }
// TODO: this should get changed into Result<&AccountId, NymdError> (or Option<&AccountId> in future commits
// note: what unwrap is doing here is just moving a failure that would have normally
// occurred in `connect` when attempting to parse an empty address,
// so it's not introducing new source of failure (just moves it)
pub fn coconut_bandwidth_contract_address(&self) -> &AccountId { pub fn coconut_bandwidth_contract_address(&self) -> &AccountId {
&self.coconut_bandwidth_contract_address self.config
.coconut_bandwidth_contract_address
.as_ref()
.unwrap()
} }
// TODO: this should get changed into Result<&AccountId, NymdError> (or Option<&AccountId> in future commits
// note: what unwrap is doing here is just moving a failure that would have normally
// occurred in `connect` when attempting to parse an empty address,
// so it's not introducing new source of failure (just moves it)
pub fn multisig_contract_address(&self) -> &AccountId { pub fn multisig_contract_address(&self) -> &AccountId {
&self.multisig_contract_address self.config.multisig_contract_address.as_ref().unwrap()
} }
pub fn set_simulated_gas_multiplier(&mut self, multiplier: f32) { pub fn set_simulated_gas_multiplier(&mut self, multiplier: f32) {
@@ -268,6 +314,10 @@ impl<C> NymdClient<C> {
self.client.gas_price() self.client.gas_price()
} }
pub fn gas_adjustment(&self) -> GasAdjustment {
self.simulated_gas_multiplier
}
pub async fn account_sequence(&self) -> Result<SequenceResponse, NymdError> pub async fn account_sequence(&self) -> Result<SequenceResponse, NymdError>
where where
C: SigningCosmWasmClient + Sync, C: SigningCosmWasmClient + Sync,
@@ -380,6 +430,16 @@ impl<C> NymdClient<C> {
.await .await
} }
pub async fn vesting_get_locked_pledge_cap(&self) -> Result<Uint128, NymdError>
where
C: CosmWasmClient + Sync,
{
let request = VestingQueryMsg::GetLockedPledgeCap {};
self.client
.query_contract_smart(self.vesting_contract_address(), &request)
.await
}
pub async fn get_delegator_rewards( pub async fn get_delegator_rewards(
&self, &self,
address: String, address: String,
@@ -426,6 +486,16 @@ impl<C> NymdClient<C> {
.await .await
} }
pub async fn get_current_operator_cost(&self) -> Result<u64, NymdError>
where
C: CosmWasmClient + Sync,
{
let request = QueryMsg::GetCurrentOperatorCost {};
self.client
.query_contract_smart(self.mixnet_contract_address(), &request)
.await
}
pub async fn get_mixnet_contract_version(&self) -> Result<MixnetContractVersion, NymdError> pub async fn get_mixnet_contract_version(&self) -> Result<MixnetContractVersion, NymdError>
where where
C: CosmWasmClient + Sync, C: CosmWasmClient + Sync,
@@ -595,6 +665,38 @@ impl<C> NymdClient<C> {
Ok(response.gateway) Ok(response.gateway)
} }
/// Checks whether there is a bonded mixnode associated with the provided identity key
pub async fn get_mixnode_bond(
&self,
identity: IdentityKey,
) -> Result<Option<MixNodeBond>, NymdError>
where
C: CosmWasmClient + Sync,
{
let request = QueryMsg::GetMixnodeBond { identity };
let response: MixnodeBondResponse = self
.client
.query_contract_smart(self.mixnet_contract_address(), &request)
.await?;
Ok(response.mixnode)
}
/// Checks whether there is a bonded gateway associated with the provided identity key
pub async fn get_gateway_bond(
&self,
identity: IdentityKey,
) -> Result<Option<GatewayBond>, NymdError>
where
C: CosmWasmClient + Sync,
{
let request = QueryMsg::GetGatewayBond { identity };
let response: GatewayBondResponse = self
.client
.query_contract_smart(self.mixnet_contract_address(), &request)
.await?;
Ok(response.gateway)
}
pub async fn get_mixnodes_paged( pub async fn get_mixnodes_paged(
&self, &self,
start_after: Option<IdentityKey>, start_after: Option<IdentityKey>,
@@ -949,6 +1051,18 @@ impl<C> NymdClient<C> {
) )
} }
#[execute("vesting")]
fn _vesting_update_locked_pledge_cap(
&self,
amount: Uint128,
fee: Option<Fee>,
) -> (VestingExecuteMsg, Option<Fee>)
where
C: SigningCosmWasmClient + Sync,
{
(VestingExecuteMsg::UpdateLockedPledgeCap { amount }, fee)
}
/// Announce a mixnode, paying a fee. /// Announce a mixnode, paying a fee.
pub async fn bond_mixnode( pub async fn bond_mixnode(
&self, &self,
@@ -49,7 +49,7 @@ impl<C: SigningCosmWasmClient + Sync + Send> MultisigSigningClient for NymdClien
) -> Result<ExecuteResult, NymdError> { ) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
let release_funds_req = CoconutBandwidthExecuteMsg::ReleaseFunds { let release_funds_req = CoconutBandwidthExecuteMsg::ReleaseFunds {
funds: Coin::new(voucher_value, DEFAULT_NETWORK.denom()), funds: Coin::new(voucher_value, DEFAULT_NETWORK.mix_denom().base),
}; };
let release_funds_msg = CosmosMsg::Wasm(WasmMsg::Execute { let release_funds_msg = CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: self.coconut_bandwidth_contract_address().to_string(), contract_addr: self.coconut_bandwidth_contract_address().to_string(),
@@ -214,7 +214,7 @@ mod tests {
]; ];
for prefix in prefixes { for prefix in prefixes {
let addrs = match prefix { let addrs = match prefix.as_ref() {
"nymt" => vec![ "nymt" => vec![
"nymt1jw6mp7d5xqc7w6xm79lha27glmd0vdt339me94", "nymt1jw6mp7d5xqc7w6xm79lha27glmd0vdt339me94",
"nymt1h5hgn94nsq4kh99rjj794hr5h5q6yfm23rjshv", "nymt1h5hgn94nsq4kh99rjj794hr5h5q6yfm23rjshv",
@@ -229,7 +229,7 @@ mod tests {
}; };
for (idx, mnemonic) in mnemonics.iter().enumerate() { for (idx, mnemonic) in mnemonics.iter().enumerate() {
let wallet = let wallet =
DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic.parse().unwrap()) DirectSecp256k1HdWallet::from_mnemonic(&prefix, mnemonic.parse().unwrap())
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
wallet.try_derive_accounts().unwrap()[0].address, wallet.try_derive_accounts().unwrap()[0].address,
@@ -3,15 +3,15 @@
use crate::validator_api::error::ValidatorAPIError; use crate::validator_api::error::ValidatorAPIError;
use crate::validator_api::routes::{CORE_STATUS_COUNT, SINCE_ARG}; use crate::validator_api::routes::{CORE_STATUS_COUNT, SINCE_ARG};
use coconut_interface::{
BlindSignRequestBody, BlindedSignatureResponse, ExecuteReleaseFundsRequestBody,
ProposeReleaseFundsRequestBody, ProposeReleaseFundsResponse, VerificationKeyResponse,
VerifyCredentialBody, VerifyCredentialResponse,
};
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond}; use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use url::Url; use url::Url;
use validator_api_requests::coconut::{
BlindSignRequestBody, BlindedSignatureResponse, CosmosAddressResponse,
ExecuteReleaseFundsRequestBody, ProposeReleaseFundsRequestBody, ProposeReleaseFundsResponse,
VerificationKeyResponse, VerifyCredentialBody, VerifyCredentialResponse,
};
use validator_api_requests::models::{ use validator_api_requests::models::{
CoreNodeStatusResponse, InclusionProbabilityResponse, MixNodeBondAnnotated, CoreNodeStatusResponse, InclusionProbabilityResponse, MixNodeBondAnnotated,
MixnodeStatusResponse, RewardEstimationResponse, StakeSaturationResponse, UptimeResponse, MixnodeStatusResponse, RewardEstimationResponse, StakeSaturationResponse, UptimeResponse,
@@ -376,6 +376,19 @@ impl Client {
.await .await
} }
pub async fn get_cosmos_address(&self) -> Result<CosmosAddressResponse, ValidatorAPIError> {
self.query_validator_api(
&[
routes::API_VERSION,
routes::COCONUT_ROUTES,
routes::BANDWIDTH,
routes::COCONUT_COSMOS_ADDRESS,
],
NO_PARAMS,
)
.await
}
pub async fn verify_bandwidth_credential( pub async fn verify_bandwidth_credential(
&self, &self,
request_body: &VerifyCredentialBody, request_body: &VerifyCredentialBody,
@@ -17,6 +17,7 @@ pub const BANDWIDTH: &str = "bandwidth";
pub const COCONUT_BLIND_SIGN: &str = "blind-sign"; pub const COCONUT_BLIND_SIGN: &str = "blind-sign";
pub const COCONUT_PARTIAL_BANDWIDTH_CREDENTIAL: &str = "partial-bandwidth-credential"; pub const COCONUT_PARTIAL_BANDWIDTH_CREDENTIAL: &str = "partial-bandwidth-credential";
pub const COCONUT_VERIFICATION_KEY: &str = "verification-key"; pub const COCONUT_VERIFICATION_KEY: &str = "verification-key";
pub const COCONUT_COSMOS_ADDRESS: &str = "cosmos-address";
pub const COCONUT_VERIFY_BANDWIDTH_CREDENTIAL: &str = "verify-bandwidth-credential"; pub const COCONUT_VERIFY_BANDWIDTH_CREDENTIAL: &str = "verify-bandwidth-credential";
pub const COCONUT_PROPOSE_RELEASE_FUNDS: &str = "propose-release-funds"; pub const COCONUT_PROPOSE_RELEASE_FUNDS: &str = "propose-release-funds";
pub const COCONUT_EXECUTE_RELEASE_FUNDS: &str = "execute-release-funds"; pub const COCONUT_EXECUTE_RELEASE_FUNDS: &str = "execute-release-funds";
-165
View File
@@ -127,171 +127,6 @@ impl Bytable for Credential {
impl Base58 for Credential {} impl Base58 for Credential {}
#[derive(Serialize, Deserialize, Getters, CopyGetters)]
pub struct VerifyCredentialBody {
#[getset(get = "pub")]
credential: Credential,
#[getset(get = "pub")]
proposal_id: u64,
}
impl VerifyCredentialBody {
pub fn new(credential: Credential, proposal_id: u64) -> VerifyCredentialBody {
VerifyCredentialBody {
credential,
proposal_id,
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct VerifyCredentialResponse {
pub verification_result: bool,
}
impl VerifyCredentialResponse {
pub fn new(verification_result: bool) -> Self {
VerifyCredentialResponse {
verification_result,
}
}
}
// All strings are base58 encoded representations of structs
#[derive(Clone, Serialize, Deserialize, Debug, Getters, CopyGetters)]
pub struct BlindSignRequestBody {
#[getset(get = "pub")]
blind_sign_request: BlindSignRequest,
#[getset(get = "pub")]
tx_hash: String,
#[getset(get = "pub")]
signature: String,
public_attributes: Vec<String>,
#[getset(get = "pub")]
public_attributes_plain: Vec<String>,
#[getset(get = "pub")]
total_params: u32,
}
impl BlindSignRequestBody {
pub fn new(
blind_sign_request: &BlindSignRequest,
tx_hash: String,
signature: String,
public_attributes: &[Attribute],
public_attributes_plain: Vec<String>,
total_params: u32,
) -> BlindSignRequestBody {
BlindSignRequestBody {
blind_sign_request: blind_sign_request.clone(),
tx_hash,
signature,
public_attributes: public_attributes
.iter()
.map(|attr| attr.to_bs58())
.collect(),
public_attributes_plain,
total_params,
}
}
pub fn public_attributes(&self) -> Vec<Attribute> {
self.public_attributes
.iter()
.map(|x| Attribute::try_from_bs58(x).unwrap())
.collect()
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct BlindedSignatureResponse {
pub remote_key: [u8; 32],
pub encrypted_signature: Vec<u8>,
}
impl BlindedSignatureResponse {
pub fn new(encrypted_signature: Vec<u8>, remote_key: [u8; 32]) -> BlindedSignatureResponse {
BlindedSignatureResponse {
encrypted_signature,
remote_key,
}
}
pub fn to_base58_string(&self) -> String {
bs58::encode(&self.to_bytes()).into_string()
}
pub fn from_base58_string<I: AsRef<[u8]>>(val: I) -> Result<Self, CoconutInterfaceError> {
let bytes = bs58::decode(val).into_vec()?;
Self::from_bytes(&bytes)
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = self.remote_key.to_vec();
bytes.extend_from_slice(&self.encrypted_signature);
bytes
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, CoconutInterfaceError> {
if bytes.len() < 32 {
return Err(CoconutInterfaceError::InvalidByteLength(bytes.len(), 32));
}
let mut remote_key = [0u8; 32];
remote_key.copy_from_slice(&bytes[..32]);
let encrypted_signature = bytes[32..].to_vec();
Ok(BlindedSignatureResponse {
remote_key,
encrypted_signature,
})
}
}
#[derive(Serialize, Deserialize)]
pub struct VerificationKeyResponse {
pub key: VerificationKey,
}
impl VerificationKeyResponse {
pub fn new(key: VerificationKey) -> VerificationKeyResponse {
VerificationKeyResponse { key }
}
}
#[derive(Serialize, Deserialize, Getters, CopyGetters)]
pub struct ProposeReleaseFundsRequestBody {
#[getset(get = "pub")]
credential: Credential,
}
impl ProposeReleaseFundsRequestBody {
pub fn new(credential: Credential) -> Self {
ProposeReleaseFundsRequestBody { credential }
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ProposeReleaseFundsResponse {
pub proposal_id: u64,
}
impl ProposeReleaseFundsResponse {
pub fn new(proposal_id: u64) -> Self {
ProposeReleaseFundsResponse { proposal_id }
}
}
#[derive(Debug, Serialize, Deserialize, Getters, CopyGetters)]
pub struct ExecuteReleaseFundsRequestBody {
#[getset(get = "pub")]
proposal_id: u64,
}
impl ExecuteReleaseFundsRequestBody {
pub fn new(proposal_id: u64) -> Self {
ExecuteReleaseFundsRequestBody { proposal_id }
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@@ -136,6 +136,12 @@ pub struct GatewayOwnershipResponse {
pub gateway: Option<GatewayBond>, pub gateway: Option<GatewayBond>,
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
pub struct GatewayBondResponse {
pub identity: IdentityKey,
pub gateway: Option<GatewayBond>,
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@@ -121,6 +121,14 @@ impl Interval {
self.start_unix_timestamp() <= block_time && block_time < self.end_unix_timestamp() self.start_unix_timestamp() <= block_time && block_time < self.end_unix_timestamp()
} }
pub fn update_duration(&mut self, secs: u64) {
self.length = Duration::from_secs(secs);
}
pub const fn length_secs(&self) -> u64 {
self.length.as_secs()
}
/// Returns the next interval. /// Returns the next interval.
#[must_use] #[must_use]
pub fn next(&self) -> Self { pub fn next(&self) -> Self {
@@ -4,7 +4,7 @@
pub mod delegation; pub mod delegation;
pub mod error; pub mod error;
pub mod events; pub mod events;
mod gateway; pub mod gateway;
mod interval; mod interval;
pub mod mixnode; pub mod mixnode;
mod msg; mod msg;
@@ -18,10 +18,13 @@ pub use delegation::{
Delegation, PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse, Delegation, PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse,
PagedMixDelegationsResponse, PagedMixDelegationsResponse,
}; };
pub use gateway::{Gateway, GatewayBond, GatewayOwnershipResponse, PagedGatewayResponse}; pub use gateway::{
Gateway, GatewayBond, GatewayBondResponse, GatewayOwnershipResponse, PagedGatewayResponse,
};
pub use interval::Interval; pub use interval::Interval;
pub use mixnode::{ pub use mixnode::{
Layer, MixNode, MixNodeBond, MixOwnershipResponse, PagedMixnodeResponse, RewardedSetNodeStatus, Layer, MixNode, MixNodeBond, MixOwnershipResponse, MixnodeBondResponse, PagedMixnodeResponse,
RewardedSetNodeStatus,
}; };
pub use msg::*; pub use msg::*;
pub use types::*; pub use types::*;
@@ -431,6 +431,7 @@ impl MixNodeBond {
pub fn estimate_reward( pub fn estimate_reward(
&self, &self,
base_operator_cost: u64,
params: &RewardParams, params: &RewardParams,
) -> Result<RewardEstimate, MixnetContractError> { ) -> Result<RewardEstimate, MixnetContractError> {
let total_node_reward = self let total_node_reward = self
@@ -439,15 +440,15 @@ impl MixNodeBond {
.checked_to_num::<u128>() .checked_to_num::<u128>()
.unwrap_or_default(); .unwrap_or_default();
let node_profit = self let node_profit = self
.node_profit(params) .node_profit(params, base_operator_cost)
.checked_to_num::<u128>() .checked_to_num::<u128>()
.unwrap_or_default(); .unwrap_or_default();
let operator_cost = params let operator_cost = params
.node .node
.operator_cost() .operator_cost(base_operator_cost)
.checked_to_num::<u128>() .checked_to_num::<u128>()
.unwrap_or_default(); .unwrap_or_default();
let operator_reward = self.operator_reward(params); let operator_reward = self.operator_reward(params, base_operator_cost);
// Total reward has to be the sum of operator and delegator rewards // Total reward has to be the sum of operator and delegator rewards
let delegators_reward = node_profit.saturating_sub(operator_reward); let delegators_reward = node_profit.saturating_sub(operator_reward);
@@ -479,21 +480,25 @@ impl MixNodeBond {
} }
} }
pub fn node_profit(&self, params: &RewardParams) -> U128 { pub fn node_profit(&self, params: &RewardParams, base_operator_cost: u64) -> U128 {
self.reward(params) self.reward(params)
.reward() .reward()
.saturating_sub(params.node.operator_cost()) .saturating_sub(params.node.operator_cost(base_operator_cost))
} }
pub fn operator_reward(&self, params: &RewardParams) -> u128 { pub fn operator_reward(&self, params: &RewardParams, base_operator_cost: u64) -> u128 {
let reward = self.reward(params); let reward = self.reward(params);
if reward.sigma == 0 { if reward.sigma == 0u128 {
return 0; return 0;
} }
let profit = reward.reward.saturating_sub(params.node.operator_cost()); let profit = reward
.reward
.saturating_sub(params.node.operator_cost(base_operator_cost));
let operator_base_reward = reward.reward.min(params.node.operator_cost()); let operator_base_reward = reward
.reward
.min(params.node.operator_cost(base_operator_cost));
// Div by zero checked above // Div by zero checked above
let operator_reward = (self.profit_margin() let operator_reward = (self.profit_margin()
+ (ONE - self.profit_margin()) * reward.lambda / reward.sigma) + (ONE - self.profit_margin()) * reward.lambda / reward.sigma)
@@ -521,11 +526,16 @@ impl MixNodeBond {
} }
} }
pub fn reward_delegation(&self, delegation_amount: Uint128, params: &RewardParams) -> u128 { pub fn reward_delegation(
&self,
delegation_amount: Uint128,
params: &RewardParams,
base_operator_cost: u64,
) -> u128 {
let reward_params = DelegatorRewardParams::new( let reward_params = DelegatorRewardParams::new(
self.sigma(params), self.sigma(params),
self.profit_margin(), self.profit_margin(),
self.node_profit(params), self.node_profit(params, base_operator_cost),
params.to_owned(), params.to_owned(),
); );
reward_params.determine_delegation_reward(delegation_amount) reward_params.determine_delegation_reward(delegation_amount)
@@ -635,6 +645,12 @@ pub struct MixOwnershipResponse {
pub mixnode: Option<MixNodeBond>, pub mixnode: Option<MixNodeBond>,
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
pub struct MixnodeBondResponse {
pub identity: IdentityKey,
pub mixnode: Option<MixNodeBond>,
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@@ -115,6 +115,7 @@ pub enum ExecuteMsg {
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum QueryMsg { pub enum QueryMsg {
GetCurrentOperatorCost {},
GetRewardingValidatorAddress {}, GetRewardingValidatorAddress {},
GetAllDelegationKeys {}, GetAllDelegationKeys {},
DebugGetAllDelegationValues {}, DebugGetAllDelegationValues {},
@@ -133,6 +134,12 @@ pub enum QueryMsg {
OwnsGateway { OwnsGateway {
address: String, address: String,
}, },
GetMixnodeBond {
identity: IdentityKey,
},
GetGatewayBond {
identity: IdentityKey,
},
StateParams {}, StateParams {},
// gets all [paged] delegations associated with particular mixnode // gets all [paged] delegations associated with particular mixnode
GetMixnodeDelegations { GetMixnodeDelegations {
@@ -159,6 +166,7 @@ pub enum QueryMsg {
LayerDistribution {}, LayerDistribution {},
GetRewardPool {}, GetRewardPool {},
GetCirculatingSupply {}, GetCirculatingSupply {},
GetStakingSupply {},
GetIntervalRewardPercent {}, GetIntervalRewardPercent {},
GetSybilResistancePercent {}, GetSybilResistancePercent {},
GetActiveSetWorkFactor {}, GetActiveSetWorkFactor {},
@@ -1,7 +1,6 @@
use crate::{error::MixnetContractError, mixnode::StoredNodeRewardResult, ONE, U128}; use crate::{error::MixnetContractError, mixnode::StoredNodeRewardResult, ONE, U128};
use az::CheckedCast; use az::CheckedCast;
use cosmwasm_std::Uint128; use cosmwasm_std::Uint128;
use network_defaults::DEFAULT_OPERATOR_INTERVAL_COST;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -41,19 +40,23 @@ impl NodeEpochRewards {
self.result.reward() self.result.reward()
} }
pub fn operator_cost(&self) -> U128 { pub fn operator_cost(&self, base_operator_cost: u64) -> U128 {
self.params.operator_cost() self.params.operator_cost(base_operator_cost)
} }
pub fn node_profit(&self) -> U128 { pub fn node_profit(&self, base_operator_cost: u64) -> U128 {
let reward = U128::from_num(self.reward().u128()); let reward = U128::from_num(self.reward().u128());
// if operating cost is higher then the reward node profit is 0 // if operating cost is higher then the reward node profit is 0
reward.saturating_sub(self.operator_cost()) reward.saturating_sub(self.operator_cost(base_operator_cost))
} }
pub fn operator_reward(&self, profit_margin: U128) -> Result<Uint128, MixnetContractError> { pub fn operator_reward(
let reward = self.node_profit(); &self,
let operator_base_reward = reward.min(self.operator_cost()); profit_margin: U128,
base_operator_cost: u64,
) -> Result<Uint128, MixnetContractError> {
let reward = self.node_profit(base_operator_cost);
let operator_base_reward = reward.min(self.operator_cost(base_operator_cost));
let div_by_zero_check = if let Some(value) = self.lambda().checked_div(self.sigma()) { let div_by_zero_check = if let Some(value) = self.lambda().checked_div(self.sigma()) {
value value
} else { } else {
@@ -74,6 +77,7 @@ impl NodeEpochRewards {
&self, &self,
delegation_amount: Uint128, delegation_amount: Uint128,
profit_margin: U128, profit_margin: U128,
base_operator_cost: u64,
epoch_reward_params: EpochRewardParams, epoch_reward_params: EpochRewardParams,
) -> Result<Uint128, MixnetContractError> { ) -> Result<Uint128, MixnetContractError> {
// change all values into their fixed representations // change all values into their fixed representations
@@ -89,7 +93,8 @@ impl NodeEpochRewards {
return Err(MixnetContractError::DivisionByZero); return Err(MixnetContractError::DivisionByZero);
}; };
let delegator_reward = (ONE - profit_margin) * check_div_by_zero * self.node_profit(); let delegator_reward =
(ONE - profit_margin) * check_div_by_zero * self.node_profit(base_operator_cost);
let reward = delegator_reward.max(U128::ZERO); let reward = delegator_reward.max(U128::ZERO);
if let Some(int_reward) = reward.checked_cast() { if let Some(int_reward) = reward.checked_cast() {
@@ -160,6 +165,14 @@ impl EpochRewardParams {
pub fn epoch_reward_pool(&self) -> u128 { pub fn epoch_reward_pool(&self) -> u128 {
self.epoch_reward_pool.u128() self.epoch_reward_pool.u128()
} }
pub fn sybil_resistance_percent(&self) -> u8 {
self.sybil_resistance_percent
}
pub fn active_set_work_factor(&self) -> u8 {
self.active_set_work_factor
}
} }
#[derive(Debug, Clone, JsonSchema, PartialEq, Serialize, Deserialize, Copy)] #[derive(Debug, Clone, JsonSchema, PartialEq, Serialize, Deserialize, Copy)]
@@ -178,8 +191,8 @@ impl NodeRewardParams {
} }
} }
pub fn operator_cost(&self) -> U128 { pub fn operator_cost(&self, base_operator_cost: u64) -> U128 {
self.performance() * U128::from_num(DEFAULT_OPERATOR_INTERVAL_COST) self.performance() * U128::from_num(base_operator_cost)
} }
pub fn uptime(&self) -> Uint128 { pub fn uptime(&self) -> Uint128 {
@@ -11,4 +11,4 @@ cw3 = { version = "0.13.1" }
cw4 = { version = "0.13.1" } cw4 = { version = "0.13.1" }
cosmwasm-std = "1.0.0" cosmwasm-std = "1.0.0"
schemars = "0.8" schemars = "0.8"
serde = { version = "1.0.103", default-features = false, features = ["derive"] } serde = { version = "1.0.103", default-features = false, features = ["derive"] }
@@ -1,6 +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
use config::defaults::DENOM; use config::defaults::MIX_DENOM;
use cosmwasm_std::{Coin, Timestamp}; use cosmwasm_std::{Coin, Timestamp};
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -11,7 +11,7 @@ pub mod events;
pub mod messages; pub mod messages;
pub fn one_ucoin() -> Coin { pub fn one_ucoin() -> Coin {
Coin::new(1, DENOM) Coin::new(1, MIX_DENOM.base)
} }
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))] #[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
@@ -1,4 +1,4 @@
use cosmwasm_std::{Coin, Timestamp}; use cosmwasm_std::{Coin, Timestamp, Uint128};
use mixnet_contract_common::{Gateway, IdentityKey, MixNode}; use mixnet_contract_common::{Gateway, IdentityKey, MixNode};
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -113,6 +113,9 @@ pub enum ExecuteMsg {
UpdateStakingAddress { UpdateStakingAddress {
to_address: Option<String>, to_address: Option<String>,
}, },
UpdateLockedPledgeCap {
amount: Uint128,
},
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
@@ -163,4 +166,5 @@ pub enum QueryMsg {
GetCurrentVestingPeriod { GetCurrentVestingPeriod {
address: String, address: String,
}, },
GetLockedPledgeCap {},
} }
+1 -1
View File
@@ -17,4 +17,4 @@ tokio = { version = "1.19.1", features = [ "rt-multi-thread", "net", "signal", "
[build-dependencies] [build-dependencies]
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] } sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] }
tokio = { version = "1.19.1", features = ["rt-multi-thread", "macros"] } tokio = { version = "1.19.1", features = ["rt-multi-thread", "macros"] }
+2 -1
View File
@@ -15,10 +15,11 @@ url = "2.2"
coconut-interface = { path = "../coconut-interface" } coconut-interface = { path = "../coconut-interface" }
crypto = { path = "../crypto", features = ["rand", "asymmetric", "symmetric", "hashing"] } crypto = { path = "../crypto", features = ["rand", "asymmetric", "symmetric", "hashing"] }
network-defaults = { path = "../network-defaults" } network-defaults = { path = "../network-defaults" }
validator-api-requests = { path = "../../validator-api/validator-api-requests" }
validator-client = { path = "../client-libs/validator-client" } validator-client = { path = "../client-libs/validator-client" }
[dev-dependencies] [dev-dependencies]
rand = "0.7.3" rand = "0.7.3"
[features] [features]
coconut = ["cosmrs"] coconut = ["cosmrs"]
+2 -2
View File
@@ -3,13 +3,13 @@
use coconut_interface::{ use coconut_interface::{
aggregate_signature_shares, aggregate_verification_keys, prove_bandwidth_credential, Attribute, aggregate_signature_shares, aggregate_verification_keys, prove_bandwidth_credential, Attribute,
BlindSignRequestBody, BlindedSignature, Credential, Parameters, Signature, SignatureShare, BlindedSignature, Credential, Parameters, Signature, SignatureShare, VerificationKey,
VerificationKey,
}; };
use crypto::asymmetric::encryption::PublicKey; use crypto::asymmetric::encryption::PublicKey;
use crypto::shared_key::recompute_shared_key; use crypto::shared_key::recompute_shared_key;
use crypto::symmetric::stream_cipher; use crypto::symmetric::stream_cipher;
use url::Url; use url::Url;
use validator_api_requests::coconut::BlindSignRequestBody;
use crate::coconut::bandwidth::{BandwidthVoucher, PRIVATE_ATTRIBUTES, PUBLIC_ATTRIBUTES}; use crate::coconut::bandwidth::{BandwidthVoucher, PRIVATE_ATTRIBUTES, PUBLIC_ATTRIBUTES};
use crate::coconut::params::{ use crate::coconut::params::{
+1 -1
View File
@@ -38,4 +38,4 @@ criterion = "0.3"
[[bench]] [[bench]]
name = "benchmarks" name = "benchmarks"
harness = false harness = false
+7
View File
@@ -458,6 +458,7 @@ mod tests {
} }
#[test] #[test]
#[ignore] // expensive test
fn share_decryption_20() { fn share_decryption_20() {
let dummy_seed = [1u8; 32]; let dummy_seed = [1u8; 32];
let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed); let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed);
@@ -487,6 +488,7 @@ mod tests {
} }
#[test] #[test]
#[ignore] // expensive test
fn share_encryption_under_nonzero_epoch() { fn share_encryption_under_nonzero_epoch() {
let dummy_seed = [1u8; 32]; let dummy_seed = [1u8; 32];
let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed); let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed);
@@ -557,6 +559,7 @@ mod tests {
} }
#[test] #[test]
#[ignore] // expensive test
fn update_and_decrypt_10() { fn update_and_decrypt_10() {
let dummy_seed = [1u8; 32]; let dummy_seed = [1u8; 32];
let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed); let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed);
@@ -581,6 +584,7 @@ mod tests {
} }
#[test] #[test]
#[ignore] // expensive test
fn reblinding_node_doesnt_affect_decryption() { fn reblinding_node_doesnt_affect_decryption() {
let dummy_seed = [1u8; 32]; let dummy_seed = [1u8; 32];
let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed); let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed);
@@ -623,6 +627,7 @@ mod tests {
} }
#[test] #[test]
#[ignore] // expensive test
fn ciphertext_integrity_check_passes_for_valid_data() { fn ciphertext_integrity_check_passes_for_valid_data() {
let params = setup(); let params = setup();
@@ -640,6 +645,7 @@ mod tests {
} }
#[test] #[test]
#[ignore] // expensive test
fn ciphertext_integrity_check_passes_fails_for_malformed_data() { fn ciphertext_integrity_check_passes_fails_for_malformed_data() {
let params = setup(); let params = setup();
@@ -668,6 +674,7 @@ mod tests {
} }
#[test] #[test]
#[ignore] // expensive test
fn ciphertext_integrity_check_passes_fails_for_wrong_epoch() { fn ciphertext_integrity_check_passes_fails_for_wrong_epoch() {
let params = setup(); let params = setup();
+4
View File
@@ -651,6 +651,7 @@ mod tests {
use rand_core::SeedableRng; use rand_core::SeedableRng;
#[test] #[test]
#[ignore] // expensive test
fn basic_coverage_nodes() { fn basic_coverage_nodes() {
// it's some basic test I've been performing when writing the update function, but figured // it's some basic test I've been performing when writing the update function, but figured
// might as well put it into a unit test. note that it doesn't check the entire structure, // might as well put it into a unit test. note that it doesn't check the entire structure,
@@ -761,6 +762,7 @@ mod tests {
} }
#[test] #[test]
#[ignore] // expensive test
fn updating_to_next_epoch() { fn updating_to_next_epoch() {
let params = setup(); let params = setup();
@@ -816,6 +818,7 @@ mod tests {
} }
#[test] #[test]
#[ignore] // expensive test
fn bte_node_roundtrip() { fn bte_node_roundtrip() {
let params = setup(); let params = setup();
@@ -839,6 +842,7 @@ mod tests {
} }
#[test] #[test]
#[ignore] // expensive test
fn decryption_key_node_roundtrip() { fn decryption_key_node_roundtrip() {
let params = setup(); let params = setup();
@@ -761,6 +761,7 @@ mod tests {
} }
#[test] #[test]
#[ignore] // expensive test
fn should_verify_a_valid_proof() { fn should_verify_a_valid_proof() {
let dummy_seed = [1u8; 32]; let dummy_seed = [1u8; 32];
let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed); let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed);
+3
View File
@@ -351,6 +351,7 @@ mod tests {
use rand_core::SeedableRng; use rand_core::SeedableRng;
#[test] #[test]
#[ignore] // expensive test
fn recovering_partial_verification_keys() { fn recovering_partial_verification_keys() {
// START OF SETUP // START OF SETUP
let dummy_seed = [42u8; 32]; let dummy_seed = [42u8; 32];
@@ -419,6 +420,7 @@ mod tests {
} }
#[test] #[test]
#[ignore] // expensive test
fn verifying_partial_verification_keys() { fn verifying_partial_verification_keys() {
let dummy_seed = [42u8; 32]; let dummy_seed = [42u8; 32];
let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed); let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed);
@@ -467,6 +469,7 @@ mod tests {
} }
#[test] #[test]
#[ignore] // expensive test
fn dealing_roundtrip() { fn dealing_roundtrip() {
let dummy_seed = [1u8; 32]; let dummy_seed = [1u8; 32];
let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed); let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed);
+3
View File
@@ -9,6 +9,7 @@ use rand_core::SeedableRng;
use std::collections::BTreeMap; use std::collections::BTreeMap;
#[test] #[test]
#[ignore] // expensive test
fn single_sender() { fn single_sender() {
// makes it easier to understand than `full_threshold_secret_sharing` // makes it easier to understand than `full_threshold_secret_sharing`
// and is a good stepping stone, because its everything each node will have to perform (from one point of view) // and is a good stepping stone, because its everything each node will have to perform (from one point of view)
@@ -66,6 +67,7 @@ fn single_sender() {
} }
#[test] #[test]
#[ignore] // expensive test
fn full_threshold_secret_sharing() { fn full_threshold_secret_sharing() {
let dummy_seed = [42u8; 32]; let dummy_seed = [42u8; 32];
let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed); let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed);
@@ -161,6 +163,7 @@ fn full_threshold_secret_sharing() {
} }
#[test] #[test]
#[ignore] // expensive test
fn full_threshold_secret_resharing() { fn full_threshold_secret_resharing() {
let dummy_seed = [42u8; 32]; let dummy_seed = [42u8; 32];
let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed); let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed);
+112 -35
View File
@@ -1,13 +1,12 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::{
DefaultNetworkDetails, DenomDetailsOwned, NymNetworkDetails, ValidatorDetails,
MAINNET_DEFAULTS, QA_DEFAULTS, SANDBOX_DEFAULTS,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{collections::HashMap, fmt, str::FromStr}; use std::{collections::HashMap, fmt, str::FromStr};
use crate::{
DefaultNetworkDetails, ValidatorDetails, MAINNET_DEFAULTS, QA_DEFAULTS, SANDBOX_DEFAULTS,
};
use thiserror::Error; use thiserror::Error;
#[derive(Error, Debug)] #[derive(Error, Debug)]
@@ -16,56 +15,95 @@ pub enum NetworkDefaultsError {
MalformedNetworkProvided(String), MalformedNetworkProvided(String),
} }
#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] // the reason for allowing it is that this is just a temporary solution
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum Network { pub enum Network {
QA, QA,
SANDBOX, SANDBOX,
MAINNET, MAINNET,
CUSTOM { details: NymNetworkDetails },
} }
impl Network { impl Network {
fn details(&self) -> &DefaultNetworkDetails<'_> { pub fn new_custom(details: NymNetworkDetails) -> Self {
Network::CUSTOM { details }
}
pub fn details(&self) -> NymNetworkDetails {
match self { match self {
Self::QA => &QA_DEFAULTS, Self::QA => (&*QA_DEFAULTS).into(),
Self::SANDBOX => &SANDBOX_DEFAULTS, Self::SANDBOX => (&*SANDBOX_DEFAULTS).into(),
Self::MAINNET => &MAINNET_DEFAULTS, Self::MAINNET => (&*MAINNET_DEFAULTS).into(),
// I dislike the clone here, but for compatibility reasons we cannot define other networks with `NymNetworkDetails` directly yet
Self::CUSTOM { details } => details.clone(),
} }
} }
pub fn bech32_prefix(&self) -> &str { pub fn bech32_prefix(&self) -> String {
self.details().bech32_prefix self.details().chain_details.bech32_account_prefix
} }
pub fn denom(&self) -> &str { pub fn mix_denom(&self) -> DenomDetailsOwned {
self.details().denom self.details().chain_details.mix_denom
} }
pub fn mixnet_contract_address(&self) -> &str { pub fn stake_denom(&self) -> DenomDetailsOwned {
self.details().mixnet_contract_address self.details().chain_details.stake_denom
} }
pub fn vesting_contract_address(&self) -> &str { pub fn base_mix_denom(&self) -> String {
self.details().vesting_contract_address self.details().chain_details.mix_denom.base
} }
pub fn bandwidth_claim_contract_address(&self) -> &str { pub fn base_stake_denom(&self) -> String {
self.details().bandwidth_claim_contract_address self.details().chain_details.stake_denom.base
} }
pub fn coconut_bandwidth_contract_address(&self) -> &str { pub fn mixnet_contract_address(&self) -> Option<String> {
self.details().coconut_bandwidth_contract_address self.details().contracts.mixnet_contract_address
} }
pub fn multisig_contract_address(&self) -> &str { pub fn vesting_contract_address(&self) -> Option<String> {
self.details().multisig_contract_address self.details().contracts.vesting_contract_address
} }
pub fn bandwidth_claim_contract_address(&self) -> Option<String> {
self.details().contracts.bandwidth_claim_contract_address
}
pub fn coconut_bandwidth_contract_address(&self) -> Option<String> {
self.details().contracts.coconut_bandwidth_contract_address
}
pub fn multisig_contract_address(&self) -> Option<String> {
self.details().contracts.multisig_contract_address
}
pub fn validators(&self) -> Vec<ValidatorDetails> {
self.details().endpoints
}
// only used in mixnet contract tests, but I don't want to be messing with that code now
pub fn rewarding_validator_address(&self) -> &str { pub fn rewarding_validator_address(&self) -> &str {
self.details().rewarding_validator_address match self {
Network::QA => crate::qa::REWARDING_VALIDATOR_ADDRESS,
Network::SANDBOX => crate::sandbox::REWARDING_VALIDATOR_ADDRESS,
Network::MAINNET => crate::mainnet::REWARDING_VALIDATOR_ADDRESS,
Network::CUSTOM { .. } => {
panic!("rewarding validator address is unavailable for a custom network")
}
}
} }
pub fn validators(&self) -> impl Iterator<Item = &ValidatorDetails> { // this should be handled differently, but I don't want to break compatibility
self.details().validators.iter() pub fn statistics_service_url(&self) -> &str {
match self {
Network::MAINNET => crate::mainnet::STATISTICS_SERVICE_DOMAIN_ADDRESS,
_ => {
panic!("statistics service url is only available for mainnet!")
}
}
} }
} }
@@ -90,6 +128,7 @@ impl fmt::Display for Network {
Network::QA => f.write_str("QA"), Network::QA => f.write_str("QA"),
Network::SANDBOX => f.write_str("Sandbox"), Network::SANDBOX => f.write_str("Sandbox"),
Network::MAINNET => f.write_str("Mainnet"), Network::MAINNET => f.write_str("Mainnet"),
Network::CUSTOM { .. } => f.write_str("Custom"),
} }
} }
} }
@@ -97,26 +136,61 @@ impl fmt::Display for Network {
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct NetworkDetails { pub struct NetworkDetails {
bech32_prefix: String, bech32_prefix: String,
denom: String, mix_denom: DenomDetailsOwned,
stake_denom: DenomDetailsOwned,
mixnet_contract_address: String, mixnet_contract_address: String,
vesting_contract_address: String, vesting_contract_address: String,
bandwidth_claim_contract_address: String, bandwidth_claim_contract_address: String,
statistics_service_url: String,
validators: Vec<ValidatorDetails>, validators: Vec<ValidatorDetails>,
} }
impl From<&DefaultNetworkDetails<'_>> for NetworkDetails { impl From<&DefaultNetworkDetails> for NetworkDetails {
fn from(details: &DefaultNetworkDetails<'_>) -> Self { fn from(details: &DefaultNetworkDetails) -> Self {
NetworkDetails { NetworkDetails {
bech32_prefix: details.bech32_prefix.into(), bech32_prefix: details.bech32_prefix.into(),
denom: details.denom.into(), mix_denom: details.mix_denom.into(),
stake_denom: details.stake_denom.into(),
mixnet_contract_address: details.mixnet_contract_address.into(), mixnet_contract_address: details.mixnet_contract_address.into(),
vesting_contract_address: details.vesting_contract_address.into(), vesting_contract_address: details.vesting_contract_address.into(),
bandwidth_claim_contract_address: details.bandwidth_claim_contract_address.into(), bandwidth_claim_contract_address: details.bandwidth_claim_contract_address.into(),
statistics_service_url: details.statistics_service_url.into(),
validators: details.validators.clone(), validators: details.validators.clone(),
} }
} }
} }
// this also has to exist for compatibility reasons since I don't want to be touching the wallet now
impl From<NymNetworkDetails> for NetworkDetails {
fn from(details: NymNetworkDetails) -> Self {
NetworkDetails {
bech32_prefix: details.chain_details.bech32_account_prefix,
mix_denom: details.chain_details.mix_denom,
stake_denom: details.chain_details.stake_denom,
mixnet_contract_address: details
.contracts
.mixnet_contract_address
.unwrap_or_default(),
vesting_contract_address: details
.contracts
.vesting_contract_address
.unwrap_or_default(),
bandwidth_claim_contract_address: details
.contracts
.bandwidth_claim_contract_address
.unwrap_or_default(),
statistics_service_url: "".to_string(),
validators: details.endpoints,
}
}
}
impl NetworkDetails {
pub fn base_mix_denom(&self) -> &str {
&self.mix_denom.base
}
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)] #[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
pub struct SupportedNetworks { pub struct SupportedNetworks {
networks: HashMap<Network, NetworkDetails>, networks: HashMap<Network, NetworkDetails>,
@@ -127,7 +201,10 @@ impl SupportedNetworks {
SupportedNetworks { SupportedNetworks {
networks: support networks: support
.into_iter() .into_iter()
.map(|n| (n, n.details().into())) .map(|n| {
let details = n.details().into();
(n, details)
})
.collect(), .collect(),
} }
} }
@@ -138,10 +215,10 @@ impl SupportedNetworks {
.map(|network_details| network_details.bech32_prefix.as_str()) .map(|network_details| network_details.bech32_prefix.as_str())
} }
pub fn denom(&self, network: Network) -> Option<&str> { pub fn base_mix_denom(&self, network: Network) -> Option<&str> {
self.networks self.networks
.get(&network) .get(&network)
.map(|network_details| network_details.denom.as_str()) .map(|network_details| network_details.base_mix_denom())
} }
pub fn mixnet_contract_address(&self, network: Network) -> Option<&str> { pub fn mixnet_contract_address(&self, network: Network) -> Option<&str> {
+261 -50
View File
@@ -17,105 +17,306 @@ pub mod sandbox;
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(network = "mainnet")] { if #[cfg(network = "mainnet")] {
pub const DEFAULT_NETWORK: all::Network = all::Network::MAINNET; pub const DEFAULT_NETWORK: all::Network = all::Network::MAINNET;
pub const DENOM: &str = mainnet::DENOM; pub const MIX_DENOM: DenomDetails = mainnet::MIX_DENOM;
pub const STAKE_DENOM: &str = mainnet::STAKE_DENOM; pub const STAKE_DENOM: DenomDetails = mainnet::STAKE_DENOM;
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_CONTRACT_ADDRESS; pub const ETH_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_CONTRACT_ADDRESS;
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_ERC20_CONTRACT_ADDRESS; pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_ERC20_CONTRACT_ADDRESS;
} else if #[cfg(network = "qa")] { } else if #[cfg(network = "qa")] {
pub const DEFAULT_NETWORK: all::Network = all::Network::QA; pub const DEFAULT_NETWORK: all::Network = all::Network::QA;
pub const DENOM: &str = qa::DENOM; pub const MIX_DENOM: DenomDetails = qa::MIX_DENOM;
pub const STAKE_DENOM: &str = qa::STAKE_DENOM; pub const STAKE_DENOM: DenomDetails = qa::STAKE_DENOM;
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = qa::_ETH_CONTRACT_ADDRESS; pub const ETH_CONTRACT_ADDRESS: [u8; 20] = qa::_ETH_CONTRACT_ADDRESS;
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = qa::_ETH_ERC20_CONTRACT_ADDRESS; pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = qa::_ETH_ERC20_CONTRACT_ADDRESS;
} else if #[cfg(network = "sandbox")] { } else if #[cfg(network = "sandbox")] {
pub const DEFAULT_NETWORK: all::Network = all::Network::SANDBOX; pub const DEFAULT_NETWORK: all::Network = all::Network::SANDBOX;
pub const DENOM: &str = sandbox::DENOM; pub const MIX_DENOM: DenomDetails = sandbox::MIX_DENOM;
pub const STAKE_DENOM: &str = sandbox::STAKE_DENOM; pub const STAKE_DENOM: DenomDetails = sandbox::STAKE_DENOM;
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = sandbox::_ETH_CONTRACT_ADDRESS; pub const ETH_CONTRACT_ADDRESS: [u8; 20] = sandbox::_ETH_CONTRACT_ADDRESS;
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = sandbox::_ETH_ERC20_CONTRACT_ADDRESS; pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = sandbox::_ETH_ERC20_CONTRACT_ADDRESS;
} }
} }
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct ChainDetails {
pub bech32_account_prefix: String,
pub mix_denom: DenomDetailsOwned,
pub stake_denom: DenomDetailsOwned,
}
// by default we assume the same defaults as mainnet, i.e. same prefixes and denoms
impl Default for ChainDetails {
fn default() -> Self {
ChainDetails {
bech32_account_prefix: mainnet::BECH32_PREFIX.into(),
mix_denom: mainnet::MIX_DENOM.into(),
stake_denom: mainnet::STAKE_DENOM.into(),
}
}
}
#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct NymContracts {
pub mixnet_contract_address: Option<String>,
pub vesting_contract_address: Option<String>,
pub bandwidth_claim_contract_address: Option<String>,
pub coconut_bandwidth_contract_address: Option<String>,
pub multisig_contract_address: Option<String>,
}
// I wanted to use the simpler `NetworkDetails` name, but there's a clash
// with `NetworkDetails` defined in all.rs...
#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct NymNetworkDetails {
pub chain_details: ChainDetails,
pub endpoints: Vec<ValidatorDetails>,
pub contracts: NymContracts,
}
impl NymNetworkDetails {
pub fn new() -> Self {
NymNetworkDetails::default()
}
pub fn new_qa() -> Self {
(&*QA_DEFAULTS).into()
}
pub fn new_sandbox() -> Self {
(&*SANDBOX_DEFAULTS).into()
}
pub fn new_mainnet() -> Self {
(&*MAINNET_DEFAULTS).into()
}
pub fn current_default() -> Self {
// backwards compatibility reasons
DEFAULT_NETWORK.details()
}
pub fn with_bech32_account_prefix<S: Into<String>>(mut self, prefix: S) -> Self {
self.chain_details.bech32_account_prefix = prefix.into();
self
}
pub fn with_mix_denom(mut self, mix_denom: DenomDetailsOwned) -> Self {
self.chain_details.mix_denom = mix_denom;
self
}
pub fn with_stake_denom(mut self, stake_denom: DenomDetailsOwned) -> Self {
self.chain_details.stake_denom = stake_denom;
self
}
pub fn with_base_mix_denom<S: Into<String>>(mut self, base_mix_denom: S) -> Self {
self.chain_details.mix_denom = DenomDetailsOwned::base_only(base_mix_denom.into());
self
}
pub fn with_base_stake_denom<S: Into<String>>(mut self, base_stake_denom: S) -> Self {
self.chain_details.stake_denom = DenomDetailsOwned::base_only(base_stake_denom.into());
self
}
pub fn with_validator_endpoint(mut self, endpoint: ValidatorDetails) -> Self {
self.endpoints.push(endpoint);
self
}
pub fn with_mixnet_contract<S: Into<String>>(mut self, contract: Option<S>) -> Self {
self.contracts.mixnet_contract_address = contract.map(Into::into);
self
}
pub fn with_vesting_contract<S: Into<String>>(mut self, contract: Option<S>) -> Self {
self.contracts.vesting_contract_address = contract.map(Into::into);
self
}
pub fn with_bandwidth_claim_contract<S: Into<String>>(mut self, contract: Option<S>) -> Self {
self.contracts.bandwidth_claim_contract_address = contract.map(Into::into);
self
}
pub fn with_coconut_bandwidth_contract<S: Into<String>>(mut self, contract: Option<S>) -> Self {
self.contracts.coconut_bandwidth_contract_address = contract.map(Into::into);
self
}
pub fn with_multisig_contract<S: Into<String>>(mut self, contract: Option<S>) -> Self {
self.contracts.multisig_contract_address = contract.map(Into::into);
self
}
}
// This conversion only exists for convenience reasons until
// we can completely phase out `DefaultNetworkDetails`
impl<'a> From<&'a DefaultNetworkDetails> for NymNetworkDetails {
fn from(details: &'a DefaultNetworkDetails) -> Self {
fn parse_optional_str(raw: &str) -> Option<String> {
if raw.is_empty() {
None
} else {
Some(raw.into())
}
}
NymNetworkDetails {
chain_details: ChainDetails {
bech32_account_prefix: details.bech32_prefix.into(),
mix_denom: details.mix_denom.into(),
stake_denom: details.stake_denom.into(),
},
endpoints: details.validators.clone(),
contracts: NymContracts {
mixnet_contract_address: parse_optional_str(details.mixnet_contract_address),
vesting_contract_address: parse_optional_str(details.vesting_contract_address),
bandwidth_claim_contract_address: parse_optional_str(
details.bandwidth_claim_contract_address,
),
coconut_bandwidth_contract_address: parse_optional_str(
details.coconut_bandwidth_contract_address,
),
multisig_contract_address: parse_optional_str(details.multisig_contract_address),
},
}
}
}
// Since these are lazily constructed, we can afford to switch some of them to stronger types in the // Since these are lazily constructed, we can afford to switch some of them to stronger types in the
// future. If we do this, and also get rid of the references we could potentially unify with // future. If we do this, and also get rid of the references we could potentially unify with
// `NetworkDetails`. // `NetworkDetails`.
#[derive(Debug)] pub struct DefaultNetworkDetails {
pub struct DefaultNetworkDetails<'a> { bech32_prefix: &'static str,
bech32_prefix: &'a str, mix_denom: DenomDetails,
denom: &'a str, stake_denom: DenomDetails,
mixnet_contract_address: &'a str, mixnet_contract_address: &'static str,
vesting_contract_address: &'a str, vesting_contract_address: &'static str,
bandwidth_claim_contract_address: &'a str, bandwidth_claim_contract_address: &'static str,
coconut_bandwidth_contract_address: &'a str, coconut_bandwidth_contract_address: &'static str,
multisig_contract_address: &'a str, multisig_contract_address: &'static str,
rewarding_validator_address: &'a str, #[allow(dead_code)]
rewarding_validator_address: &'static str,
statistics_service_url: &'static str,
validators: Vec<ValidatorDetails>, validators: Vec<ValidatorDetails>,
} }
static MAINNET_DEFAULTS: Lazy<DefaultNetworkDetails<'static>> = static MAINNET_DEFAULTS: Lazy<DefaultNetworkDetails> = Lazy::new(|| DefaultNetworkDetails {
Lazy::new(|| DefaultNetworkDetails { bech32_prefix: mainnet::BECH32_PREFIX,
bech32_prefix: mainnet::BECH32_PREFIX, mix_denom: mainnet::MIX_DENOM,
denom: mainnet::DENOM, stake_denom: mainnet::STAKE_DENOM,
mixnet_contract_address: mainnet::MIXNET_CONTRACT_ADDRESS, mixnet_contract_address: mainnet::MIXNET_CONTRACT_ADDRESS,
vesting_contract_address: mainnet::VESTING_CONTRACT_ADDRESS, vesting_contract_address: mainnet::VESTING_CONTRACT_ADDRESS,
bandwidth_claim_contract_address: mainnet::BANDWIDTH_CLAIM_CONTRACT_ADDRESS, bandwidth_claim_contract_address: mainnet::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
coconut_bandwidth_contract_address: mainnet::COCONUT_BANDWIDTH_CONTRACT_ADDRESS, coconut_bandwidth_contract_address: mainnet::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
multisig_contract_address: mainnet::MULTISIG_CONTRACT_ADDRESS, multisig_contract_address: mainnet::MULTISIG_CONTRACT_ADDRESS,
rewarding_validator_address: mainnet::REWARDING_VALIDATOR_ADDRESS, rewarding_validator_address: mainnet::REWARDING_VALIDATOR_ADDRESS,
validators: mainnet::validators(), statistics_service_url: mainnet::STATISTICS_SERVICE_DOMAIN_ADDRESS,
}); validators: mainnet::validators(),
});
static SANDBOX_DEFAULTS: Lazy<DefaultNetworkDetails<'static>> = static SANDBOX_DEFAULTS: Lazy<DefaultNetworkDetails> = Lazy::new(|| DefaultNetworkDetails {
Lazy::new(|| DefaultNetworkDetails { bech32_prefix: sandbox::BECH32_PREFIX,
bech32_prefix: sandbox::BECH32_PREFIX, mix_denom: sandbox::MIX_DENOM,
denom: sandbox::DENOM, stake_denom: sandbox::STAKE_DENOM,
mixnet_contract_address: sandbox::MIXNET_CONTRACT_ADDRESS, mixnet_contract_address: sandbox::MIXNET_CONTRACT_ADDRESS,
vesting_contract_address: sandbox::VESTING_CONTRACT_ADDRESS, vesting_contract_address: sandbox::VESTING_CONTRACT_ADDRESS,
bandwidth_claim_contract_address: sandbox::BANDWIDTH_CLAIM_CONTRACT_ADDRESS, bandwidth_claim_contract_address: sandbox::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
coconut_bandwidth_contract_address: sandbox::COCONUT_BANDWIDTH_CONTRACT_ADDRESS, coconut_bandwidth_contract_address: sandbox::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
multisig_contract_address: sandbox::MULTISIG_CONTRACT_ADDRESS, multisig_contract_address: sandbox::MULTISIG_CONTRACT_ADDRESS,
rewarding_validator_address: sandbox::REWARDING_VALIDATOR_ADDRESS, rewarding_validator_address: sandbox::REWARDING_VALIDATOR_ADDRESS,
validators: sandbox::validators(), statistics_service_url: sandbox::STATISTICS_SERVICE_DOMAIN_ADDRESS,
}); validators: sandbox::validators(),
});
static QA_DEFAULTS: Lazy<DefaultNetworkDetails<'static>> = Lazy::new(|| DefaultNetworkDetails { static QA_DEFAULTS: Lazy<DefaultNetworkDetails> = Lazy::new(|| DefaultNetworkDetails {
bech32_prefix: qa::BECH32_PREFIX, bech32_prefix: qa::BECH32_PREFIX,
denom: qa::DENOM, mix_denom: qa::MIX_DENOM,
stake_denom: qa::STAKE_DENOM,
mixnet_contract_address: qa::MIXNET_CONTRACT_ADDRESS, mixnet_contract_address: qa::MIXNET_CONTRACT_ADDRESS,
vesting_contract_address: qa::VESTING_CONTRACT_ADDRESS, vesting_contract_address: qa::VESTING_CONTRACT_ADDRESS,
bandwidth_claim_contract_address: qa::BANDWIDTH_CLAIM_CONTRACT_ADDRESS, bandwidth_claim_contract_address: qa::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
coconut_bandwidth_contract_address: qa::COCONUT_BANDWIDTH_CONTRACT_ADDRESS, coconut_bandwidth_contract_address: qa::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
multisig_contract_address: qa::MULTISIG_CONTRACT_ADDRESS, multisig_contract_address: qa::MULTISIG_CONTRACT_ADDRESS,
rewarding_validator_address: qa::REWARDING_VALIDATOR_ADDRESS, rewarding_validator_address: qa::REWARDING_VALIDATOR_ADDRESS,
statistics_service_url: qa::STATISTICS_SERVICE_DOMAIN_ADDRESS,
validators: qa::validators(), validators: qa::validators(),
}); });
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct DenomDetails {
pub base: &'static str,
pub display: &'static str,
// i.e. display_amount * 10^display_exponent = base_amount
pub display_exponent: u32,
}
impl DenomDetails {
pub const fn new(base: &'static str, display: &'static str, display_exponent: u32) -> Self {
DenomDetails {
base,
display,
display_exponent,
}
}
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct DenomDetailsOwned {
pub base: String,
pub display: String,
// i.e. display_amount * 10^display_exponent = base_amount
pub display_exponent: u32,
}
impl From<DenomDetails> for DenomDetailsOwned {
fn from(details: DenomDetails) -> Self {
DenomDetailsOwned {
base: details.base.to_owned(),
display: details.display.to_owned(),
display_exponent: details.display_exponent,
}
}
}
impl DenomDetailsOwned {
pub fn base_only(base: String) -> Self {
DenomDetailsOwned {
base: base.clone(),
display: base,
display_exponent: 0,
}
}
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct ValidatorDetails { pub struct ValidatorDetails {
// it is assumed those values are always valid since they're being provided in our defaults file // it is assumed those values are always valid since they're being provided in our defaults file
pub nymd_url: String, pub nymd_url: String,
// Right now api_url is optional as we are not running the api reliably on all validators // Right now api_url is optional as we are not running the api reliably on all validators
// however, later on it should be a mandatory field // however, later on it should be a mandatory field
pub api_url: Option<String>, pub api_url: Option<String>,
// TODO: I'd argue this one should also have a field like `gas_price` since its a validator-specific setting
} }
impl ValidatorDetails { impl ValidatorDetails {
pub fn new(nymd_url: &str, api_url: Option<&str>) -> Self { pub fn new<S: Into<String>>(nymd_url: S, api_url: Option<S>) -> Self {
ValidatorDetails { ValidatorDetails {
nymd_url: nymd_url.to_string(), nymd_url: nymd_url.into(),
api_url: api_url.map(ToString::to_string), api_url: api_url.map(Into::into),
} }
} }
pub fn new_with_name(nymd_url: &str, api_url: Option<&str>) -> Self { pub fn new_nymd_only<S: Into<String>>(nymd_url: S) -> Self {
ValidatorDetails { ValidatorDetails {
nymd_url: nymd_url.to_string(), nymd_url: nymd_url.into(),
api_url: api_url.map(ToString::to_string), api_url: None,
} }
} }
@@ -132,9 +333,17 @@ impl ValidatorDetails {
} }
} }
pub fn default_statistics_service_url() -> Url {
DEFAULT_NETWORK
.statistics_service_url()
.parse()
.expect("the provided statistics service url is invalid!")
}
pub fn default_nymd_endpoints() -> Vec<Url> { pub fn default_nymd_endpoints() -> Vec<Url> {
DEFAULT_NETWORK DEFAULT_NETWORK
.validators() .validators()
.iter()
.map(ValidatorDetails::nymd_url) .map(ValidatorDetails::nymd_url)
.collect() .collect()
} }
@@ -142,6 +351,7 @@ pub fn default_nymd_endpoints() -> Vec<Url> {
pub fn default_api_endpoints() -> Vec<Url> { pub fn default_api_endpoints() -> Vec<Url> {
DEFAULT_NETWORK DEFAULT_NETWORK
.validators() .validators()
.iter()
.filter_map(ValidatorDetails::api_url) .filter_map(ValidatorDetails::api_url)
.collect() .collect()
} }
@@ -199,7 +409,8 @@ pub const VALIDATOR_API_VERSION: &str = "v1";
/// We'll be assuming a few more things, profit margin and cost function. Since we don't have relialable package measurement, we'll be using uptime. We'll also set the value of 1 Nym to 1 $, to be able to translate interval costs to Nyms. We'll also assume a cost of 40$ per interval(month), converting that to Nym at our 1$ rate translates to 40_000_000 uNyms /// We'll be assuming a few more things, profit margin and cost function. Since we don't have relialable package measurement, we'll be using uptime. We'll also set the value of 1 Nym to 1 $, to be able to translate interval costs to Nyms. We'll also assume a cost of 40$ per interval(month), converting that to Nym at our 1$ rate translates to 40_000_000 uNyms
// pub const DEFAULT_OPERATOR_INTERVAL_COST: u64 = 40_000_000; // 40$/(30 days) at 1 Nym == 1$ // pub const DEFAULT_OPERATOR_INTERVAL_COST: u64 = 40_000_000; // 40$/(30 days) at 1 Nym == 1$
pub const DEFAULT_OPERATOR_INTERVAL_COST: u64 = 55_556; // 40$/1hr at 1 Nym == 1$ // pub const DEFAULT_OPERATOR_INTERVAL_COST: u64 = 55_556; // 40$/1hr at 1 Nym == 1$
// pub const DEFAULT_OPERATOR_INTERVAL_COST: u64 = 9259; // 40$/1hr/6 at 1 Nym == 1$
// TODO: is there a way to get this from the chain // TODO: is there a way to get this from the chain
pub const TOTAL_SUPPLY: u128 = 1_000_000_000_000_000; pub const TOTAL_SUPPLY: u128 = 1_000_000_000_000_000;
+5 -3
View File
@@ -1,11 +1,12 @@
// 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 crate::ValidatorDetails; use crate::{DenomDetails, ValidatorDetails};
pub(crate) const BECH32_PREFIX: &str = "n"; pub(crate) const BECH32_PREFIX: &str = "n";
pub const DENOM: &str = "unym";
pub const STAKE_DENOM: &str = "unyx"; pub const MIX_DENOM: DenomDetails = DenomDetails::new("unym", "nym", 6);
pub const STAKE_DENOM: DenomDetails = DenomDetails::new("unyx", "nyx", 6);
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = pub(crate) const MIXNET_CONTRACT_ADDRESS: &str =
"n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g"; "n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g";
@@ -22,6 +23,7 @@ pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
hex_literal::hex!("0000000000000000000000000000000000000000"); hex_literal::hex!("0000000000000000000000000000000000000000");
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy"; pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy";
pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "http://mainnet-stats.nymte.ch:8090";
pub(crate) fn validators() -> Vec<ValidatorDetails> { pub(crate) fn validators() -> Vec<ValidatorDetails> {
vec![ValidatorDetails::new( vec![ValidatorDetails::new(
"https://rpc.nyx.nodes.guru/", "https://rpc.nyx.nodes.guru/",
+5 -3
View File
@@ -1,11 +1,12 @@
// 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 crate::ValidatorDetails; use crate::{DenomDetails, ValidatorDetails};
pub(crate) const BECH32_PREFIX: &str = "n"; pub(crate) const BECH32_PREFIX: &str = "n";
pub const DENOM: &str = "unym";
pub const STAKE_DENOM: &str = "unyx"; pub const MIX_DENOM: DenomDetails = DenomDetails::new("unym", "nym", 6);
pub const STAKE_DENOM: DenomDetails = DenomDetails::new("unyx", "nyx", 6);
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = pub(crate) const MIXNET_CONTRACT_ADDRESS: &str =
"n1suhgf5svhu4usrurvxzlgn54ksxmn8gljarjtxqnapv8kjnp4nrsd3qaep"; "n1suhgf5svhu4usrurvxzlgn54ksxmn8gljarjtxqnapv8kjnp4nrsd3qaep";
@@ -22,6 +23,7 @@ pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
hex_literal::hex!("0000000000000000000000000000000000000000"); hex_literal::hex!("0000000000000000000000000000000000000000");
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n1tfzd4qz3a45u8p4mr5zmzv66457uwjgcl05jdq"; pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n1tfzd4qz3a45u8p4mr5zmzv66457uwjgcl05jdq";
pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "";
pub(crate) fn validators() -> Vec<ValidatorDetails> { pub(crate) fn validators() -> Vec<ValidatorDetails> {
vec![ValidatorDetails::new( vec![ValidatorDetails::new(
"https://qa-validator.nymtech.net", "https://qa-validator.nymtech.net",
+5 -3
View File
@@ -1,11 +1,12 @@
// 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 crate::ValidatorDetails; use crate::{DenomDetails, ValidatorDetails};
pub(crate) const BECH32_PREFIX: &str = "nymt"; pub(crate) const BECH32_PREFIX: &str = "nymt";
pub const DENOM: &str = "unymt";
pub const STAKE_DENOM: &str = "unyxt"; pub const MIX_DENOM: DenomDetails = DenomDetails::new("unymt", "nymt", 6);
pub const STAKE_DENOM: DenomDetails = DenomDetails::new("unyxt", "nyxt", 6);
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "nymt1ghd753shjuwexxywmgs4xz7x2q732vcnstz02j"; pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "nymt1ghd753shjuwexxywmgs4xz7x2q732vcnstz02j";
pub(crate) const VESTING_CONTRACT_ADDRESS: &str = "nymt14ejqjyq8um4p3xfqj74yld5waqljf88fn549lh"; pub(crate) const VESTING_CONTRACT_ADDRESS: &str = "nymt14ejqjyq8um4p3xfqj74yld5waqljf88fn549lh";
@@ -20,6 +21,7 @@ pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
hex_literal::hex!("E8883BAeF3869e14E4823F46662e81D4F7d2A81F"); hex_literal::hex!("E8883BAeF3869e14E4823F46662e81D4F7d2A81F");
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "nymt1jh0s6qu6tuw9ut438836mmn7f3f2wencrnmdj4"; pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "nymt1jh0s6qu6tuw9ut438836mmn7f3f2wencrnmdj4";
pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "";
pub(crate) fn validators() -> Vec<ValidatorDetails> { pub(crate) fn validators() -> Vec<ValidatorDetails> {
vec![ValidatorDetails::new( vec![ValidatorDetails::new(
"https://sandbox-validator.nymtech.net", "https://sandbox-validator.nymtech.net",
+1 -1
View File
@@ -12,4 +12,4 @@ nymsphinx-types = { path = "../types" } # we need to be able to refer to some ty
serde = "1.0" # implementing serialization/deserialization for some types, like `Recipient` serde = "1.0" # implementing serialization/deserialization for some types, like `Recipient`
[dev-dependencies] [dev-dependencies]
rand = "0.7" rand = "0.7"
+1 -1
View File
@@ -16,4 +16,4 @@ nymsphinx-chunking = { path = "../chunking" }
nymsphinx-params = { path = "../params" } nymsphinx-params = { path = "../params" }
nymsphinx-forwarding = { path = "../forwarding" } nymsphinx-forwarding = { path = "../forwarding" }
nymsphinx-types = { path = "../types" } nymsphinx-types = { path = "../types" }
topology = { path = "../../topology" } topology = { path = "../../topology" }
+1 -1
View File
@@ -8,4 +8,4 @@ edition = "2021"
[dependencies] [dependencies]
crypto = { path = "../../crypto", features = ["hashing", "symmetric"] } crypto = { path = "../../crypto", features = ["hashing", "symmetric"] }
nymsphinx-types = { path = "../types" } nymsphinx-types = { path = "../types" }
+1 -1
View File
@@ -18,4 +18,4 @@ socks5-requests = { path = "../requests" }
ordered-buffer = { path = "../ordered-buffer" } ordered-buffer = { path = "../ordered-buffer" }
[dev-dependencies] [dev-dependencies]
tokio-test = "0.4.2" tokio-test = "0.4.2"
+9 -3
View File
@@ -2,14 +2,20 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
[package] [package]
name = "statistics" name = "statistics-common"
version = "1.0.1" version = "1.0.1"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
reqwest = "0.11" async-trait = { version = "0.1.51" }
log = "0.4"
reqwest = { version = "0.11", features = ["json"] }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1" serde_json = "1"
thiserror = "1" sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "chrono"]}
thiserror = "1"
tokio = { version = "1.19.1", features = [ "time" ] }
network-defaults = { path = "../network-defaults" }
+17 -1
View File
@@ -10,13 +10,29 @@ pub const DEFAULT_STATISTICS_SERVICE_PORT: u16 = 8090;
pub const STATISTICS_SERVICE_VERSION: &str = "/v1"; pub const STATISTICS_SERVICE_VERSION: &str = "/v1";
pub const STATISTICS_SERVICE_API_STATISTICS: &str = "statistic"; pub const STATISTICS_SERVICE_API_STATISTICS: &str = "statistic";
pub async fn build_and_send_statistics_request(
msg: StatsMessage,
url: String,
) -> Result<(), StatsError> {
reqwest::Client::new()
.post(format!(
"{}{}/{}",
url, STATISTICS_SERVICE_VERSION, STATISTICS_SERVICE_API_STATISTICS
))
.json(&msg)
.send()
.await?;
Ok(())
}
pub fn build_statistics_request_bytes(msg: StatsMessage) -> Result<Vec<u8>, StatsError> { pub fn build_statistics_request_bytes(msg: StatsMessage) -> Result<Vec<u8>, StatsError> {
let json_msg = msg.to_json()?; let json_msg = msg.to_json()?;
let req = reqwest::Request::new( let req = reqwest::Request::new(
reqwest::Method::POST, reqwest::Method::POST,
reqwest::Url::parse(&format!( reqwest::Url::parse(&format!(
"http://{}:{}/{}/{}", "http://{}:{}{}/{}",
DEFAULT_STATISTICS_SERVICE_ADDRESS, DEFAULT_STATISTICS_SERVICE_ADDRESS,
DEFAULT_STATISTICS_SERVICE_PORT, DEFAULT_STATISTICS_SERVICE_PORT,
STATISTICS_SERVICE_VERSION, STATISTICS_SERVICE_VERSION,
+57
View File
@@ -0,0 +1,57 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use async_trait::async_trait;
use log::error;
use sqlx::types::chrono::{DateTime, Utc};
use std::time::Duration;
use tokio::time;
use crate::error::StatsError;
use crate::StatsMessage;
const STATISTICS_TIMER_INTERVAL: Duration = Duration::from_secs(60);
#[async_trait]
pub trait StatisticsCollector {
async fn create_stats_message(
&self,
interval: Duration,
timestamp: DateTime<Utc>,
) -> StatsMessage;
async fn send_stats_message(&self, stats_message: StatsMessage) -> Result<(), StatsError>;
async fn reset_stats(&mut self);
}
pub struct StatisticsSender<T: StatisticsCollector> {
collector: T,
interval: Duration,
timestamp: DateTime<Utc>,
}
impl<T: StatisticsCollector> StatisticsSender<T> {
pub fn new(collector: T) -> Self {
StatisticsSender {
collector,
interval: STATISTICS_TIMER_INTERVAL,
timestamp: Utc::now(),
}
}
pub async fn run(&mut self) {
let mut interval = time::interval(self.interval);
loop {
interval.tick().await;
let stats_message = self
.collector
.create_stats_message(self.interval, self.timestamp)
.await;
if let Err(e) = self.collector.send_stats_message(stats_message).await {
error!("Statistics not sent: {}", e);
}
self.collector.reset_stats().await;
self.timestamp = Utc::now();
}
}
}
+3
View File
@@ -7,4 +7,7 @@ use thiserror::Error;
pub enum StatsError { pub enum StatsError {
#[error("Serde JSON error: {0}")] #[error("Serde JSON error: {0}")]
SerdeJsonError(#[from] serde_json::Error), SerdeJsonError(#[from] serde_json::Error),
#[error("Reqwest error: {0}")]
ReqwestError(#[from] reqwest::Error),
} }
+23 -1
View File
@@ -6,11 +6,12 @@ use serde::{Deserialize, Serialize};
use error::StatsError; use error::StatsError;
pub mod api; pub mod api;
pub mod collector;
pub mod error; pub mod error;
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub struct StatsMessage { pub struct StatsMessage {
pub stats_data: Vec<StatsServiceData>, pub stats_data: Vec<StatsData>,
pub interval_seconds: u32, pub interval_seconds: u32,
pub timestamp: String, pub timestamp: String,
} }
@@ -25,6 +26,27 @@ impl StatsMessage {
} }
} }
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum StatsData {
Service(StatsServiceData),
Gateway(StatsGatewayData),
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct StatsGatewayData {
pub gateway_id: String,
pub inbox_count: u32,
}
impl StatsGatewayData {
pub fn new(gateway_id: String, inbox_count: u32) -> Self {
StatsGatewayData {
gateway_id,
inbox_count,
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub struct StatsServiceData { pub struct StatsServiceData {
pub requested_service: String, pub requested_service: String,
+6 -2
View File
@@ -20,7 +20,7 @@ pub struct Delegation {
pub node_identity: String, pub node_identity: String,
pub amount: MajorCurrencyAmount, pub amount: MajorCurrencyAmount,
pub block_height: u64, pub block_height: u64,
pub proxy: Option<String>, // proxy address used to delegate the funds on behalf of anouther address pub proxy: Option<String>, // proxy address used to delegate the funds on behalf of another address
} }
impl TryFrom<MixnetContractDelegation> for Delegation { impl TryFrom<MixnetContractDelegation> for Delegation {
@@ -57,6 +57,7 @@ pub struct DelegationRecord {
pub amount: MajorCurrencyAmount, pub amount: MajorCurrencyAmount,
pub block_height: u64, pub block_height: u64,
pub delegated_on_iso_datetime: String, pub delegated_on_iso_datetime: String,
pub uses_vesting_contract_tokens: bool,
} }
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))] #[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
@@ -76,7 +77,7 @@ pub struct DelegationWithEverything {
pub profit_margin_percent: Option<u8>, pub profit_margin_percent: Option<u8>,
pub avg_uptime_percent: Option<u8>, pub avg_uptime_percent: Option<u8>,
pub stake_saturation: Option<f32>, pub stake_saturation: Option<f32>,
pub proxy: Option<String>, pub uses_vesting_contract_tokens: bool,
pub accumulated_rewards: Option<MajorCurrencyAmount>, pub accumulated_rewards: Option<MajorCurrencyAmount>,
pub pending_events: Vec<DelegationEvent>, pub pending_events: Vec<DelegationEvent>,
pub history: Vec<DelegationRecord>, pub history: Vec<DelegationRecord>,
@@ -144,6 +145,7 @@ pub struct DelegationEvent {
pub address: String, pub address: String,
pub amount: Option<MajorCurrencyAmount>, pub amount: Option<MajorCurrencyAmount>,
pub block_height: u64, pub block_height: u64,
pub proxy: Option<String>,
} }
impl TryFrom<ContractDelegationEvent> for DelegationEvent { impl TryFrom<ContractDelegationEvent> for DelegationEvent {
@@ -159,6 +161,7 @@ impl TryFrom<ContractDelegationEvent> for DelegationEvent {
address: delegation.owner.into_string(), address: delegation.owner.into_string(),
node_identity: delegation.node_identity, node_identity: delegation.node_identity,
amount: Some(amount), amount: Some(amount),
proxy: delegation.proxy.map(|p| p.into_string()),
}) })
} }
ContractDelegationEvent::Undelegate(pending_undelegate) => Ok(DelegationEvent { ContractDelegationEvent::Undelegate(pending_undelegate) => Ok(DelegationEvent {
@@ -167,6 +170,7 @@ impl TryFrom<ContractDelegationEvent> for DelegationEvent {
address: pending_undelegate.delegate().into_string(), address: pending_undelegate.delegate().into_string(),
node_identity: pending_undelegate.mix_identity(), node_identity: pending_undelegate.mix_identity(),
amount: None, amount: None,
proxy: pending_undelegate.proxy().map(|p| p.into_string()),
}), }),
} }
} }
+3
View File
@@ -51,6 +51,8 @@ pub enum TypesError {
#[from] #[from]
source: cosmwasm_std::DecimalRangeExceeded, source: cosmwasm_std::DecimalRangeExceeded,
}, },
#[error("No validator API URL configured")]
NoValidatorApiUrlConfigured,
#[error("{0} is not a valid amount string")] #[error("{0} is not a valid amount string")]
InvalidAmount(String), InvalidAmount(String),
#[error("{0} is not a valid denomination string")] #[error("{0} is not a valid denomination string")]
@@ -78,6 +80,7 @@ impl From<ValidatorClientError> for TypesError {
ValidatorClientError::ValidatorAPIError { source } => source.into(), ValidatorClientError::ValidatorAPIError { source } => source.into(),
ValidatorClientError::MalformedUrlProvided(e) => e.into(), ValidatorClientError::MalformedUrlProvided(e) => e.into(),
ValidatorClientError::NymdError(e) => e.into(), ValidatorClientError::NymdError(e) => e.into(),
ValidatorClientError::NoAPIUrlAvailable => TypesError::NoValidatorApiUrlConfigured,
} }
} }
} }
+74 -8
View File
@@ -1,18 +1,84 @@
use crate::currency::MajorCurrencyAmount;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use validator_client::nymd::Fee; use validator_client::nymd::Fee;
use crate::currency::MajorCurrencyAmount; #[cfg(feature = "generate-ts")]
use ts_rs::{Dependency, TS};
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr(
feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/FeeDetails.ts")
)]
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FeeDetails { pub struct FeeDetails {
// expected to be used by the wallet in order to display detailed fee information to the user // expected to be used by the wallet in order to display detailed fee information to the user
pub amount: Option<MajorCurrencyAmount>, pub amount: Option<MajorCurrencyAmount>,
#[cfg_attr(feature = "generate-ts", ts(skip))]
pub fee: Fee, pub fee: Fee,
} }
#[cfg(feature = "generate-ts")]
impl TS for FeeDetails {
const EXPORT_TO: Option<&'static str> = Some("ts-packages/types/src/types/rust/FeeDetails.ts");
fn decl() -> String {
format!("type {} = {};", Self::name(), Self::inline())
}
fn name() -> String {
"FeeDetails".into()
}
fn inline() -> String {
"{ amount: MajorCurrencyAmount | null, fee: Fee }".into()
}
fn dependencies() -> Vec<Dependency> {
vec![
Dependency::from_ty::<MajorCurrencyAmount>()
.expect("TS was incorrectly defined on `CurrencyDenom`"),
Dependency::from_ty::<ts_type_helpers::Fee>()
.expect("TS was incorrectly defined on `ts_type_helpers::Fee`"),
]
}
fn transparent() -> bool {
false
}
}
// this should really be sealed and NEVER EVER used as "normal" types,
// but due to our typescript requirements, we have to expose it to generate
// the types...
#[cfg(feature = "generate-ts")]
pub mod ts_type_helpers {
use serde::{Deserialize, Serialize};
use validator_client::nymd::GasAdjustment;
#[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS)]
#[ts(export_to = "ts-packages/types/src/types/rust/Fee.ts")]
pub enum Fee {
Manual(CosmosFee),
Auto(Option<GasAdjustment>),
}
#[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS)]
#[ts(export_to = "ts-packages/types/src/types/rust/CosmosFee.ts")]
// this should corresponds to cosmrs::tx::Fee
// IMPORTANT NOTE: this should work as of cosmrs 0.7.1 due to their `FromStr` implementations
// on the type. The below struct might have to get readjusted if we update cosmrs!!
pub struct CosmosFee {
amount: Vec<Coin>,
gas_limit: u64,
payer: Option<String>,
granter: Option<String>,
}
// Note: I've got a feeling this one will bite us hard at some point...
#[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS)]
#[ts(export_to = "ts-packages/types/src/types/rust/Coin.ts")]
// this should corresponds to cosmrs::Coin
// IMPORTANT NOTE: this should work as of cosmrs 0.7.1 due to their `FromStr` implementations
// on the type. The below struct might have to get readjusted if we update cosmrs!!
pub struct Coin {
denom: String,
// this is not entirely true, but for the purposes
// of ts_rs, it's sufficient for the time being
amount: u64,
}
}
+1 -1
View File
@@ -51,7 +51,7 @@ impl Gas {
feature = "generate-ts", feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/GasInfo.ts") ts(export_to = "ts-packages/types/src/types/rust/GasInfo.ts")
)] )]
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize, Debug)]
pub struct GasInfo { pub struct GasInfo {
/// GasWanted is the maximum units of work we allow this tx to perform. /// GasWanted is the maximum units of work we allow this tx to perform.
pub gas_wanted: u64, pub gas_wanted: u64,
+1 -1
View File
@@ -60,7 +60,7 @@ pub struct TransactionDetails {
feature = "generate-ts", feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/TransactionExecuteResult.ts") ts(export_to = "ts-packages/types/src/types/rust/TransactionExecuteResult.ts")
)] )]
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize, Debug)]
pub struct TransactionExecuteResult { pub struct TransactionExecuteResult {
pub logs_json: String, pub logs_json: String,
pub data_json: String, pub data_json: String,
+1 -1
View File
@@ -7,4 +7,4 @@ 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]
semver = "0.11" semver = "0.11"
+1 -1
View File
@@ -29,4 +29,4 @@ features = [
"ProgressEvent", "ProgressEvent",
"WebSocket", "WebSocket",
"Window", "Window",
] ]
+2 -2
View File
@@ -1024,7 +1024,7 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]] [[package]]
name = "mixnet-contract" name = "mixnet-contract"
version = "1.0.0" version = "1.0.1"
dependencies = [ dependencies = [
"az", "az",
"bs58", "bs58",
@@ -1826,7 +1826,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]] [[package]]
name = "vesting-contract" name = "vesting-contract"
version = "1.0.0" version = "1.0.1"
dependencies = [ dependencies = [
"config", "config",
"cosmwasm-std", "cosmwasm-std",
+3 -3
View File
@@ -62,7 +62,7 @@ pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Respon
pub mod tests { pub mod tests {
use super::*; use super::*;
use bandwidth_claim_contract::payment::PagedPaymentResponse; use bandwidth_claim_contract::payment::PagedPaymentResponse;
use config::defaults::DENOM; use config::defaults::MIX_DENOM;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
use cosmwasm_std::{coins, from_binary}; use cosmwasm_std::{coins, from_binary};
@@ -91,11 +91,11 @@ pub mod tests {
// Contract balance should match what we initialized it as // Contract balance should match what we initialized it as
assert_eq!( assert_eq!(
coins(0, DENOM), coins(0, MIX_DENOM.base),
vec![deps vec![deps
.as_ref() .as_ref()
.querier .querier
.query_balance(env.contract.address, DENOM) .query_balance(env.contract.address, MIX_DENOM.base)
.unwrap()] .unwrap()]
); );
} }
+7 -8
View File
@@ -63,11 +63,10 @@ mod tests {
use super::*; use super::*;
use crate::support::tests::helpers::*; use crate::support::tests::helpers::*;
use coconut_bandwidth_contract_common::deposit::DepositData; use coconut_bandwidth_contract_common::deposit::DepositData;
use config::defaults::DENOM; use config::defaults::MIX_DENOM;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
use cosmwasm_std::{coins, Addr}; use cosmwasm_std::{coins, Addr};
use cw_multi_test::Executor; use cw_multi_test::Executor;
use serde::de::Unexpected::Str;
#[test] #[test]
fn initialize_contract() { fn initialize_contract() {
@@ -84,20 +83,20 @@ mod tests {
// Contract balance should be 0 // Contract balance should be 0
assert_eq!( assert_eq!(
coins(0, DENOM), coins(0, MIX_DENOM.base),
vec![deps vec![deps
.as_ref() .as_ref()
.querier .querier
.query_balance(env.contract.address, DENOM) .query_balance(env.contract.address, MIX_DENOM.base)
.unwrap()] .unwrap()]
); );
} }
#[test] #[test]
fn deposit_and_release() { fn deposit_and_release() {
let init_funds = coins(10, DENOM); let init_funds = coins(10, MIX_DENOM.base);
let deposit_funds = coins(1, DENOM); let deposit_funds = coins(1, MIX_DENOM.base);
let release_funds = coins(2, DENOM); let release_funds = coins(2, MIX_DENOM.base);
let mut app = mock_app(&init_funds); let mut app = mock_app(&init_funds);
let multisig_addr = String::from(MULTISIG_CONTRACT); let multisig_addr = String::from(MULTISIG_CONTRACT);
let pool_addr = String::from(POOL_CONTRACT); let pool_addr = String::from(POOL_CONTRACT);
@@ -157,7 +156,7 @@ mod tests {
&[], &[],
) )
.unwrap(); .unwrap();
let pool_bal = app.wrap().query_balance(pool_addr, DENOM).unwrap(); let pool_bal = app.wrap().query_balance(pool_addr, MIX_DENOM.base).unwrap();
assert_eq!(pool_bal, deposit_funds[0]); assert_eq!(pool_bal, deposit_funds[0]);
} }
} }
+2 -2
View File
@@ -5,7 +5,7 @@ use cosmwasm_std::StdError;
use cw_controllers::AdminError; use cw_controllers::AdminError;
use thiserror::Error; use thiserror::Error;
use config::defaults::DENOM; use config::defaults::MIX_DENOM;
/// Custom errors for contract failure conditions. /// Custom errors for contract failure conditions.
/// ///
@@ -22,7 +22,7 @@ pub enum ContractError {
#[error("No coin was sent for voucher")] #[error("No coin was sent for voucher")]
NoCoin, NoCoin,
#[error("Wrong coin denomination, you must send {}", DENOM)] #[error("Wrong coin denomination, you must send {}", MIX_DENOM.base)]
WrongDenom, WrongDenom,
#[error("There aren't enough funds in the contract")] #[error("There aren't enough funds in the contract")]
@@ -4,7 +4,6 @@
#[cfg(test)] #[cfg(test)]
pub mod helpers { pub mod helpers {
pub const OWNER: &str = "admin0001"; pub const OWNER: &str = "admin0001";
pub const SOMEBODY: &str = "somebody";
pub const MULTISIG_CONTRACT: &str = "multisig contract address"; pub const MULTISIG_CONTRACT: &str = "multisig contract address";
pub const POOL_CONTRACT: &str = "mix pool contract address"; pub const POOL_CONTRACT: &str = "mix pool contract address";
@@ -23,7 +22,7 @@ pub mod helpers {
let env = mock_env(); let env = mock_env();
let info = mock_info("creator", &[]); let info = mock_info("creator", &[]);
instantiate(deps.as_mut(), env.clone(), info, msg).unwrap(); instantiate(deps.as_mut(), env.clone(), info, msg).unwrap();
return deps; deps
} }
pub fn mock_app(init_funds: &[Coin]) -> App { pub fn mock_app(init_funds: &[Coin]) -> App {
@@ -11,7 +11,7 @@ use coconut_bandwidth_contract_common::events::{
DEPOSITED_FUNDS_EVENT_TYPE, DEPOSIT_ENCRYPTION_KEY, DEPOSIT_IDENTITY_KEY, DEPOSIT_INFO, DEPOSITED_FUNDS_EVENT_TYPE, DEPOSIT_ENCRYPTION_KEY, DEPOSIT_IDENTITY_KEY, DEPOSIT_INFO,
DEPOSIT_VALUE, DEPOSIT_VALUE,
}; };
use config::defaults::DENOM; use config::defaults::MIX_DENOM;
pub(crate) fn deposit_funds( pub(crate) fn deposit_funds(
_deps: DepsMut<'_>, _deps: DepsMut<'_>,
@@ -25,7 +25,7 @@ pub(crate) fn deposit_funds(
if info.funds.len() > 1 { if info.funds.len() > 1 {
return Err(ContractError::MultipleDenoms); return Err(ContractError::MultipleDenoms);
} }
if info.funds[0].denom != DENOM { if info.funds[0].denom != MIX_DENOM.base {
return Err(ContractError::WrongDenom); return Err(ContractError::WrongDenom);
} }
@@ -45,10 +45,12 @@ pub(crate) fn release_funds(
info: MessageInfo, info: MessageInfo,
funds: Coin, funds: Coin,
) -> Result<Response, ContractError> { ) -> Result<Response, ContractError> {
if funds.denom != DENOM { if funds.denom != MIX_DENOM.base {
return Err(ContractError::WrongDenom); return Err(ContractError::WrongDenom);
} }
let current_balance = deps.querier.query_balance(env.contract.address, DENOM)?; let current_balance = deps
.querier
.query_balance(env.contract.address, MIX_DENOM.base)?;
if funds.amount > current_balance.amount { if funds.amount > current_balance.amount {
return Err(ContractError::NotEnoughFunds); return Err(ContractError::NotEnoughFunds);
} }
@@ -90,7 +92,7 @@ mod tests {
Err(ContractError::NoCoin) Err(ContractError::NoCoin)
); );
let coin = Coin::new(1000000, DENOM); let coin = Coin::new(1000000, MIX_DENOM.base);
let second_coin = Coin::new(1000000, "some_denom"); let second_coin = Coin::new(1000000, "some_denom");
let info = mock_info("requester", &[coin, second_coin.clone()]); let info = mock_info("requester", &[coin, second_coin.clone()]);
@@ -120,7 +122,7 @@ mod tests {
verification_key.clone(), verification_key.clone(),
encryption_key.clone(), encryption_key.clone(),
); );
let coin = Coin::new(deposit_value, DENOM); let coin = Coin::new(deposit_value, MIX_DENOM.base);
let info = mock_info("requester", &[coin]); let info = mock_info("requester", &[coin]);
let tx = deposit_funds(deps.as_mut(), env.clone(), info, data).unwrap(); let tx = deposit_funds(deps.as_mut(), env.clone(), info, data).unwrap();
@@ -169,7 +171,7 @@ mod tests {
let mut deps = helpers::init_contract(); let mut deps = helpers::init_contract();
let env = mock_env(); let env = mock_env();
let invalid_admin = "invalid admin"; let invalid_admin = "invalid admin";
let funds = Coin::new(1, DENOM); let funds = Coin::new(1, MIX_DENOM.base);
let err = release_funds( let err = release_funds(
deps.as_mut(), deps.as_mut(),
@@ -205,7 +207,7 @@ mod tests {
fn valid_release() { fn valid_release() {
let mut deps = helpers::init_contract(); let mut deps = helpers::init_contract();
let env = mock_env(); let env = mock_env();
let coin = Coin::new(1, DENOM); let coin = Coin::new(1, MIX_DENOM.base);
deps.querier deps.querier
.update_balance(env.contract.address.clone(), vec![coin.clone()]); .update_balance(env.contract.address.clone(), vec![coin.clone()]);
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "mixnet-contract" name = "mixnet-contract"
version = "1.0.0" version = "1.0.1"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"] authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
edition = "2021" edition = "2021"
+2 -1
View File
@@ -13,4 +13,5 @@ pub const ACTIVE_SET_WORK_FACTOR: u8 = 10;
// and we can't change this easily to `Duration`, because then the entire rewarded set storage // and we can't change this easily to `Duration`, because then the entire rewarded set storage
// would be messed up... (as we look up stuff "by blocks") // would be messed up... (as we look up stuff "by blocks")
pub const REWARDED_SET_REFRESH_BLOCKS: u64 = 720; // with blocktime being approximately 5s, it should be roughly 1h pub const REWARDED_SET_REFRESH_BLOCKS: u64 = 720; // with blocktime being approximately 5s, it should be roughly 1h
pub const EPOCHS_IN_INTERVAL: u64 = 720; // Hours in a month pub const INTERVAL_SECONDS: u64 = 86400 * 30; // 30 days
pub const DEFAULT_OPERATOR_INTERVAL_COST: u64 = 40_000_000;
+16 -87
View File
@@ -7,10 +7,9 @@ use crate::delegations::queries::query_mixnode_delegation;
use crate::delegations::queries::{ use crate::delegations::queries::{
query_mixnode_delegations_paged, query_pending_delegation_events, query_mixnode_delegations_paged, query_pending_delegation_events,
}; };
use crate::delegations::storage::delegations;
use crate::error::ContractError; use crate::error::ContractError;
use crate::gateways::queries::query_gateways_paged;
use crate::gateways::queries::query_owns_gateway; use crate::gateways::queries::query_owns_gateway;
use crate::gateways::queries::{query_gateway_bond, query_gateways_paged};
use crate::interval::queries::query_current_epoch; use crate::interval::queries::query_current_epoch;
use crate::interval::queries::{ use crate::interval::queries::{
query_current_rewarded_set_height, query_rewarded_set, query_current_rewarded_set_height, query_rewarded_set,
@@ -29,14 +28,13 @@ use crate::mixnodes::bonding_queries::{
}; };
use crate::mixnodes::layer_queries::query_layer_distribution; use crate::mixnodes::layer_queries::query_layer_distribution;
use crate::rewards::queries::{ use crate::rewards::queries::{
query_circulating_supply, query_reward_pool, query_rewarding_status, query_circulating_supply, query_reward_pool, query_rewarding_status, query_staking_supply,
}; };
use crate::rewards::storage as rewards_storage; use crate::rewards::storage as rewards_storage;
use cosmwasm_std::{ use cosmwasm_std::{
entry_point, to_binary, Addr, Api, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response, entry_point, to_binary, Addr, Api, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response,
Uint128, Uint128,
}; };
use mixnet_contract_common::mixnode::DelegationEvent;
use mixnet_contract_common::{ use mixnet_contract_common::{
ContractStateParams, ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg, ContractStateParams, ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg,
}; };
@@ -331,6 +329,10 @@ pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result<QueryResponse, C
QueryMsg::OwnsMixnode { address } => { QueryMsg::OwnsMixnode { address } => {
to_binary(&mixnode_queries::query_owns_mixnode(deps, address)?) to_binary(&mixnode_queries::query_owns_mixnode(deps, address)?)
} }
QueryMsg::GetMixnodeBond { identity } => {
to_binary(&mixnode_queries::query_mixnode_bond(deps, identity)?)
}
QueryMsg::GetGatewayBond { identity } => to_binary(&query_gateway_bond(deps, identity)?),
QueryMsg::OwnsGateway { address } => to_binary(&query_owns_gateway(deps, address)?), QueryMsg::OwnsGateway { address } => to_binary(&query_owns_gateway(deps, address)?),
QueryMsg::StateParams {} => to_binary(&query_contract_settings_params(deps)?), QueryMsg::StateParams {} => to_binary(&query_contract_settings_params(deps)?),
QueryMsg::LayerDistribution {} => to_binary(&query_layer_distribution(deps)?), QueryMsg::LayerDistribution {} => to_binary(&query_layer_distribution(deps)?),
@@ -367,6 +369,7 @@ pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result<QueryResponse, C
)?), )?),
QueryMsg::GetRewardPool {} => to_binary(&query_reward_pool(deps)?), QueryMsg::GetRewardPool {} => to_binary(&query_reward_pool(deps)?),
QueryMsg::GetCirculatingSupply {} => to_binary(&query_circulating_supply(deps)?), QueryMsg::GetCirculatingSupply {} => to_binary(&query_circulating_supply(deps)?),
QueryMsg::GetStakingSupply {} => to_binary(&query_staking_supply(deps)?),
QueryMsg::GetIntervalRewardPercent {} => to_binary(&INTERVAL_REWARD_PERCENT), QueryMsg::GetIntervalRewardPercent {} => to_binary(&INTERVAL_REWARD_PERCENT),
QueryMsg::GetSybilResistancePercent {} => to_binary(&SYBIL_RESISTANCE_PERCENT), QueryMsg::GetSybilResistancePercent {} => to_binary(&SYBIL_RESISTANCE_PERCENT),
QueryMsg::GetActiveSetWorkFactor {} => to_binary(&ACTIVE_SET_WORK_FACTOR), QueryMsg::GetActiveSetWorkFactor {} => to_binary(&ACTIVE_SET_WORK_FACTOR),
@@ -394,7 +397,12 @@ pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result<QueryResponse, C
QueryMsg::GetRewardedSetRefreshBlocks {} => { QueryMsg::GetRewardedSetRefreshBlocks {} => {
to_binary(&query_rewarded_set_refresh_minimum_blocks()) to_binary(&query_rewarded_set_refresh_minimum_blocks())
} }
QueryMsg::GetEpochsInInterval {} => to_binary(&crate::constants::EPOCHS_IN_INTERVAL), QueryMsg::GetEpochsInInterval {} => {
to_binary(&crate::support::helpers::epochs_in_interval(deps.storage)?)
}
QueryMsg::GetCurrentOperatorCost {} => to_binary(
&crate::support::helpers::current_operator_epoch_cost(deps.storage)?,
),
QueryMsg::GetCurrentEpoch {} => to_binary(&query_current_epoch(deps.storage)?), QueryMsg::GetCurrentEpoch {} => to_binary(&query_current_epoch(deps.storage)?),
QueryMsg::QueryOperatorReward { address } => to_binary( QueryMsg::QueryOperatorReward { address } => to_binary(
&crate::rewards::queries::query_operator_reward(deps, address)?, &crate::rewards::queries::query_operator_reward(deps, address)?,
@@ -435,87 +443,8 @@ pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result<QueryResponse, C
Ok(query_res?) Ok(query_res?)
} }
fn migrate_contract_state_params(deps: DepsMut<'_>) -> Result<(), ContractError> {
use crate::mixnet_contract_settings::storage::CONTRACT_STATE;
use cw_storage_plus::Item;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct OldContractState {
pub owner: Addr,
pub rewarding_validator_address: Addr,
pub params: OldContractStateParams,
}
#[derive(Serialize, Deserialize)]
struct OldContractStateParams {
pub minimum_mixnode_pledge: Uint128,
pub minimum_gateway_pledge: Uint128,
pub mixnode_rewarded_set_size: u32,
pub mixnode_active_set_size: u32,
}
const OLD_CONTRACT_STATE: Item<'_, OldContractState> = Item::new("config");
let old_contract_state = OLD_CONTRACT_STATE.load(deps.storage)?;
let old_params = old_contract_state.params;
let new_params = ContractStateParams {
minimum_mixnode_pledge: old_params.minimum_mixnode_pledge,
minimum_gateway_pledge: old_params.minimum_gateway_pledge,
mixnode_rewarded_set_size: old_params.mixnode_rewarded_set_size,
mixnode_active_set_size: old_params.mixnode_active_set_size,
staking_supply: INITIAL_STAKING_SUPPLY,
};
let new_contract_state = ContractState {
owner: old_contract_state.owner,
rewarding_validator_address: old_contract_state.rewarding_validator_address,
params: new_params,
};
CONTRACT_STATE.save(deps.storage, &new_contract_state)?;
Ok(())
}
fn _deal_with_zero_delegations(deps: DepsMut<'_>) -> Result<(), ContractError> {
// if there exists any delegation of 0 value, remove it
let zero_delegations = delegations()
.range(deps.storage, None, None, cosmwasm_std::Order::Ascending)
.filter_map(|r| r.ok())
.filter(|(_k, v)| v.amount.amount == Uint128::zero())
.map(|(k, _v)| k)
.collect::<Vec<_>>();
for delegation in &zero_delegations {
delegations().remove(deps.storage, delegation.clone())?;
}
// similarly, if there exists any event that is scheduled to insert/remove delegation with 0 value, purge it
let delegate_events_to_purge = crate::delegations::storage::PENDING_DELEGATION_EVENTS
.range(deps.storage, None, None, cosmwasm_std::Order::Ascending)
.filter_map(|r| r.ok())
.filter(|(_k, v)| match v {
DelegationEvent::Delegate(d) => d.amount.amount == Uint128::zero(),
_ => false,
})
.map(|(k, _v)| k)
.collect::<Vec<_>>();
for delegation_event in delegate_events_to_purge {
crate::delegations::storage::PENDING_DELEGATION_EVENTS
.remove(deps.storage, delegation_event);
}
Ok(())
}
#[entry_point] #[entry_point]
pub fn migrate(deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> { pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
migrate_contract_state_params(deps)?;
Ok(Default::default()) Ok(Default::default())
} }
@@ -523,7 +452,7 @@ pub fn migrate(deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Respons
pub mod tests { pub mod tests {
use super::*; use super::*;
use crate::support::tests; use crate::support::tests;
use config::defaults::{DEFAULT_NETWORK, DENOM}; use config::defaults::{DEFAULT_NETWORK, MIX_DENOM};
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
use cosmwasm_std::{coins, from_binary}; use cosmwasm_std::{coins, from_binary};
use mixnet_contract_common::PagedMixnodeResponse; use mixnet_contract_common::PagedMixnodeResponse;
@@ -555,7 +484,7 @@ pub mod tests {
// Contract balance should match what we initialized it as // Contract balance should match what we initialized it as
assert_eq!( assert_eq!(
coins(0, DENOM), coins(0, MIX_DENOM.base),
tests::queries::query_contract_balance(env.contract.address, deps) tests::queries::query_contract_balance(env.contract.address, deps)
); );
} }
+4 -4
View File
@@ -200,7 +200,7 @@ pub(crate) fn query_mixnode_delegations_paged(
pub(crate) mod tests { pub(crate) mod tests {
use super::*; use super::*;
use crate::support::tests::test_helpers; use crate::support::tests::test_helpers;
use config::defaults::DENOM; use config::defaults::MIX_DENOM;
use cosmwasm_std::{coin, Addr, Storage}; use cosmwasm_std::{coin, Addr, Storage};
use rand::Rng; use rand::Rng;
@@ -385,7 +385,7 @@ pub(crate) mod tests {
let delegation = Delegation::new( let delegation = Delegation::new(
delegation_owner.clone(), delegation_owner.clone(),
node_identity.clone(), node_identity.clone(),
coin(1234, DENOM), coin(1234, MIX_DENOM.base),
1234, 1234,
None, None,
); );
@@ -433,7 +433,7 @@ pub(crate) mod tests {
let delegation = Delegation::new( let delegation = Delegation::new(
delegation_owner2, delegation_owner2,
node_identity1.clone(), node_identity1.clone(),
coin(1234, DENOM), coin(1234, MIX_DENOM.base),
1234, 1234,
None, None,
); );
@@ -460,7 +460,7 @@ pub(crate) mod tests {
let delegation = Delegation::new( let delegation = Delegation::new(
delegation_owner1.clone(), delegation_owner1.clone(),
node_identity2, node_identity2,
coin(1234, DENOM), coin(1234, MIX_DENOM.base),
1234, 1234,
None, None,
); );
+3 -3
View File
@@ -77,7 +77,7 @@ mod tests {
mod reverse_mix_delegations { mod reverse_mix_delegations {
use super::*; use super::*;
use crate::support::tests::test_helpers; use crate::support::tests::test_helpers;
use config::defaults::DENOM; use config::defaults::MIX_DENOM;
use cosmwasm_std::testing::mock_env; use cosmwasm_std::testing::mock_env;
use cosmwasm_std::{coin, Order}; use cosmwasm_std::{coin, Order};
use mixnet_contract_common::Delegation; use mixnet_contract_common::Delegation;
@@ -87,7 +87,7 @@ mod tests {
let mut deps = test_helpers::init_contract(); let mut deps = test_helpers::init_contract();
let node_identity: IdentityKey = "foo".into(); let node_identity: IdentityKey = "foo".into();
let delegation_owner = Addr::unchecked("bar"); let delegation_owner = Addr::unchecked("bar");
let delegation = coin(12345, DENOM); let delegation = coin(12345, MIX_DENOM.base);
let dummy_data = Delegation::new( let dummy_data = Delegation::new(
delegation_owner.clone(), delegation_owner.clone(),
@@ -125,7 +125,7 @@ mod tests {
let node_identity2: IdentityKey = "foo2".into(); let node_identity2: IdentityKey = "foo2".into();
let delegation_owner1 = Addr::unchecked("bar"); let delegation_owner1 = Addr::unchecked("bar");
let delegation_owner2 = Addr::unchecked("bar2"); let delegation_owner2 = Addr::unchecked("bar2");
let delegation = coin(12345, DENOM); let delegation = coin(12345, MIX_DENOM.base);
assert!(test_helpers::read_delegation( assert!(test_helpers::read_delegation(
deps.as_ref().storage, deps.as_ref().storage,
@@ -6,7 +6,7 @@ use super::storage::{self, PENDING_DELEGATION_EVENTS};
use crate::error::ContractError; use crate::error::ContractError;
use crate::mixnet_contract_settings::storage as mixnet_params_storage; use crate::mixnet_contract_settings::storage as mixnet_params_storage;
use crate::mixnodes::storage as mixnodes_storage; use crate::mixnodes::storage as mixnodes_storage;
use config::defaults::DENOM; use config::defaults::MIX_DENOM;
use cosmwasm_std::{ use cosmwasm_std::{
coins, wasm_execute, Addr, Api, BankMsg, Coin, DepsMut, Env, Event, MessageInfo, Order, coins, wasm_execute, Addr, Api, BankMsg, Coin, DepsMut, Env, Event, MessageInfo, Order,
Response, Storage, Uint128, WasmMsg, Response, Storage, Uint128, WasmMsg,
@@ -85,7 +85,7 @@ fn validate_delegation_stake(mut delegation: Vec<Coin>) -> Result<Coin, Contract
} }
// check that the denomination is correct // check that the denomination is correct
if delegation[0].denom != DENOM { if delegation[0].denom != MIX_DENOM.base {
return Err(ContractError::WrongDenom {}); return Err(ContractError::WrongDenom {});
} }
@@ -389,7 +389,7 @@ pub(crate) fn try_reconcile_undelegation(
.as_ref() .as_ref()
.unwrap_or(&pending_undelegate.delegate()) .unwrap_or(&pending_undelegate.delegate())
.to_string(), .to_string(),
amount: coins(total_funds.u128(), DENOM), amount: coins(total_funds.u128(), MIX_DENOM.base),
}) })
} else { } else {
None None
@@ -401,7 +401,7 @@ pub(crate) fn try_reconcile_undelegation(
let msg = Some(VestingContractExecuteMsg::TrackUndelegation { let msg = Some(VestingContractExecuteMsg::TrackUndelegation {
owner: pending_undelegate.delegate().as_str().to_string(), owner: pending_undelegate.delegate().as_str().to_string(),
mix_identity: pending_undelegate.mix_identity(), mix_identity: pending_undelegate.mix_identity(),
amount: Coin::new(total_funds.u128(), DENOM), amount: Coin::new(total_funds.u128(), MIX_DENOM.base),
}); });
wasm_msg = Some(wasm_execute(proxy, &msg, vec![one_ucoin()])?); wasm_msg = Some(wasm_execute(proxy, &msg, vec![one_ucoin()])?);
@@ -492,7 +492,7 @@ mod tests {
assert_eq!( assert_eq!(
Err(ContractError::MultipleDenoms), Err(ContractError::MultipleDenoms),
validate_delegation_stake(vec![ validate_delegation_stake(vec![
coin(123, DENOM), coin(123, MIX_DENOM.base),
coin(123, "BTC"), coin(123, "BTC"),
coin(123, "DOGE") coin(123, "DOGE")
]) ])
@@ -511,16 +511,16 @@ mod tests {
fn stake_coin_must_have_value_greater_than_zero() { fn stake_coin_must_have_value_greater_than_zero() {
assert_eq!( assert_eq!(
Err(ContractError::EmptyDelegation), Err(ContractError::EmptyDelegation),
validate_delegation_stake(coins(0, DENOM)) validate_delegation_stake(coins(0, MIX_DENOM.base))
) )
} }
#[test] #[test]
fn stake_can_have_any_positive_value() { fn stake_can_have_any_positive_value() {
// this might change in the future, but right now an arbitrary (positive) value can be delegated // this might change in the future, but right now an arbitrary (positive) value can be delegated
assert!(validate_delegation_stake(coins(1, DENOM)).is_ok()); assert!(validate_delegation_stake(coins(1, MIX_DENOM.base)).is_ok());
assert!(validate_delegation_stake(coins(123, DENOM)).is_ok()); assert!(validate_delegation_stake(coins(123, MIX_DENOM.base)).is_ok());
assert!(validate_delegation_stake(coins(10000000000, DENOM)).is_ok()); assert!(validate_delegation_stake(coins(10000000000, MIX_DENOM.base)).is_ok());
} }
} }
@@ -543,7 +543,7 @@ mod tests {
try_delegate_to_mixnode( try_delegate_to_mixnode(
deps.as_mut(), deps.as_mut(),
mock_env(), mock_env(),
mock_info("sender", &coins(123, DENOM)), mock_info("sender", &coins(123, MIX_DENOM.base)),
"non-existent-mix-identity".into(), "non-existent-mix-identity".into(),
) )
); );
@@ -559,7 +559,7 @@ mod tests {
deps.as_mut(), deps.as_mut(),
); );
let delegation_owner = Addr::unchecked("sender"); let delegation_owner = Addr::unchecked("sender");
let delegation = coin(123, DENOM); let delegation = coin(123, MIX_DENOM.base);
assert!(try_delegate_to_mixnode( assert!(try_delegate_to_mixnode(
deps.as_mut(), deps.as_mut(),
mock_env(), mock_env(),
@@ -616,7 +616,7 @@ mod tests {
try_delegate_to_mixnode( try_delegate_to_mixnode(
deps.as_mut(), deps.as_mut(),
mock_env(), mock_env(),
mock_info(delegation_owner.as_str(), &coins(123, DENOM)), mock_info(delegation_owner.as_str(), &coins(123, MIX_DENOM.base)),
identity, identity,
) )
); );
@@ -637,7 +637,7 @@ mod tests {
tests::fixtures::good_mixnode_pledge(), tests::fixtures::good_mixnode_pledge(),
deps.as_mut(), deps.as_mut(),
); );
let delegation = coin(123, DENOM); let delegation = coin(123, MIX_DENOM.base);
let delegation_owner = Addr::unchecked("sender"); let delegation_owner = Addr::unchecked("sender");
assert!(try_delegate_to_mixnode( assert!(try_delegate_to_mixnode(
deps.as_mut(), deps.as_mut(),
@@ -687,8 +687,8 @@ mod tests {
deps.as_mut(), deps.as_mut(),
); );
let delegation_owner = Addr::unchecked("sender"); let delegation_owner = Addr::unchecked("sender");
let delegation1 = coin(100, DENOM); let delegation1 = coin(100, MIX_DENOM.base);
let delegation2 = coin(50, DENOM); let delegation2 = coin(50, MIX_DENOM.base);
let mut env = mock_env(); let mut env = mock_env();
@@ -715,7 +715,7 @@ mod tests {
// let expected = Delegation::new( // let expected = Delegation::new(
// delegation_owner.clone(), // delegation_owner.clone(),
// identity.clone(), // identity.clone(),
// coin(delegation1.amount.u128() + delegation2.amount.u128(), DENOM), // coin(delegation1.amount.u128() + delegation2.amount.u128(), MIX_DENOM.base),
// mock_env().block.height, // mock_env().block.height,
// None, // None,
// ); // );
@@ -750,7 +750,7 @@ mod tests {
deps.as_mut(), deps.as_mut(),
); );
let delegation_owner = Addr::unchecked("sender"); let delegation_owner = Addr::unchecked("sender");
let delegation = coin(100, DENOM); let delegation = coin(100, MIX_DENOM.base);
let env1 = mock_env(); let env1 = mock_env();
let mut env2 = mock_env(); let mut env2 = mock_env();
let initial_height = env1.block.height; let initial_height = env1.block.height;
@@ -815,8 +815,8 @@ mod tests {
); );
let delegation_owner1 = Addr::unchecked("sender1"); let delegation_owner1 = Addr::unchecked("sender1");
let delegation_owner2 = Addr::unchecked("sender2"); let delegation_owner2 = Addr::unchecked("sender2");
let delegation1 = coin(100, DENOM); let delegation1 = coin(100, MIX_DENOM.base);
let delegation2 = coin(120, DENOM); let delegation2 = coin(120, MIX_DENOM.base);
let env1 = mock_env(); let env1 = mock_env();
let mut env2 = mock_env(); let mut env2 = mock_env();
let initial_height = env1.block.height; let initial_height = env1.block.height;
@@ -891,7 +891,7 @@ mod tests {
try_delegate_to_mixnode( try_delegate_to_mixnode(
deps.as_mut(), deps.as_mut(),
mock_env(), mock_env(),
mock_info(delegation_owner.as_str(), &coins(100, DENOM)), mock_info(delegation_owner.as_str(), &coins(100, MIX_DENOM.base)),
identity.clone(), identity.clone(),
) )
.unwrap(); .unwrap();
@@ -903,7 +903,7 @@ mod tests {
try_delegate_to_mixnode( try_delegate_to_mixnode(
deps.as_mut(), deps.as_mut(),
mock_env(), mock_env(),
mock_info(delegation_owner.as_str(), &coins(50, DENOM)), mock_info(delegation_owner.as_str(), &coins(50, MIX_DENOM.base)),
identity, identity,
) )
); );
@@ -928,14 +928,14 @@ mod tests {
assert!(try_delegate_to_mixnode( assert!(try_delegate_to_mixnode(
deps.as_mut(), deps.as_mut(),
mock_env(), mock_env(),
mock_info(delegation_owner.as_str(), &coins(123, DENOM)), mock_info(delegation_owner.as_str(), &coins(123, MIX_DENOM.base)),
identity1.clone(), identity1.clone(),
) )
.is_ok()); .is_ok());
assert!(try_delegate_to_mixnode( assert!(try_delegate_to_mixnode(
deps.as_mut(), deps.as_mut(),
mock_env(), mock_env(),
mock_info(delegation_owner.as_str(), &coins(42, DENOM)), mock_info(delegation_owner.as_str(), &coins(42, MIX_DENOM.base)),
identity2.clone(), identity2.clone(),
) )
.is_ok()); .is_ok());
@@ -945,7 +945,7 @@ mod tests {
let expected1 = Delegation::new( let expected1 = Delegation::new(
delegation_owner.clone(), delegation_owner.clone(),
identity1.clone(), identity1.clone(),
coin(123, DENOM), coin(123, MIX_DENOM.base),
mock_env().block.height, mock_env().block.height,
None, None,
); );
@@ -953,7 +953,7 @@ mod tests {
let expected2 = Delegation::new( let expected2 = Delegation::new(
delegation_owner.clone(), delegation_owner.clone(),
identity2.clone(), identity2.clone(),
coin(42, DENOM), coin(42, MIX_DENOM.base),
mock_env().block.height, mock_env().block.height,
None, None,
); );
@@ -989,8 +989,8 @@ mod tests {
tests::fixtures::good_mixnode_pledge(), tests::fixtures::good_mixnode_pledge(),
deps.as_mut(), deps.as_mut(),
); );
let delegation1 = coin(123, DENOM); let delegation1 = coin(123, MIX_DENOM.base);
let delegation2 = coin(234, DENOM); let delegation2 = coin(234, MIX_DENOM.base);
assert!(try_delegate_to_mixnode( assert!(try_delegate_to_mixnode(
deps.as_mut(), deps.as_mut(),
mock_env(), mock_env(),
@@ -1026,7 +1026,7 @@ mod tests {
deps.as_mut(), deps.as_mut(),
); );
let delegation_owner = Addr::unchecked("sender"); let delegation_owner = Addr::unchecked("sender");
let delegation_amount = coin(100, DENOM); let delegation_amount = coin(100, MIX_DENOM.base);
try_delegate_to_mixnode( try_delegate_to_mixnode(
deps.as_mut(), deps.as_mut(),
mock_env(), mock_env(),
@@ -1118,7 +1118,7 @@ mod tests {
try_delegate_to_mixnode( try_delegate_to_mixnode(
deps.as_mut(), deps.as_mut(),
mock_env(), mock_env(),
mock_info(delegation_owner.as_str(), &coins(100, DENOM)), mock_info(delegation_owner.as_str(), &coins(100, MIX_DENOM.base)),
identity.clone(), identity.clone(),
) )
.unwrap(); .unwrap();
@@ -1137,7 +1137,7 @@ mod tests {
let expected_response = Response::new() let expected_response = Response::new()
.add_message(BankMsg::Send { .add_message(BankMsg::Send {
to_address: delegation_owner.clone().into(), to_address: delegation_owner.clone().into(),
amount: coins(100, DENOM), amount: coins(100, MIX_DENOM.base),
}) })
.add_event(new_undelegation_event( .add_event(new_undelegation_event(
&delegation_owner, &delegation_owner,
@@ -1188,7 +1188,7 @@ mod tests {
try_delegate_to_mixnode( try_delegate_to_mixnode(
deps.as_mut(), deps.as_mut(),
mock_env(), mock_env(),
mock_info(delegation_owner.as_str(), &coins(100, DENOM)), mock_info(delegation_owner.as_str(), &coins(100, MIX_DENOM.base)),
identity.clone(), identity.clone(),
) )
.unwrap(); .unwrap();
@@ -1207,7 +1207,7 @@ mod tests {
let expected_response = Response::new() let expected_response = Response::new()
.add_message(BankMsg::Send { .add_message(BankMsg::Send {
to_address: delegation_owner.clone().into(), to_address: delegation_owner.clone().into(),
amount: coins(100, DENOM), amount: coins(100, MIX_DENOM.base),
}) })
.add_event(new_undelegation_event( .add_event(new_undelegation_event(
&delegation_owner, &delegation_owner,
@@ -1251,8 +1251,8 @@ mod tests {
); );
let delegation_owner1 = Addr::unchecked("sender1"); let delegation_owner1 = Addr::unchecked("sender1");
let delegation_owner2 = Addr::unchecked("sender2"); let delegation_owner2 = Addr::unchecked("sender2");
let delegation1 = coin(123, DENOM); let delegation1 = coin(123, MIX_DENOM.base);
let delegation2 = coin(234, DENOM); let delegation2 = coin(234, MIX_DENOM.base);
assert!(try_delegate_to_mixnode( assert!(try_delegate_to_mixnode(
deps.as_mut(), deps.as_mut(),
mock_env(), mock_env(),
+3 -3
View File
@@ -1,7 +1,7 @@
// 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 config::defaults::DENOM; use config::defaults::MIX_DENOM;
use cosmwasm_std::{Addr, StdError}; use cosmwasm_std::{Addr, StdError};
use mixnet_contract_common::{error::MixnetContractError, IdentityKey}; use mixnet_contract_common::{error::MixnetContractError, IdentityKey};
use thiserror::Error; use thiserror::Error;
@@ -33,13 +33,13 @@ pub enum ContractError {
#[error("MIXNET ({}): Unauthorized", line!())] #[error("MIXNET ({}): Unauthorized", line!())]
Unauthorized, Unauthorized,
#[error("MIXNET ({}): Wrong coin denomination, you must send {}", line!(), DENOM)] #[error("MIXNET ({}): Wrong coin denomination, you must send {}", line!(), MIX_DENOM.base)]
WrongDenom, WrongDenom,
#[error("MIXNET ({}): Received multiple coin types during staking", line!())] #[error("MIXNET ({}): Received multiple coin types during staking", line!())]
MultipleDenoms, MultipleDenoms,
#[error("MIXNET ({}): No coin was sent for the bonding, you must send {}", line!(), DENOM)] #[error("MIXNET ({}): No coin was sent for the bonding, you must send {}", line!(), MIX_DENOM.base)]
NoBondFound, NoBondFound,
#[error("MIXNET ({}): Provided active set size is bigger than the rewarded set", line!())] #[error("MIXNET ({}): Provided active set size is bigger than the rewarded set", line!())]

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