Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cc5e12e2b5 | |||
| b31587e051 | |||
| 9b1574ff08 | |||
| d3d5e327c7 | |||
| 433604dec7 | |||
| c429e67d68 |
@@ -1,9 +0,0 @@
|
||||
# Description
|
||||
|
||||
Closes: #XXXX
|
||||
|
||||
<!-- If appropriate, insert relevant description here -->
|
||||
|
||||
# Checklist:
|
||||
|
||||
- [ ] added a changelog entry to `CHANGELOG.md`
|
||||
@@ -1,72 +0,0 @@
|
||||
name: Continuous integration on dispatch
|
||||
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: [ self-hosted, custom-linux-exoscale ]
|
||||
# Enable sccache via environment variable
|
||||
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
|
||||
|
||||
- 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: --workspace
|
||||
|
||||
- name: Run all tests
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --workspace --all-features
|
||||
|
||||
- name: Check formatting
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
|
||||
- uses: actions-rs/clippy-check@v1
|
||||
name: Clippy checks
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --all-features
|
||||
|
||||
- name: Run clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: --workspace -- -D warnings
|
||||
|
||||
- name: Build all binaries with coconut enabled
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --workspace --features=coconut
|
||||
|
||||
- name: Run all tests with coconut enabled
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --workspace --features=coconut
|
||||
|
||||
- name: Run clippy with coconut enabled
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: --features=coconut -- -D warnings
|
||||
@@ -31,8 +31,6 @@ jobs:
|
||||
# continue-on-error: true
|
||||
- run: yarn && yarn build
|
||||
continue-on-error: true
|
||||
- run: yarn storybook:build
|
||||
name: Build storybook
|
||||
- name: Deploy branch to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
@@ -44,17 +42,6 @@ jobs:
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/network-explorer-${{ env.GITHUB_REF_SLUG }}
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Deploy storybook to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "explorer/storybook-static/"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/ne-sb-${{ env.GITHUB_REF_SLUG }}
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Keybase - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
@@ -64,7 +51,6 @@ jobs:
|
||||
NYM_PROJECT_NAME: "Network Explorer"
|
||||
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
|
||||
NYM_CI_WWW_LOCATION: "network-explorer-${{ env.GITHUB_REF_SLUG }}"
|
||||
NYM_CI_WWW_LOCATION_STORYBOOK: "ne-sb-${{ env.GITHUB_REF_SLUG }}"
|
||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
|
||||
|
||||
@@ -75,12 +75,6 @@ jobs:
|
||||
command: clippy
|
||||
args: --workspace --all-targets -- -D warnings
|
||||
|
||||
- name: Reclaim some disk space (because Windows is being annoying)
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
with:
|
||||
command: clean
|
||||
|
||||
# COCONUT stuff
|
||||
- name: Build all binaries with coconut enabled
|
||||
uses: actions-rs/cargo@v1
|
||||
@@ -106,33 +100,6 @@ jobs:
|
||||
with:
|
||||
command: clippy
|
||||
args: --workspace --all-targets --features=coconut -- -D warnings
|
||||
|
||||
# nym-wallet (the rust part)
|
||||
- name: Build nym-wallet rust code
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --manifest-path nym-wallet/Cargo.toml --workspace
|
||||
|
||||
- name: Run nym-wallet tests
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --manifest-path nym-wallet/Cargo.toml --workspace
|
||||
|
||||
- name: Check nym-wallet formatting
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --manifest-path nym-wallet/Cargo.toml --all -- --check
|
||||
|
||||
- name: Run clippy for nym-wallet
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.rust != 'nightly' }}
|
||||
with:
|
||||
command: clippy
|
||||
args: --manifest-path nym-wallet/Cargo.toml --workspace --all-targets -- -D warnings
|
||||
|
||||
notification:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -44,4 +44,3 @@ jobs:
|
||||
target/release/nym-mixnode
|
||||
target/release/nym-socks5-client
|
||||
target/release/nym-validator-api
|
||||
target/release/nym-network-requester
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View output:** https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}/
|
||||
> `storybook`: https://{{ env.NYM_CI_WWW_LOCATION_STORYBOOK }}.{{ env.NYM_CI_WWW_BASE }}
|
||||
> ✅ **SUCCESS**
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
name: Nym Wallet (rust)
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'explorer/**'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'explorer/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: [ self-hosted, custom-linux-exoscale ]
|
||||
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
|
||||
|
||||
- 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-wallet/Cargo.toml --workspace
|
||||
|
||||
- name: Run all tests
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --manifest-path nym-wallet/Cargo.toml --workspace
|
||||
|
||||
- name: Check formatting
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --manifest-path nym-wallet/Cargo.toml --all -- --check
|
||||
|
||||
- uses: actions-rs/clippy-check@v1
|
||||
name: Clippy checks
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --manifest-path nym-wallet/Cargo.toml --workspace --all-features
|
||||
|
||||
- name: Run clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: --manifest-path nym-wallet/Cargo.toml --workspace --all-features -- -D warnings
|
||||
-334
@@ -1,338 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- wallet: require password to switch accounts
|
||||
- wallet: add simple CLI tool for decrypting and recovering the wallet file.
|
||||
- wallet: added support for multiple accounts ([#1265])
|
||||
- wallet: the wallet backend learned how to keep track of validator name, either hardcoded or by querying the status endpoint.
|
||||
- mixnet-contract: Replace all naked `-` with `saturating_sub`.
|
||||
- validator-api: add Swagger to document the REST API ([#1249]).
|
||||
- all: added network compilation target to `--help` (or `--version`) commands ([#1256]).
|
||||
- network-requester: send traffic statistics from all network requesters and receive it in a special network-requester that aggregates the data and exposes it via a rest API ([#1267], [#1278]).
|
||||
|
||||
### Fixed
|
||||
|
||||
- vesting-contract: replaced `checked_sub` with `saturating_sub` to fix the underflow in `get_vesting_tokens` ([#1275])
|
||||
- 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: 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])
|
||||
|
||||
[#1258]: https://github.com/nymtech/nym/pull/1258
|
||||
[#1249]: https://github.com/nymtech/nym/pull/1249
|
||||
[#1256]: https://github.com/nymtech/nym/pull/1256
|
||||
[#1257]: https://github.com/nymtech/nym/pull/1257
|
||||
[#1260]: https://github.com/nymtech/nym/pull/1260
|
||||
[#1265]: https://github.com/nymtech/nym/pull/1265
|
||||
[#1267]: https://github.com/nymtech/nym/pull/1267
|
||||
[#1275]: https://github.com/nymtech/nym/pull/1275
|
||||
[#1278]: https://github.com/nymtech/nym/pull/1278
|
||||
|
||||
## [nym-wallet-v1.0.4](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.4) (2022-05-04)
|
||||
|
||||
### Changed
|
||||
|
||||
- all: the default behaviour of validator client is changed to use `broadcast_sync` and poll for transaction inclusion instead of using `broadcast_commit` to deal with timeouts ([#1246])
|
||||
|
||||
## [v1.0.1](https://github.com/nymtech/nym/tree/v1.0.1) (2022-05-04)
|
||||
|
||||
### Added
|
||||
|
||||
- validator-api: introduced endpoint for getting average mixnode uptime ([#1238])
|
||||
|
||||
### Changed
|
||||
|
||||
- all: the default behaviour of validator client is changed to use `broadcast_sync` and poll for transaction inclusion instead of using `broadcast_commit` to deal with timeouts ([#1246])
|
||||
|
||||
### Fixed
|
||||
|
||||
- nym-network-requester: is included in the Github Actions for building release binaries
|
||||
|
||||
[#1238]: https://github.com/nymtech/nym/pull/1238
|
||||
[#1246]: https://github.com/nymtech/nym/pull/1246
|
||||
|
||||
## [v1.0.0](https://github.com/nymtech/nym/tree/v1.0.0) (2022-05-03)
|
||||
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/v0.12.1...v1.0.0)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Feature/show pending delegations [\#1229](https://github.com/nymtech/nym/pull/1229) ([fmtabbara](https://github.com/fmtabbara))
|
||||
- Bucket inclusion probabilities [\#1224](https://github.com/nymtech/nym/pull/1224) ([durch](https://github.com/durch))
|
||||
- Create a new bundled delegation when compounding rewards [\#1221](https://github.com/nymtech/nym/pull/1221) ([durch](https://github.com/durch))
|
||||
|
||||
## [nym-binaries-1.0.0](https://github.com/nymtech/nym/tree/nym-binaries-1.0.0) (2022-04-27)
|
||||
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/nym-wallet-v1.0.3...nym-binaries-1.0.0)
|
||||
|
||||
## [nym-wallet-v1.0.3](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.3) (2022-04-25)
|
||||
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/nym-binaries-1.0.0-rc.2...nym-wallet-v1.0.3)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- \[Issue\] Wallet 1.0.2 cannot send NYM tokens from a DelayedVestingAccount [\#1215](https://github.com/nymtech/nym/issues/1215)
|
||||
- Main README not showing properly with GitHub dark mode [\#1211](https://github.com/nymtech/nym/issues/1211)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Bugfix - wallet undelegation for vesting accounts [\#1220](https://github.com/nymtech/nym/pull/1220) ([mmsinclair](https://github.com/mmsinclair))
|
||||
- Bugfix/delegation reconcile [\#1219](https://github.com/nymtech/nym/pull/1219) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Bugfix/query proxied pending delegations [\#1218](https://github.com/nymtech/nym/pull/1218) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Using custom gas multiplier in the wallet [\#1217](https://github.com/nymtech/nym/pull/1217) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/vesting accounts support [\#1216](https://github.com/nymtech/nym/pull/1216) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Release/1.0.0 rc.2 [\#1214](https://github.com/nymtech/nym/pull/1214) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- chore: fix dark mode rendering [\#1212](https://github.com/nymtech/nym/pull/1212) ([pwnfoo](https://github.com/pwnfoo))
|
||||
- Feature/spend coconut [\#1210](https://github.com/nymtech/nym/pull/1210) ([neacsu](https://github.com/neacsu))
|
||||
- Bugfix/unique sphinx key [\#1207](https://github.com/nymtech/nym/pull/1207) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Add cache read and write timeouts [\#1206](https://github.com/nymtech/nym/pull/1206) ([durch](https://github.com/durch))
|
||||
- Additional, more informative routes [\#1204](https://github.com/nymtech/nym/pull/1204) ([durch](https://github.com/durch))
|
||||
- Feature/aggregated econ dynamics explorer endpoint [\#1203](https://github.com/nymtech/nym/pull/1203) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Debugging validator [\#1198](https://github.com/nymtech/nym/pull/1198) ([durch](https://github.com/durch))
|
||||
- wallet: expose additional validator configuration functionality to the frontend [\#1195](https://github.com/nymtech/nym/pull/1195) ([octol](https://github.com/octol))
|
||||
- Update rewarding validator address [\#1193](https://github.com/nymtech/nym/pull/1193) ([durch](https://github.com/durch))
|
||||
- Crypto part of the Groth's NIDKG [\#1182](https://github.com/nymtech/nym/pull/1182) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- fix unbond page [\#1180](https://github.com/nymtech/nym/pull/1180) ([tommyv1987](https://github.com/tommyv1987))
|
||||
- Type safe bounds [\#1179](https://github.com/nymtech/nym/pull/1179) ([durch](https://github.com/durch))
|
||||
- Fix delegation paging [\#1174](https://github.com/nymtech/nym/pull/1174) ([durch](https://github.com/durch))
|
||||
- Update binaries to rc version [\#1172](https://github.com/nymtech/nym/pull/1172) ([tommyv1987](https://github.com/tommyv1987))
|
||||
- Bump ansi-regex from 4.1.0 to 4.1.1 in /docker/typescript\_client/upload\_contract [\#1171](https://github.com/nymtech/nym/pull/1171) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
|
||||
## [nym-binaries-1.0.0-rc.2](https://github.com/nymtech/nym/tree/nym-binaries-1.0.0-rc.2) (2022-04-15)
|
||||
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/nym-wallet-v1.0.2...nym-binaries-1.0.0-rc.2)
|
||||
|
||||
## [nym-wallet-v1.0.2](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.2) (2022-04-05)
|
||||
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/nym-wallet-v1.0.1...nym-wallet-v1.0.2)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Wallet 1.0.2 visual tweaks [\#1197](https://github.com/nymtech/nym/pull/1197) ([mmsinclair](https://github.com/mmsinclair))
|
||||
- Password for wallet with routes [\#1196](https://github.com/nymtech/nym/pull/1196) ([fmtabbara](https://github.com/fmtabbara))
|
||||
- Add auto-updater to Nym Wallet [\#1194](https://github.com/nymtech/nym/pull/1194) ([mmsinclair](https://github.com/mmsinclair))
|
||||
- Fix clippy warnings for beta toolchain [\#1191](https://github.com/nymtech/nym/pull/1191) ([octol](https://github.com/octol))
|
||||
- wallet: expose validator urls to the frontend [\#1190](https://github.com/nymtech/nym/pull/1190) ([octol](https://github.com/octol))
|
||||
- wallet: add test for decrypting stored wallet file [\#1189](https://github.com/nymtech/nym/pull/1189) ([octol](https://github.com/octol))
|
||||
- Fix clippy warnings [\#1188](https://github.com/nymtech/nym/pull/1188) ([octol](https://github.com/octol))
|
||||
- Password for wallet with routes [\#1187](https://github.com/nymtech/nym/pull/1187) ([mmsinclair](https://github.com/mmsinclair))
|
||||
- wallet: add validate\_mnemonic [\#1186](https://github.com/nymtech/nym/pull/1186) ([octol](https://github.com/octol))
|
||||
- wallet: support removing accounts from the wallet file [\#1185](https://github.com/nymtech/nym/pull/1185) ([octol](https://github.com/octol))
|
||||
- Feature/adding discord [\#1184](https://github.com/nymtech/nym/pull/1184) ([gala1234](https://github.com/gala1234))
|
||||
- wallet: config backend for validator selection [\#1183](https://github.com/nymtech/nym/pull/1183) ([octol](https://github.com/octol))
|
||||
- Add storybook to wallet [\#1178](https://github.com/nymtech/nym/pull/1178) ([mmsinclair](https://github.com/mmsinclair))
|
||||
- wallet: connection test nymd and api urls independently [\#1170](https://github.com/nymtech/nym/pull/1170) ([octol](https://github.com/octol))
|
||||
- wallet: wire up account storage [\#1153](https://github.com/nymtech/nym/pull/1153) ([octol](https://github.com/octol))
|
||||
- Feature/signature on deposit [\#1151](https://github.com/nymtech/nym/pull/1151) ([neacsu](https://github.com/neacsu))
|
||||
|
||||
## [nym-wallet-v1.0.1](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.1) (2022-04-05)
|
||||
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/nym-binaries-1.0.0-rc.1...nym-wallet-v1.0.1)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Check enabling bbbc simultaneously with open access. Estimate what it would take to make this the default compilation target. [\#1175](https://github.com/nymtech/nym/issues/1175)
|
||||
- Get coconut credential for deposited tokens [\#1138](https://github.com/nymtech/nym/issues/1138)
|
||||
- Make payments lazy [\#1135](https://github.com/nymtech/nym/issues/1135)
|
||||
- Uptime on node selection for sets [\#1049](https://github.com/nymtech/nym/issues/1049)
|
||||
|
||||
## [nym-binaries-1.0.0-rc.1](https://github.com/nymtech/nym/tree/nym-binaries-1.0.0-rc.1) (2022-03-28)
|
||||
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/nym-wallet-v1.0.0...nym-binaries-1.0.0-rc.1)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- \[Issue\]cargo build --release issue [\#1101](https://github.com/nymtech/nym/issues/1101)
|
||||
- appimage fail to load in Fedora [\#1098](https://github.com/nymtech/nym/issues/1098)
|
||||
- \[Issue\] React Example project does not compile when using @nymproject/nym-client-wasm v0.9.0-1 [\#878](https://github.com/nymtech/nym/issues/878)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Make mainnet coin transfers work [\#1096](https://github.com/nymtech/nym/issues/1096)
|
||||
- Make Nym wallet validators configurable at runtime [\#1026](https://github.com/nymtech/nym/issues/1026)
|
||||
- Project Platypus e2e / integration testing [\#942](https://github.com/nymtech/nym/issues/942)
|
||||
- \[Coconut\]: Replace ElGamal with Pedersen commitments [\#901](https://github.com/nymtech/nym/issues/901)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Different values for mixes and gateways [\#1169](https://github.com/nymtech/nym/pull/1169) ([durch](https://github.com/durch))
|
||||
- Add global blacklist to validator-cache [\#1168](https://github.com/nymtech/nym/pull/1168) ([durch](https://github.com/durch))
|
||||
- Feature/upgrade rewarding sandbox [\#1167](https://github.com/nymtech/nym/pull/1167) ([durch](https://github.com/durch))
|
||||
- Bump node-forge from 1.2.1 to 1.3.0 [\#1165](https://github.com/nymtech/nym/pull/1165) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump minimist from 1.2.5 to 1.2.6 in /nym-wallet/webdriver [\#1164](https://github.com/nymtech/nym/pull/1164) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump minimist from 1.2.5 to 1.2.6 in /clients/tauri-client [\#1163](https://github.com/nymtech/nym/pull/1163) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump minimist from 1.2.5 to 1.2.6 in /clients/webassembly/js-example [\#1162](https://github.com/nymtech/nym/pull/1162) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump minimist from 1.2.5 to 1.2.6 in /clients/native/examples/js-examples/websocket [\#1160](https://github.com/nymtech/nym/pull/1160) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump minimist from 1.2.5 to 1.2.6 in /docker/typescript\_client/upload\_contract [\#1159](https://github.com/nymtech/nym/pull/1159) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Feature/vesting full [\#1158](https://github.com/nymtech/nym/pull/1158) ([fmtabbara](https://github.com/fmtabbara))
|
||||
- get\_current\_epoch tauri [\#1156](https://github.com/nymtech/nym/pull/1156) ([durch](https://github.com/durch))
|
||||
- Cleanup [\#1155](https://github.com/nymtech/nym/pull/1155) ([durch](https://github.com/durch))
|
||||
- Feature flag reward payments [\#1154](https://github.com/nymtech/nym/pull/1154) ([durch](https://github.com/durch))
|
||||
- Add Query endpoints for calculating rewards [\#1152](https://github.com/nymtech/nym/pull/1152) ([durch](https://github.com/durch))
|
||||
- Pending endpoints [\#1150](https://github.com/nymtech/nym/pull/1150) ([durch](https://github.com/durch))
|
||||
- wallet: add logging [\#1149](https://github.com/nymtech/nym/pull/1149) ([octol](https://github.com/octol))
|
||||
- wallet: use Urls rather than Strings for validator urls [\#1148](https://github.com/nymtech/nym/pull/1148) ([octol](https://github.com/octol))
|
||||
- Change accumulated reward to Option, migrate delegations [\#1147](https://github.com/nymtech/nym/pull/1147) ([durch](https://github.com/durch))
|
||||
- wallet: fetch validators url remotely if available [\#1146](https://github.com/nymtech/nym/pull/1146) ([octol](https://github.com/octol))
|
||||
- Fix delegated\_free calculation [\#1145](https://github.com/nymtech/nym/pull/1145) ([durch](https://github.com/durch))
|
||||
- Update Nym wallet dependencies to use `ts-packages` [\#1144](https://github.com/nymtech/nym/pull/1144) ([mmsinclair](https://github.com/mmsinclair))
|
||||
- wallet: try validators one by one if available [\#1143](https://github.com/nymtech/nym/pull/1143) ([octol](https://github.com/octol))
|
||||
- Update Network Explorer Packages and add mix node identity key copy [\#1142](https://github.com/nymtech/nym/pull/1142) ([mmsinclair](https://github.com/mmsinclair))
|
||||
- Feature/vesting token pool selector [\#1140](https://github.com/nymtech/nym/pull/1140) ([fmtabbara](https://github.com/fmtabbara))
|
||||
- Add `ts-packages` for shared Typescript packages [\#1139](https://github.com/nymtech/nym/pull/1139) ([mmsinclair](https://github.com/mmsinclair))
|
||||
- allow main-net prefix and denom to work [\#1137](https://github.com/nymtech/nym/pull/1137) ([tommyv1987](https://github.com/tommyv1987))
|
||||
- Upgrade blake3 to v1.3.1 and tauri to 1.0.0-rc.3 [\#1136](https://github.com/nymtech/nym/pull/1136) ([mmsinclair](https://github.com/mmsinclair))
|
||||
- Bump url-parse from 1.5.7 to 1.5.10 in /clients/native/examples/js-examples/websocket [\#1134](https://github.com/nymtech/nym/pull/1134) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Use network explorer map data with disputed areas [\#1133](https://github.com/nymtech/nym/pull/1133) ([Baro1905](https://github.com/Baro1905))
|
||||
- Feature/vesting UI [\#1132](https://github.com/nymtech/nym/pull/1132) ([fmtabbara](https://github.com/fmtabbara))
|
||||
- Refactor to a lazy rewarding system [\#1127](https://github.com/nymtech/nym/pull/1127) ([durch](https://github.com/durch))
|
||||
- Bump ws from 6.2.1 to 6.2.2 in /clients/webassembly/js-example [\#1126](https://github.com/nymtech/nym/pull/1126) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump url-parse from 1.4.7 to 1.5.7 in /clients/webassembly/react-example [\#1125](https://github.com/nymtech/nym/pull/1125) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump url-parse from 1.5.4 to 1.5.7 in /clients/native/examples/js-examples/websocket [\#1124](https://github.com/nymtech/nym/pull/1124) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump url-parse from 1.5.1 to 1.5.7 in /clients/webassembly/js-example [\#1122](https://github.com/nymtech/nym/pull/1122) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- update contract address [\#1121](https://github.com/nymtech/nym/pull/1121) ([tommyv1987](https://github.com/tommyv1987))
|
||||
- Refactor GitHub Actions notifications [\#1119](https://github.com/nymtech/nym/pull/1119) ([mmsinclair](https://github.com/mmsinclair))
|
||||
- Change `pledge` to `bond` in gateway list [\#1118](https://github.com/nymtech/nym/pull/1118) ([mmsinclair](https://github.com/mmsinclair))
|
||||
- Bump follow-redirects from 1.14.7 to 1.14.8 in /contracts/basic-bandwidth-generation [\#1117](https://github.com/nymtech/nym/pull/1117) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump follow-redirects from 1.14.3 to 1.14.8 in /explorer [\#1116](https://github.com/nymtech/nym/pull/1116) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump follow-redirects from 1.14.5 to 1.14.8 in /nym-wallet [\#1115](https://github.com/nymtech/nym/pull/1115) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump follow-redirects from 1.14.7 to 1.14.8 in /clients/native/examples/js-examples/websocket [\#1114](https://github.com/nymtech/nym/pull/1114) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump follow-redirects from 1.14.7 to 1.14.8 in /testnet-faucet [\#1113](https://github.com/nymtech/nym/pull/1113) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump follow-redirects from 1.14.1 to 1.14.8 in /clients/webassembly/js-example [\#1112](https://github.com/nymtech/nym/pull/1112) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Feature/vesting get current period [\#1111](https://github.com/nymtech/nym/pull/1111) ([durch](https://github.com/durch))
|
||||
- Bump simple-get from 2.8.1 to 2.8.2 in /contracts/basic-bandwidth-generation [\#1110](https://github.com/nymtech/nym/pull/1110) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump simple-get from 3.1.0 to 3.1.1 in /explorer [\#1109](https://github.com/nymtech/nym/pull/1109) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump simple-get from 3.1.0 to 3.1.1 in /clients/tauri-client [\#1108](https://github.com/nymtech/nym/pull/1108) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump simple-get from 3.1.0 to 3.1.1 in /nym-wallet [\#1107](https://github.com/nymtech/nym/pull/1107) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump node-sass from 4.14.1 to 7.0.0 in /clients/webassembly/react-example [\#1105](https://github.com/nymtech/nym/pull/1105) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Fix hardcoded period logic [\#1104](https://github.com/nymtech/nym/pull/1104) ([durch](https://github.com/durch))
|
||||
- Fixed underflow in rewarding all delegators [\#1099](https://github.com/nymtech/nym/pull/1099) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Emit original bond as part of rewarding event [\#1094](https://github.com/nymtech/nym/pull/1094) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Add UpdateMixnodeConfigOnBehalf to vestng contract [\#1091](https://github.com/nymtech/nym/pull/1091) ([durch](https://github.com/durch))
|
||||
- Fixes infinite loops in requests involving pagination [\#1085](https://github.com/nymtech/nym/pull/1085) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Removes migration code [\#1071](https://github.com/nymtech/nym/pull/1071) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- feature/pedersen-commitments [\#1048](https://github.com/nymtech/nym/pull/1048) ([danielementary](https://github.com/danielementary))
|
||||
- Feature/reuse init owner [\#970](https://github.com/nymtech/nym/pull/970) ([neacsu](https://github.com/neacsu))
|
||||
|
||||
## [nym-wallet-v1.0.0](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.0) (2022-02-03)
|
||||
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/v0.12.1...nym-wallet-v1.0.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- \[Feature Request\] Please enable registration without need for Telegram account [\#1016](https://github.com/nymtech/nym/issues/1016)
|
||||
- Fast mixnode launch with a pre-built ISO + VM software [\#1001](https://github.com/nymtech/nym/issues/1001)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- \[Issue\] [\#1000](https://github.com/nymtech/nym/issues/1000)
|
||||
- \[Issue\] `nym-client` requires multiple attempts to run a server [\#869](https://github.com/nymtech/nym/issues/869)
|
||||
- De-'float'-ing `Interval` \(`Display` impl + `serde`\) [\#1065](https://github.com/nymtech/nym/pull/1065) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- display client address on wallet creation [\#1058](https://github.com/nymtech/nym/pull/1058) ([fmtabbara](https://github.com/fmtabbara))
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Rewarded set inclusion probability API endpoint [\#1037](https://github.com/nymtech/nym/issues/1037)
|
||||
- Update cw-storage-plus to 0.11 [\#1032](https://github.com/nymtech/nym/issues/1032)
|
||||
- Change `u128` fields in `RewardEstimationResponse` to `u64` [\#1029](https://github.com/nymtech/nym/issues/1029)
|
||||
- Test out the mainnet Gravity Bridge [\#1006](https://github.com/nymtech/nym/issues/1006)
|
||||
- Add vesting contract interface to nym-wallet [\#959](https://github.com/nymtech/nym/issues/959)
|
||||
- Mixnode crash [\#486](https://github.com/nymtech/nym/issues/486)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- create custom urls for mainnet [\#1095](https://github.com/nymtech/nym/pull/1095) ([fmtabbara](https://github.com/fmtabbara))
|
||||
- Wallet signing on MacOS [\#1093](https://github.com/nymtech/nym/pull/1093) ([mmsinclair](https://github.com/mmsinclair))
|
||||
- Fix rust 2018 idioms warnings [\#1092](https://github.com/nymtech/nym/pull/1092) ([octol](https://github.com/octol))
|
||||
- Prevent contract overwriting [\#1090](https://github.com/nymtech/nym/pull/1090) ([durch](https://github.com/durch))
|
||||
- Logout operation [\#1087](https://github.com/nymtech/nym/pull/1087) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Update to rust edition 2021 everywhere [\#1086](https://github.com/nymtech/nym/pull/1086) ([octol](https://github.com/octol))
|
||||
- Tag contract errors, and print out lines for easier QA [\#1084](https://github.com/nymtech/nym/pull/1084) ([durch](https://github.com/durch))
|
||||
- Feature/flexible vesting + utility queries [\#1083](https://github.com/nymtech/nym/pull/1083) ([durch](https://github.com/durch))
|
||||
- Bump @openzeppelin/contracts from 4.3.1 to 4.4.2 in /contracts/basic-bandwidth-generation [\#1082](https://github.com/nymtech/nym/pull/1082) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump nth-check from 2.0.0 to 2.0.1 in /clients/native/examples/js-examples/websocket [\#1081](https://github.com/nymtech/nym/pull/1081) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump url-parse from 1.5.1 to 1.5.4 in /clients/native/examples/js-examples/websocket [\#1080](https://github.com/nymtech/nym/pull/1080) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump follow-redirects from 1.14.1 to 1.14.7 in /clients/native/examples/js-examples/websocket [\#1079](https://github.com/nymtech/nym/pull/1079) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump nanoid from 3.1.23 to 3.2.0 in /clients/native/examples/js-examples/websocket [\#1078](https://github.com/nymtech/nym/pull/1078) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Setup basic test for mixnode stats reporting [\#1077](https://github.com/nymtech/nym/pull/1077) ([octol](https://github.com/octol))
|
||||
- Make wallet\_address mandatory for mixnode init [\#1076](https://github.com/nymtech/nym/pull/1076) ([octol](https://github.com/octol))
|
||||
- Tidy nym-mixnode module visibility [\#1075](https://github.com/nymtech/nym/pull/1075) ([octol](https://github.com/octol))
|
||||
- Feature/wallet login with password [\#1074](https://github.com/nymtech/nym/pull/1074) ([fmtabbara](https://github.com/fmtabbara))
|
||||
- Add trait to mock client dependency in DelayForwarder [\#1073](https://github.com/nymtech/nym/pull/1073) ([octol](https://github.com/octol))
|
||||
- Bump rust-version to latest stable for nym-mixnode [\#1072](https://github.com/nymtech/nym/pull/1072) ([octol](https://github.com/octol))
|
||||
- Fixes CI for our wasm build [\#1069](https://github.com/nymtech/nym/pull/1069) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Add @octol as codeowner [\#1068](https://github.com/nymtech/nym/pull/1068) ([octol](https://github.com/octol))
|
||||
- set-up inclusion probability [\#1067](https://github.com/nymtech/nym/pull/1067) ([fmtabbara](https://github.com/fmtabbara))
|
||||
- Feature/wasm client [\#1066](https://github.com/nymtech/nym/pull/1066) ([neacsu](https://github.com/neacsu))
|
||||
- Changed bech32\_prefix from punk to nymt [\#1064](https://github.com/nymtech/nym/pull/1064) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Bump nanoid from 3.1.30 to 3.2.0 in /testnet-faucet [\#1063](https://github.com/nymtech/nym/pull/1063) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump nanoid from 3.1.30 to 3.2.0 in /nym-wallet [\#1062](https://github.com/nymtech/nym/pull/1062) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Rework vesting contract storage [\#1061](https://github.com/nymtech/nym/pull/1061) ([durch](https://github.com/durch))
|
||||
- Mixnet Contract constants extraction [\#1060](https://github.com/nymtech/nym/pull/1060) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- fix: make explorer footer year dynamic [\#1059](https://github.com/nymtech/nym/pull/1059) ([martinyung](https://github.com/martinyung))
|
||||
- Add mnemonic just on creation, to display it [\#1057](https://github.com/nymtech/nym/pull/1057) ([neacsu](https://github.com/neacsu))
|
||||
- Network Explorer: updates to API and UI to show the active set [\#1056](https://github.com/nymtech/nym/pull/1056) ([mmsinclair](https://github.com/mmsinclair))
|
||||
- Made contract addresses for query NymdClient construction optional [\#1055](https://github.com/nymtech/nym/pull/1055) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Introduced RPC query for total token supply [\#1053](https://github.com/nymtech/nym/pull/1053) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/tokio console [\#1052](https://github.com/nymtech/nym/pull/1052) ([durch](https://github.com/durch))
|
||||
- Implemented beta clippy lint recommendations [\#1051](https://github.com/nymtech/nym/pull/1051) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- add new function to update profit percentage [\#1050](https://github.com/nymtech/nym/pull/1050) ([fmtabbara](https://github.com/fmtabbara))
|
||||
- Upgrade Clap and use declarative argument parsing for nym-mixnode [\#1047](https://github.com/nymtech/nym/pull/1047) ([octol](https://github.com/octol))
|
||||
- Feature/additional bond validation [\#1046](https://github.com/nymtech/nym/pull/1046) ([fmtabbara](https://github.com/fmtabbara))
|
||||
- Fix clippy on relevant lints [\#1044](https://github.com/nymtech/nym/pull/1044) ([neacsu](https://github.com/neacsu))
|
||||
- Bump shelljs from 0.8.4 to 0.8.5 in /contracts/basic-bandwidth-generation [\#1043](https://github.com/nymtech/nym/pull/1043) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Endpoint for rewarded set inclusion probabilities [\#1042](https://github.com/nymtech/nym/pull/1042) ([durch](https://github.com/durch))
|
||||
- Bump follow-redirects from 1.14.4 to 1.14.7 in /contracts/basic-bandwidth-generation [\#1041](https://github.com/nymtech/nym/pull/1041) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Bump follow-redirects from 1.14.5 to 1.14.7 in /testnet-faucet [\#1040](https://github.com/nymtech/nym/pull/1040) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Feature/node settings update [\#1036](https://github.com/nymtech/nym/pull/1036) ([fmtabbara](https://github.com/fmtabbara))
|
||||
- Migrate to cw-storage-plus 0.11.1 [\#1035](https://github.com/nymtech/nym/pull/1035) ([durch](https://github.com/durch))
|
||||
- Bump @openzeppelin/contracts from 4.4.1 to 4.4.2 in /contracts/basic-bandwidth-generation [\#1034](https://github.com/nymtech/nym/pull/1034) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Feature/configurable wallet [\#1033](https://github.com/nymtech/nym/pull/1033) ([neacsu](https://github.com/neacsu))
|
||||
- Feature/downcast reward estimation [\#1031](https://github.com/nymtech/nym/pull/1031) ([durch](https://github.com/durch))
|
||||
- Wallet UI updates [\#1028](https://github.com/nymtech/nym/pull/1028) ([fmtabbara](https://github.com/fmtabbara))
|
||||
- Remove migration code [\#1027](https://github.com/nymtech/nym/pull/1027) ([neacsu](https://github.com/neacsu))
|
||||
- Chore/stricter dependency requirements [\#1025](https://github.com/nymtech/nym/pull/1025) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/validator api client endpoints [\#1024](https://github.com/nymtech/nym/pull/1024) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Updated cosmrs to 0.4.1 [\#1023](https://github.com/nymtech/nym/pull/1023) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/testnet deploy scripts [\#1022](https://github.com/nymtech/nym/pull/1022) ([mfahampshire](https://github.com/mfahampshire))
|
||||
- Changed wallet's client to a full validator client [\#1021](https://github.com/nymtech/nym/pull/1021) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Fix 404 link [\#1020](https://github.com/nymtech/nym/pull/1020) ([RiccardoMasutti](https://github.com/RiccardoMasutti))
|
||||
- Feature/additional mixnode endpoints [\#1019](https://github.com/nymtech/nym/pull/1019) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Introduced denom check when trying to withdraw vested coins [\#1018](https://github.com/nymtech/nym/pull/1018) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Add network defaults for qa [\#1017](https://github.com/nymtech/nym/pull/1017) ([neacsu](https://github.com/neacsu))
|
||||
- Feature/expanded events [\#1015](https://github.com/nymtech/nym/pull/1015) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- update frontend to use new profit update api [\#1014](https://github.com/nymtech/nym/pull/1014) ([fmtabbara](https://github.com/fmtabbara))
|
||||
- Feature/node state endpoint [\#1013](https://github.com/nymtech/nym/pull/1013) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Feature/hourly set updates [\#1012](https://github.com/nymtech/nym/pull/1012) ([durch](https://github.com/durch))
|
||||
- Feature/remove unused profit margin [\#1011](https://github.com/nymtech/nym/pull/1011) ([neacsu](https://github.com/neacsu))
|
||||
- Feature/explorer node status [\#1010](https://github.com/nymtech/nym/pull/1010) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Use serial integer instead of random [\#1009](https://github.com/nymtech/nym/pull/1009) ([durch](https://github.com/durch))
|
||||
- Feature/configure profit [\#1008](https://github.com/nymtech/nym/pull/1008) ([neacsu](https://github.com/neacsu))
|
||||
- Feature/fix gateway sign [\#1004](https://github.com/nymtech/nym/pull/1004) ([neacsu](https://github.com/neacsu))
|
||||
- Fix clippy [\#1003](https://github.com/nymtech/nym/pull/1003) ([neacsu](https://github.com/neacsu))
|
||||
- Update wallet version [\#998](https://github.com/nymtech/nym/pull/998) ([tommyv1987](https://github.com/tommyv1987))
|
||||
- Fix wallet build instructions [\#997](https://github.com/nymtech/nym/pull/997) ([tommyv1987](https://github.com/tommyv1987))
|
||||
- Make the separation between testnet-mode and erc20 bandwidth mode clearer [\#994](https://github.com/nymtech/nym/pull/994) ([neacsu](https://github.com/neacsu))
|
||||
- Bump @openzeppelin/contracts from 3.4.0 to 4.4.1 in /contracts/basic-bandwidth-generation [\#983](https://github.com/nymtech/nym/pull/983) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||
- Feature/implicit runtime [\#973](https://github.com/nymtech/nym/pull/973) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Differentiate staking and ownership [\#961](https://github.com/nymtech/nym/pull/961) ([durch](https://github.com/durch))
|
||||
|
||||
## [v0.12.1](https://github.com/nymtech/nym/tree/v0.12.1) (2021-12-23)
|
||||
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/v0.12.0...v0.12.1)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Add version check to binaries [\#967](https://github.com/nymtech/nym/issues/967)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- \[Issue\] NYM wallet doesn't work after login [\#995](https://github.com/nymtech/nym/issues/995)
|
||||
- \[Issue\] [\#993](https://github.com/nymtech/nym/issues/993)
|
||||
- NYM wallet setup trouble\[Issue\] [\#958](https://github.com/nymtech/nym/issues/958)
|
||||
|
||||
## [v0.12.0](https://github.com/nymtech/nym/tree/v0.12.0) (2021-12-21)
|
||||
|
||||
[Full Changelog](https://github.com/nymtech/nym/compare/v0.11.0...v0.12.0)
|
||||
@@ -391,7 +58,6 @@
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Update wallet to align with versioning on nodes and gateways [\#991](https://github.com/nymtech/nym/pull/991) ([tommyv1987](https://github.com/tommyv1987))
|
||||
- Fix success view messages. [\#990](https://github.com/nymtech/nym/pull/990) ([tommyv1987](https://github.com/tommyv1987))
|
||||
- Feature/enable signature check [\#989](https://github.com/nymtech/nym/pull/989) ([neacsu](https://github.com/neacsu))
|
||||
- Update mixnet contract address [\#988](https://github.com/nymtech/nym/pull/988) ([neacsu](https://github.com/neacsu))
|
||||
|
||||
Generated
+10
-22
@@ -581,7 +581,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "client-core"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0-rc.2"
|
||||
dependencies = [
|
||||
"config",
|
||||
"crypto",
|
||||
@@ -648,7 +648,6 @@ dependencies = [
|
||||
name = "config"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"handlebars",
|
||||
"humantime-serde",
|
||||
"log",
|
||||
@@ -1063,8 +1062,6 @@ dependencies = [
|
||||
"pemstore",
|
||||
"rand 0.7.3",
|
||||
"rand_chacha 0.2.2",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
"subtle-encoding",
|
||||
"x25519-dalek",
|
||||
]
|
||||
@@ -1429,7 +1426,6 @@ version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d5c4b5e5959dc2c2b89918d8e2cc40fcdd623cef026ed09d2f0ee05199dc8e4"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"signature",
|
||||
]
|
||||
|
||||
@@ -1443,7 +1439,6 @@ dependencies = [
|
||||
"ed25519",
|
||||
"rand 0.7.3",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
"sha2",
|
||||
"zeroize",
|
||||
]
|
||||
@@ -1599,7 +1594,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "explorer-api"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0-rc.2"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"humantime-serde",
|
||||
@@ -3048,7 +3043,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-client"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0-rc.2"
|
||||
dependencies = [
|
||||
"clap 2.34.0",
|
||||
"client-core",
|
||||
@@ -3083,7 +3078,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-gateway"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0-rc.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -3129,7 +3124,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-mixnode"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0-rc.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bs58",
|
||||
@@ -3167,26 +3162,20 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-network-requester"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0-rc.2"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"clap 2.34.0",
|
||||
"dirs",
|
||||
"futures",
|
||||
"ipnetwork",
|
||||
"log",
|
||||
"network-defaults",
|
||||
"nymsphinx",
|
||||
"ordered-buffer",
|
||||
"pretty_env_logger",
|
||||
"proxy-helpers",
|
||||
"publicsuffix",
|
||||
"rand 0.7.3",
|
||||
"rocket",
|
||||
"serde",
|
||||
"socks5-requests",
|
||||
"sqlx",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"websocket-requests",
|
||||
@@ -3194,7 +3183,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0-rc.2"
|
||||
dependencies = [
|
||||
"clap 2.34.0",
|
||||
"client-core",
|
||||
@@ -3230,7 +3219,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-validator-api"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0-rc.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -4838,9 +4827,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_bytes"
|
||||
version = "0.11.6"
|
||||
version = "0.11.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "212e73464ebcde48d723aa02eb270ba62eff38a9b732df31f33f1b4e145f3a54"
|
||||
checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@@ -5229,7 +5218,6 @@ dependencies = [
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"crc",
|
||||
"crossbeam-queue",
|
||||
"either",
|
||||
|
||||
@@ -9,10 +9,6 @@ overflow-checks = true
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
[profile.test]
|
||||
# equivalent of running in `--release` (but since we're in test profile we're keeping overflow checks and all of those by default)
|
||||
opt-level = 3
|
||||
|
||||
[workspace]
|
||||
|
||||
resolver = "2"
|
||||
|
||||
@@ -26,7 +26,7 @@ clippy-all-wallet:
|
||||
cargo clippy --workspace --manifest-path nym-wallet/Cargo.toml --all-features -- -D warnings
|
||||
|
||||
test-main:
|
||||
cargo test --all-features --workspace
|
||||
cargo test --all-features --workspace --release
|
||||
|
||||
test-contracts:
|
||||
cargo test --manifest-path contracts/Cargo.toml --all-features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "client-core"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0-rc.2"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -110,8 +110,8 @@ impl<T: NymConfig> Config<T> {
|
||||
self.client.id = id;
|
||||
}
|
||||
|
||||
pub fn with_disabled_credentials(&mut self, disabled_credentials_mode: bool) {
|
||||
self.client.disabled_credentials_mode = disabled_credentials_mode;
|
||||
pub fn with_testnet_mode(&mut self, testnet_mode: bool) {
|
||||
self.client.testnet_mode = testnet_mode;
|
||||
}
|
||||
|
||||
pub fn with_gateway_endpoint<S: Into<String>>(&mut self, id: S, owner: S, listener: S) {
|
||||
@@ -154,8 +154,8 @@ impl<T: NymConfig> Config<T> {
|
||||
self.client.id.clone()
|
||||
}
|
||||
|
||||
pub fn get_disabled_credentials_mode(&self) -> bool {
|
||||
self.client.disabled_credentials_mode
|
||||
pub fn get_testnet_mode(&self) -> bool {
|
||||
self.client.testnet_mode
|
||||
}
|
||||
|
||||
pub fn get_nym_root_directory(&self) -> PathBuf {
|
||||
@@ -294,10 +294,10 @@ pub struct Client<T> {
|
||||
/// ID specifies the human readable ID of this particular client.
|
||||
id: String,
|
||||
|
||||
/// Indicates whether this client is running in a disabled credentials mode, thus attempting
|
||||
/// Indicates whether this client is running in a testnet mode, thus attempting
|
||||
/// to claim bandwidth without presenting bandwidth credentials.
|
||||
#[serde(default)]
|
||||
disabled_credentials_mode: bool,
|
||||
testnet_mode: bool,
|
||||
|
||||
/// Addresses to APIs running on validator from which the client gets the view of the network.
|
||||
validator_api_urls: Vec<Url>,
|
||||
@@ -354,7 +354,7 @@ impl<T: NymConfig> Default for Client<T> {
|
||||
Client {
|
||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
id: "".to_string(),
|
||||
disabled_credentials_mode: true,
|
||||
testnet_mode: false,
|
||||
validator_api_urls: default_api_endpoints(),
|
||||
private_identity_key_file: Default::default(),
|
||||
public_identity_key_file: Default::default(),
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0-rc.2"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.56"
|
||||
|
||||
@@ -592,9 +592,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/async": {
|
||||
"version": "2.6.4",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
|
||||
"integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
|
||||
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.14"
|
||||
@@ -4825,9 +4825,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"async": {
|
||||
"version": "2.6.4",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
|
||||
"integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
|
||||
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash": "^4.17.14"
|
||||
|
||||
@@ -19,9 +19,9 @@ version = '{{ client.version }}'
|
||||
# Human readable ID of this particular client.
|
||||
id = '{{ client.id }}'
|
||||
|
||||
# Indicates whether this client is running in a disabled credentials mode, thus attempting
|
||||
# Indicates whether this client is running in a testnet mode, thus attempting
|
||||
# to claim bandwidth without presenting bandwidth credentials.
|
||||
disabled_credentials_mode = {{ client.disabled_credentials_mode }}
|
||||
testnet_mode = {{ client.testnet_mode }}
|
||||
|
||||
# Addresses to APIs running on validator from which the client gets the view of the network.
|
||||
validator_api_urls = [
|
||||
|
||||
@@ -199,8 +199,8 @@ impl NymClient {
|
||||
Some(bandwidth_controller),
|
||||
);
|
||||
|
||||
if self.config.get_base().get_disabled_credentials_mode() {
|
||||
gateway_client.set_disabled_credentials_mode(true)
|
||||
if self.config.get_base().get_testnet_mode() {
|
||||
gateway_client.set_testnet_mode(true)
|
||||
}
|
||||
gateway_client
|
||||
.authenticate_and_start()
|
||||
|
||||
@@ -24,8 +24,8 @@ use crate::commands::override_config;
|
||||
#[cfg(feature = "eth")]
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use crate::commands::{
|
||||
DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY, ENABLED_CREDENTIALS_MODE_ARG_NAME,
|
||||
ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME,
|
||||
DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY, ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME,
|
||||
TESTNET_MODE_ARG_NAME,
|
||||
};
|
||||
|
||||
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
@@ -66,22 +66,22 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
let app = app
|
||||
.arg(
|
||||
Arg::with_name(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
||||
.long(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
||||
.help("Set this client to work in a disabled credentials mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
|
||||
Arg::with_name(TESTNET_MODE_ARG_NAME)
|
||||
.long(TESTNET_MODE_ARG_NAME)
|
||||
.help("Set this client to work in a testnet mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
|
||||
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
|
||||
)
|
||||
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
|
||||
.long(ETH_ENDPOINT_ARG_NAME)
|
||||
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
|
||||
.takes_value(true)
|
||||
.default_value_if(ENABLED_CREDENTIALS_MODE_ARG_NAME, None, DEFAULT_ETH_ENDPOINT)
|
||||
.default_value_if(TESTNET_MODE_ARG_NAME, None, DEFAULT_ETH_ENDPOINT)
|
||||
.required(true))
|
||||
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME)
|
||||
.long(ETH_PRIVATE_KEY_ARG_NAME)
|
||||
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
|
||||
.takes_value(true)
|
||||
.default_value_if(ENABLED_CREDENTIALS_MODE_ARG_NAME, None, DEFAULT_ETH_PRIVATE_KEY)
|
||||
.default_value_if(TESTNET_MODE_ARG_NAME, None, DEFAULT_ETH_PRIVATE_KEY)
|
||||
.required(true)
|
||||
);
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::client::config::{Config, SocketType};
|
||||
use clap::ArgMatches;
|
||||
use url::Url;
|
||||
|
||||
pub(crate) const ENABLED_CREDENTIALS_MODE_ARG_NAME: &str = "enabled-credentials-mode";
|
||||
pub(crate) const TESTNET_MODE_ARG_NAME: &str = "testnet-mode";
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
pub(crate) const ETH_ENDPOINT_ARG_NAME: &str = "eth_endpoint";
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
@@ -72,8 +72,8 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> C
|
||||
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY);
|
||||
}
|
||||
|
||||
if matches.is_present(ENABLED_CREDENTIALS_MODE_ARG_NAME) {
|
||||
config.get_base_mut().with_disabled_credentials(false)
|
||||
if !cfg!(feature = "eth") || matches.is_present(TESTNET_MODE_ARG_NAME) {
|
||||
config.get_base_mut().with_testnet_mode(true)
|
||||
}
|
||||
|
||||
config
|
||||
|
||||
@@ -6,9 +6,7 @@ use crate::client::NymClient;
|
||||
use crate::commands::override_config;
|
||||
#[cfg(feature = "eth")]
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use crate::commands::{
|
||||
ENABLED_CREDENTIALS_MODE_ARG_NAME, ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME,
|
||||
};
|
||||
use crate::commands::{ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME, TESTNET_MODE_ARG_NAME};
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use config::NymConfig;
|
||||
use log::*;
|
||||
@@ -48,9 +46,9 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
let app = app
|
||||
.arg(
|
||||
Arg::with_name(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
||||
.long(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
||||
.help("Set this client to work in a enabled credentials mode that would attempt to use gateway with bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
|
||||
Arg::with_name(TESTNET_MODE_ARG_NAME)
|
||||
.long(TESTNET_MODE_ARG_NAME)
|
||||
.help("Set this client to work in a testnet mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
|
||||
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
|
||||
)
|
||||
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::{crate_version, App, ArgMatches};
|
||||
use network_defaults::DEFAULT_NETWORK;
|
||||
|
||||
pub mod client;
|
||||
pub mod commands;
|
||||
@@ -68,7 +67,6 @@ fn long_version() -> String {
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
"#,
|
||||
"Build Timestamp:",
|
||||
env!("VERGEN_BUILD_TIMESTAMP"),
|
||||
@@ -86,8 +84,6 @@ fn long_version() -> String {
|
||||
env!("VERGEN_RUSTC_CHANNEL"),
|
||||
"cargo Profile:",
|
||||
env!("VERGEN_CARGO_PROFILE"),
|
||||
"Network:",
|
||||
DEFAULT_NETWORK
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0-rc.2"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.56"
|
||||
|
||||
@@ -19,9 +19,9 @@ version = '{{ client.version }}'
|
||||
# Human readable ID of this particular client.
|
||||
id = '{{ client.id }}'
|
||||
|
||||
# Indicates whether this client is running in a disabled credentials mode, thus attempting
|
||||
# Indicates whether this client is running in a testnet mode, thus attempting
|
||||
# to claim bandwidth without presenting bandwidth credentials.
|
||||
disabled_credentials_mode = {{ client.disabled_credentials_mode }}
|
||||
testnet_mode = {{ client.testnet_mode }}
|
||||
|
||||
# Addresses to APIs running on validator from which the client gets the view of the network.
|
||||
validator_api_urls = [
|
||||
|
||||
@@ -187,8 +187,8 @@ impl NymClient {
|
||||
Some(bandwidth_controller),
|
||||
);
|
||||
|
||||
if self.config.get_base().get_disabled_credentials_mode() {
|
||||
gateway_client.set_disabled_credentials_mode(true)
|
||||
if self.config.get_base().get_testnet_mode() {
|
||||
gateway_client.set_testnet_mode(true)
|
||||
}
|
||||
gateway_client
|
||||
.authenticate_and_start()
|
||||
|
||||
@@ -22,8 +22,8 @@ use crate::commands::override_config;
|
||||
#[cfg(feature = "eth")]
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use crate::commands::{
|
||||
DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY, ENABLED_CREDENTIALS_MODE_ARG_NAME,
|
||||
ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME,
|
||||
DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY, ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME,
|
||||
TESTNET_MODE_ARG_NAME,
|
||||
};
|
||||
|
||||
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
@@ -66,22 +66,22 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
let app = app
|
||||
.arg(
|
||||
Arg::with_name(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
||||
.long(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
||||
.help("Set this client to work in a enabled credentials mode that would attempt to use gateway with bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
|
||||
Arg::with_name(TESTNET_MODE_ARG_NAME)
|
||||
.long(TESTNET_MODE_ARG_NAME)
|
||||
.help("Set this client to work in a testnet mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
|
||||
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
|
||||
)
|
||||
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
|
||||
.long(ETH_ENDPOINT_ARG_NAME)
|
||||
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
|
||||
.takes_value(true)
|
||||
.default_value_if(ENABLED_CREDENTIALS_MODE_ARG_NAME, None, DEFAULT_ETH_ENDPOINT)
|
||||
.default_value_if(TESTNET_MODE_ARG_NAME, None, DEFAULT_ETH_ENDPOINT)
|
||||
.required(true))
|
||||
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME)
|
||||
.long(ETH_PRIVATE_KEY_ARG_NAME)
|
||||
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
|
||||
.takes_value(true)
|
||||
.default_value_if(ENABLED_CREDENTIALS_MODE_ARG_NAME, None, DEFAULT_ETH_PRIVATE_KEY)
|
||||
.default_value_if(TESTNET_MODE_ARG_NAME, None, DEFAULT_ETH_PRIVATE_KEY)
|
||||
.required(true)
|
||||
);
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ pub(crate) mod init;
|
||||
pub(crate) mod run;
|
||||
pub(crate) mod upgrade;
|
||||
|
||||
pub(crate) const ENABLED_CREDENTIALS_MODE_ARG_NAME: &str = "enabled-credentials-mode";
|
||||
pub(crate) const TESTNET_MODE_ARG_NAME: &str = "testnet-mode";
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
pub(crate) const ETH_ENDPOINT_ARG_NAME: &str = "eth_endpoint";
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
@@ -68,8 +68,8 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> C
|
||||
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY);
|
||||
}
|
||||
|
||||
if matches.is_present(ENABLED_CREDENTIALS_MODE_ARG_NAME) {
|
||||
config.get_base_mut().with_disabled_credentials(false)
|
||||
if !cfg!(feature = "eth") || matches.is_present(TESTNET_MODE_ARG_NAME) {
|
||||
config.get_base_mut().with_testnet_mode(true)
|
||||
}
|
||||
|
||||
config
|
||||
|
||||
@@ -6,9 +6,7 @@ use crate::client::NymClient;
|
||||
use crate::commands::override_config;
|
||||
#[cfg(feature = "eth")]
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use crate::commands::{
|
||||
ENABLED_CREDENTIALS_MODE_ARG_NAME, ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME,
|
||||
};
|
||||
use crate::commands::{ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME, TESTNET_MODE_ARG_NAME};
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use config::NymConfig;
|
||||
use log::*;
|
||||
@@ -54,9 +52,9 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
let app = app
|
||||
.arg(
|
||||
Arg::with_name(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
||||
.long(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
||||
.help("Set this client to work in a disabled credentials mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
|
||||
Arg::with_name(TESTNET_MODE_ARG_NAME)
|
||||
.long(TESTNET_MODE_ARG_NAME)
|
||||
.help("Set this client to work in a testnet mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
|
||||
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
|
||||
)
|
||||
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::{crate_version, App, ArgMatches};
|
||||
use network_defaults::DEFAULT_NETWORK;
|
||||
|
||||
pub mod client;
|
||||
mod commands;
|
||||
@@ -68,7 +67,6 @@ fn long_version() -> String {
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
"#,
|
||||
"Build Timestamp:",
|
||||
env!("VERGEN_BUILD_TIMESTAMP"),
|
||||
@@ -86,8 +84,6 @@ fn long_version() -> String {
|
||||
env!("VERGEN_RUSTC_CHANNEL"),
|
||||
"cargo Profile:",
|
||||
env!("VERGEN_CARGO_PROFILE"),
|
||||
"Network:",
|
||||
DEFAULT_NETWORK
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ use proxy_helpers::connection_controller::{
|
||||
};
|
||||
use proxy_helpers::proxy_runner::ProxyRunner;
|
||||
use rand::RngCore;
|
||||
use socks5_requests::{ConnectionId, Message, RemoteAddress, Request};
|
||||
use socks5_requests::{ConnectionId, RemoteAddress, Request};
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use std::pin::Pin;
|
||||
@@ -224,9 +224,8 @@ impl SocksClient {
|
||||
|
||||
async fn send_connect_to_mixnet(&mut self, remote_address: RemoteAddress) {
|
||||
let req = Request::new_connect(self.connection_id, remote_address, self.self_address);
|
||||
let msg = Message::Request(req);
|
||||
|
||||
let input_message = InputMessage::new_fresh(self.service_provider, msg.into_bytes(), false);
|
||||
let input_message = InputMessage::new_fresh(self.service_provider, req.into_bytes(), false);
|
||||
self.input_sender.unbounded_send(input_message).unwrap();
|
||||
}
|
||||
|
||||
@@ -253,8 +252,7 @@ impl SocksClient {
|
||||
)
|
||||
.run(move |conn_id, read_data, socket_closed| {
|
||||
let provider_request = Request::new_send(conn_id, read_data, socket_closed);
|
||||
let provider_message = Message::Request(provider_request);
|
||||
InputMessage::new_fresh(recipient, provider_message.into_bytes(), false)
|
||||
InputMessage::new_fresh(recipient, provider_request.into_bytes(), false)
|
||||
})
|
||||
.await
|
||||
.into_inner();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "nym-client-wasm"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jedrzej Stuczynski <andrew@nymtech.net>"]
|
||||
version = "1.0.1"
|
||||
version = "1.0.0-rc.2"
|
||||
edition = "2021"
|
||||
keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy", "client"]
|
||||
license = "Apache-2.0"
|
||||
|
||||
+8
-7
@@ -24,7 +24,8 @@
|
||||
},
|
||||
"../pkg": {
|
||||
"name": "@nymproject/nym-client-wasm",
|
||||
"version": "0.0.1"
|
||||
"version": "0.12.0",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@discoveryjs/json-ext": {
|
||||
"version": "0.5.7",
|
||||
@@ -585,9 +586,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/async": {
|
||||
"version": "2.6.4",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
|
||||
"integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
|
||||
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.14"
|
||||
@@ -4304,9 +4305,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"async": {
|
||||
"version": "2.6.4",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
|
||||
"integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
|
||||
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash": "^4.17.14"
|
||||
|
||||
@@ -26,7 +26,7 @@ const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_millis(1_500);
|
||||
#[wasm_bindgen]
|
||||
pub struct NymClient {
|
||||
validator_server: Url,
|
||||
disabled_credentials_mode: bool,
|
||||
testnet_mode: bool,
|
||||
|
||||
// TODO: technically this doesn't need to be an Arc since wasm is run on a single thread
|
||||
// however, once we eventually combine this code with the native-client's, it will make things
|
||||
@@ -72,7 +72,7 @@ impl NymClient {
|
||||
|
||||
on_message: None,
|
||||
on_gateway_connect: None,
|
||||
disabled_credentials_mode: true,
|
||||
testnet_mode: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,12 +85,9 @@ impl NymClient {
|
||||
self.on_gateway_connect = Some(on_connect)
|
||||
}
|
||||
|
||||
pub fn set_disabled_credentials_mode(&mut self, disabled_credentials_mode: bool) {
|
||||
console_log!(
|
||||
"Setting disabled credentials mode to {}",
|
||||
disabled_credentials_mode
|
||||
);
|
||||
self.disabled_credentials_mode = disabled_credentials_mode;
|
||||
pub fn set_testnet_mode(&mut self, testnet_mode: bool) {
|
||||
console_log!("Setting testnet mode to {}", testnet_mode);
|
||||
self.testnet_mode = testnet_mode;
|
||||
}
|
||||
|
||||
fn self_recipient(&self) -> Recipient {
|
||||
@@ -110,7 +107,7 @@ impl NymClient {
|
||||
|
||||
// Right now it's impossible to have async exported functions to take `&self` rather than self
|
||||
pub async fn initial_setup(self) -> Self {
|
||||
let disabled_credentials_mode = self.disabled_credentials_mode;
|
||||
let testnet_mode = self.testnet_mode;
|
||||
|
||||
let bandwidth_controller = None;
|
||||
|
||||
@@ -132,8 +129,8 @@ impl NymClient {
|
||||
bandwidth_controller,
|
||||
);
|
||||
|
||||
if disabled_credentials_mode {
|
||||
gateway_client.set_disabled_credentials_mode(true)
|
||||
if testnet_mode {
|
||||
gateway_client.set_testnet_mode(true)
|
||||
}
|
||||
|
||||
gateway_client
|
||||
|
||||
@@ -45,7 +45,7 @@ const DEFAULT_RECONNECTION_BACKOFF: Duration = Duration::from_secs(5);
|
||||
|
||||
pub struct GatewayClient {
|
||||
authenticated: bool,
|
||||
disabled_credentials_mode: bool,
|
||||
testnet_mode: bool,
|
||||
bandwidth_remaining: i64,
|
||||
gateway_address: String,
|
||||
gateway_identity: identity::PublicKey,
|
||||
@@ -83,7 +83,7 @@ impl GatewayClient {
|
||||
) -> Self {
|
||||
GatewayClient {
|
||||
authenticated: false,
|
||||
disabled_credentials_mode: true,
|
||||
testnet_mode: false,
|
||||
bandwidth_remaining: 0,
|
||||
gateway_address,
|
||||
gateway_identity,
|
||||
@@ -100,8 +100,8 @@ impl GatewayClient {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_disabled_credentials_mode(&mut self, disabled_credentials_mode: bool) {
|
||||
self.disabled_credentials_mode = disabled_credentials_mode
|
||||
pub fn set_testnet_mode(&mut self, testnet_mode: bool) {
|
||||
self.testnet_mode = testnet_mode
|
||||
}
|
||||
|
||||
// TODO: later convert into proper builder methods
|
||||
@@ -134,7 +134,7 @@ impl GatewayClient {
|
||||
|
||||
GatewayClient {
|
||||
authenticated: false,
|
||||
disabled_credentials_mode: true,
|
||||
testnet_mode: false,
|
||||
bandwidth_remaining: 0,
|
||||
gateway_address,
|
||||
gateway_identity,
|
||||
@@ -548,13 +548,13 @@ impl GatewayClient {
|
||||
if self.shared_key.is_none() {
|
||||
return Err(GatewayClientError::NoSharedKeyAvailable);
|
||||
}
|
||||
if self.bandwidth_controller.is_none() && !self.disabled_credentials_mode {
|
||||
if self.bandwidth_controller.is_none() && !self.testnet_mode {
|
||||
return Err(GatewayClientError::NoBandwidthControllerAvailable);
|
||||
}
|
||||
|
||||
warn!("Not enough bandwidth. Trying to get more bandwidth, this might take a while");
|
||||
if self.disabled_credentials_mode {
|
||||
info!("The client is running in disabled credentials mode - attempting to claim bandwidth without a credential");
|
||||
if self.testnet_mode {
|
||||
info!("The client is running in testnet mode - attempting to claim bandwidth without a credential");
|
||||
return self.try_claim_testnet_bandwidth().await;
|
||||
}
|
||||
|
||||
|
||||
@@ -133,14 +133,20 @@ impl Client {
|
||||
if current_attempt == 0 {
|
||||
None
|
||||
} else {
|
||||
let exp = 2_u32.checked_pow(current_attempt);
|
||||
let backoff = exp
|
||||
.and_then(|exp| self.config.initial_reconnection_backoff.checked_mul(exp))
|
||||
.unwrap_or(self.config.maximum_reconnection_backoff);
|
||||
// according to https://github.com/tokio-rs/tokio/issues/1953 there's an undocumented
|
||||
// limit of tokio delay of about 2 years.
|
||||
// let's ensure our delay is always on a sane side of being maximum 1 hour.
|
||||
let maximum_sane_delay = Duration::from_secs(60 * 60);
|
||||
|
||||
Some(std::cmp::min(
|
||||
backoff,
|
||||
self.config.maximum_reconnection_backoff,
|
||||
maximum_sane_delay,
|
||||
std::cmp::min(
|
||||
self.config
|
||||
.initial_reconnection_backoff
|
||||
.checked_mul(2_u32.pow(current_attempt))
|
||||
.unwrap_or(self.config.maximum_reconnection_backoff),
|
||||
self.config.maximum_reconnection_backoff,
|
||||
),
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -248,45 +254,3 @@ impl SendWithoutResponse for Client {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn dummy_client() -> Client {
|
||||
Client::new(Config {
|
||||
initial_reconnection_backoff: Duration::from_millis(10_000),
|
||||
maximum_reconnection_backoff: Duration::from_millis(300_000),
|
||||
initial_connection_timeout: Duration::from_millis(1_500),
|
||||
maximum_connection_buffer_size: 128,
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn determining_backoff_works_regardless_of_attempt() {
|
||||
let client = dummy_client();
|
||||
assert!(client.determine_backoff(0).is_none());
|
||||
assert!(client.determine_backoff(1).is_some());
|
||||
assert!(client.determine_backoff(2).is_some());
|
||||
assert_eq!(
|
||||
client.determine_backoff(16).unwrap(),
|
||||
client.config.maximum_reconnection_backoff
|
||||
);
|
||||
assert_eq!(
|
||||
client.determine_backoff(32).unwrap(),
|
||||
client.config.maximum_reconnection_backoff
|
||||
);
|
||||
assert_eq!(
|
||||
client.determine_backoff(1024).unwrap(),
|
||||
client.config.maximum_reconnection_backoff
|
||||
);
|
||||
assert_eq!(
|
||||
client.determine_backoff(65536).unwrap(),
|
||||
client.config.maximum_reconnection_backoff
|
||||
);
|
||||
assert_eq!(
|
||||
client.determine_backoff(u32::MAX).unwrap(),
|
||||
client.config.maximum_reconnection_backoff
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,6 @@ use crate::{validator_api, ValidatorClientError};
|
||||
use coconut_interface::{BlindSignRequestBody, BlindedSignatureResponse, VerificationKeyResponse};
|
||||
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
|
||||
use url::Url;
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
use validator_api_requests::models::UptimeResponse;
|
||||
use validator_api_requests::models::{
|
||||
CoreNodeStatusResponse, MixnodeStatusResponse, RewardEstimationResponse,
|
||||
StakeSaturationResponse,
|
||||
@@ -585,12 +582,6 @@ impl<C> Client<C> {
|
||||
Ok(delegations)
|
||||
}
|
||||
|
||||
pub async fn get_mixnode_avg_uptimes(
|
||||
&self,
|
||||
) -> Result<Vec<UptimeResponse>, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_mixnode_avg_uptimes().await?)
|
||||
}
|
||||
|
||||
pub async fn blind_sign(
|
||||
&self,
|
||||
request_body: &BlindSignRequestBody,
|
||||
|
||||
@@ -30,26 +30,12 @@ use cosmwasm_std::Coin as CosmWasmCoin;
|
||||
use prost::Message;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::time::Duration;
|
||||
|
||||
#[async_trait]
|
||||
impl CosmWasmClient for HttpClient {
|
||||
fn broadcast_polling_rate(&self) -> Duration {
|
||||
Duration::from_secs(4)
|
||||
}
|
||||
|
||||
fn broadcast_timeout(&self) -> Duration {
|
||||
Duration::from_secs(60)
|
||||
}
|
||||
}
|
||||
impl CosmWasmClient for HttpClient {}
|
||||
|
||||
#[async_trait]
|
||||
pub trait CosmWasmClient: rpc::Client {
|
||||
// this should probably get redesigned, but I'm leaving those like that temporarily to fix
|
||||
// the underlying issue more quickly
|
||||
fn broadcast_polling_rate(&self) -> Duration;
|
||||
fn broadcast_timeout(&self) -> Duration;
|
||||
|
||||
// helper method to remove duplicate code involved in making abci requests with protobuf messages
|
||||
// TODO: perhaps it should have an additional argument to determine whether the response should
|
||||
// require proof?
|
||||
@@ -267,42 +253,6 @@ pub trait CosmWasmClient: rpc::Client {
|
||||
Ok(rpc::Client::broadcast_tx_commit(self, tx).await?)
|
||||
}
|
||||
|
||||
async fn broadcast_tx(&self, tx: Transaction) -> Result<TxResponse, NymdError> {
|
||||
let broadcasted = CosmWasmClient::broadcast_tx_sync(self, tx).await?;
|
||||
|
||||
if broadcasted.code.is_err() {
|
||||
let code_val = broadcasted.code.value();
|
||||
return Err(NymdError::BroadcastTxErrorDeliverTx {
|
||||
hash: broadcasted.hash,
|
||||
height: None,
|
||||
code: code_val,
|
||||
raw_log: broadcasted.log.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
let tx_hash = broadcasted.hash;
|
||||
|
||||
let start = tokio::time::Instant::now();
|
||||
loop {
|
||||
log::debug!(
|
||||
"Polling for result of including {} in a block...",
|
||||
broadcasted.hash
|
||||
);
|
||||
if tokio::time::Instant::now().duration_since(start) >= self.broadcast_timeout() {
|
||||
return Err(NymdError::BroadcastTimeout {
|
||||
hash: tx_hash,
|
||||
timeout: self.broadcast_timeout(),
|
||||
});
|
||||
}
|
||||
|
||||
if let Ok(poll_res) = self.get_tx(tx_hash).await {
|
||||
return Ok(poll_res);
|
||||
}
|
||||
|
||||
tokio::time::sleep(self.broadcast_polling_rate()).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_codes(&self) -> Result<Vec<Code>, NymdError> {
|
||||
let path = Some("/cosmwasm.wasm.v1.Query/Codes".parse().unwrap());
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ impl CheckResponse for broadcast::tx_commit::Response {
|
||||
if self.check_tx.code.is_err() {
|
||||
return Err(NymdError::BroadcastTxErrorCheckTx {
|
||||
hash: self.hash,
|
||||
height: Some(self.height),
|
||||
height: self.height,
|
||||
code: self.check_tx.code.value(),
|
||||
raw_log: self.check_tx.log.value().to_owned(),
|
||||
});
|
||||
@@ -28,7 +28,7 @@ impl CheckResponse for broadcast::tx_commit::Response {
|
||||
if self.deliver_tx.code.is_err() {
|
||||
return Err(NymdError::BroadcastTxErrorDeliverTx {
|
||||
hash: self.hash,
|
||||
height: Some(self.height),
|
||||
height: self.height,
|
||||
code: self.deliver_tx.code.value(),
|
||||
raw_log: self.deliver_tx.log.value().to_owned(),
|
||||
});
|
||||
@@ -38,21 +38,6 @@ impl CheckResponse for broadcast::tx_commit::Response {
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckResponse for crate::nymd::TxResponse {
|
||||
fn check_response(self) -> Result<Self, NymdError> {
|
||||
if self.tx_result.code.is_err() {
|
||||
return Err(NymdError::BroadcastTxErrorDeliverTx {
|
||||
hash: self.hash,
|
||||
height: Some(self.height),
|
||||
code: self.tx_result.code.value(),
|
||||
raw_log: self.tx_result.log.value().to_owned(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compress_wasm_code(code: &[u8]) -> Result<Vec<u8>, NymdError> {
|
||||
// using compression level 9, same as cosmjs, that optimises for size
|
||||
let mut encoder = GzEncoder::new(Vec::new(), Compression::best());
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::convert::TryInto;
|
||||
use std::time::Duration;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use cosmrs::bank::MsgSend;
|
||||
@@ -25,7 +24,7 @@ use crate::nymd::cosmwasm_client::types::*;
|
||||
use crate::nymd::error::NymdError;
|
||||
use crate::nymd::fee::{Fee, DEFAULT_SIMULATED_GAS_MULTIPLIER};
|
||||
use crate::nymd::wallet::DirectSecp256k1HdWallet;
|
||||
use crate::nymd::{CosmosCoin, GasPrice, TxResponse};
|
||||
use crate::nymd::{CosmosCoin, GasPrice};
|
||||
|
||||
// we need to have **a** valid secp256k1 signature for simulation purposes.
|
||||
// it doesn't matter what it is as long as it parses correctly
|
||||
@@ -36,9 +35,6 @@ const DUMMY_SECP256K1_SIGNATURE: &[u8] = &[
|
||||
91,
|
||||
];
|
||||
|
||||
const DEFAULT_BROADCAST_POLLING_RATE: Duration = Duration::from_secs(4);
|
||||
const DEFAULT_BROADCAST_TIMEOUT: Duration = Duration::from_secs(60);
|
||||
|
||||
#[async_trait]
|
||||
pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
fn signer(&self) -> &DirectSecp256k1HdWallet;
|
||||
@@ -115,12 +111,12 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
.map_err(|_| NymdError::SerializationError("MsgStoreCode".to_owned()))?;
|
||||
|
||||
let tx_res = self
|
||||
.sign_and_broadcast(sender_address, vec![upload_msg], fee, memo)
|
||||
.sign_and_broadcast_commit(sender_address, vec![upload_msg], fee, memo)
|
||||
.await?
|
||||
.check_response()?;
|
||||
|
||||
let logs = parse_raw_logs(tx_res.tx_result.log)?;
|
||||
let gas_info = GasInfo::new(tx_res.tx_result.gas_wanted, tx_res.tx_result.gas_used);
|
||||
let logs = parse_raw_logs(tx_res.deliver_tx.log)?;
|
||||
let gas_info = GasInfo::new(tx_res.deliver_tx.gas_wanted, tx_res.deliver_tx.gas_used);
|
||||
|
||||
// TODO: should those strings be extracted into some constants?
|
||||
// the reason I think unwrap here is fine is that if the transaction succeeded and those
|
||||
@@ -176,12 +172,12 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
.map_err(|_| NymdError::SerializationError("MsgInstantiateContract".to_owned()))?;
|
||||
|
||||
let tx_res = self
|
||||
.sign_and_broadcast(sender_address, vec![init_msg], fee, memo)
|
||||
.sign_and_broadcast_commit(sender_address, vec![init_msg], fee, memo)
|
||||
.await?
|
||||
.check_response()?;
|
||||
|
||||
let logs = parse_raw_logs(tx_res.tx_result.log)?;
|
||||
let gas_info = GasInfo::new(tx_res.tx_result.gas_wanted, tx_res.tx_result.gas_used);
|
||||
let logs = parse_raw_logs(tx_res.deliver_tx.log)?;
|
||||
let gas_info = GasInfo::new(tx_res.deliver_tx.gas_wanted, tx_res.deliver_tx.gas_used);
|
||||
|
||||
// TODO: should those strings be extracted into some constants?
|
||||
// the reason I think unwrap here is fine is that if the transaction succeeded and those
|
||||
@@ -218,14 +214,14 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
.map_err(|_| NymdError::SerializationError("MsgUpdateAdmin".to_owned()))?;
|
||||
|
||||
let tx_res = self
|
||||
.sign_and_broadcast(sender_address, vec![change_admin_msg], fee, memo)
|
||||
.sign_and_broadcast_commit(sender_address, vec![change_admin_msg], fee, memo)
|
||||
.await?
|
||||
.check_response()?;
|
||||
|
||||
let gas_info = GasInfo::new(tx_res.tx_result.gas_wanted, tx_res.tx_result.gas_used);
|
||||
let gas_info = GasInfo::new(tx_res.deliver_tx.gas_wanted, tx_res.deliver_tx.gas_used);
|
||||
|
||||
Ok(ChangeAdminResult {
|
||||
logs: parse_raw_logs(tx_res.tx_result.log)?,
|
||||
logs: parse_raw_logs(tx_res.deliver_tx.log)?,
|
||||
transaction_hash: tx_res.hash,
|
||||
gas_info,
|
||||
})
|
||||
@@ -246,14 +242,14 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
.map_err(|_| NymdError::SerializationError("MsgClearAdmin".to_owned()))?;
|
||||
|
||||
let tx_res = self
|
||||
.sign_and_broadcast(sender_address, vec![change_admin_msg], fee, memo)
|
||||
.sign_and_broadcast_commit(sender_address, vec![change_admin_msg], fee, memo)
|
||||
.await?
|
||||
.check_response()?;
|
||||
|
||||
let gas_info = GasInfo::new(tx_res.tx_result.gas_wanted, tx_res.tx_result.gas_used);
|
||||
let gas_info = GasInfo::new(tx_res.deliver_tx.gas_wanted, tx_res.deliver_tx.gas_used);
|
||||
|
||||
Ok(ChangeAdminResult {
|
||||
logs: parse_raw_logs(tx_res.tx_result.log)?,
|
||||
logs: parse_raw_logs(tx_res.deliver_tx.log)?,
|
||||
transaction_hash: tx_res.hash,
|
||||
gas_info,
|
||||
})
|
||||
@@ -281,14 +277,14 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
.map_err(|_| NymdError::SerializationError("MsgMigrateContract".to_owned()))?;
|
||||
|
||||
let tx_res = self
|
||||
.sign_and_broadcast(sender_address, vec![migrate_msg], fee, memo)
|
||||
.sign_and_broadcast_commit(sender_address, vec![migrate_msg], fee, memo)
|
||||
.await?
|
||||
.check_response()?;
|
||||
|
||||
let gas_info = GasInfo::new(tx_res.tx_result.gas_wanted, tx_res.tx_result.gas_used);
|
||||
let gas_info = GasInfo::new(tx_res.deliver_tx.gas_wanted, tx_res.deliver_tx.gas_used);
|
||||
|
||||
Ok(MigrateResult {
|
||||
logs: parse_raw_logs(tx_res.tx_result.log)?,
|
||||
logs: parse_raw_logs(tx_res.deliver_tx.log)?,
|
||||
transaction_hash: tx_res.hash,
|
||||
gas_info,
|
||||
})
|
||||
@@ -316,15 +312,14 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
.map_err(|_| NymdError::SerializationError("MsgExecuteContract".to_owned()))?;
|
||||
|
||||
let tx_res = self
|
||||
.sign_and_broadcast(sender_address, vec![execute_msg], fee, memo)
|
||||
.sign_and_broadcast_commit(sender_address, vec![execute_msg], fee, memo)
|
||||
.await?
|
||||
.check_response()?;
|
||||
|
||||
let gas_info = GasInfo::new(tx_res.tx_result.gas_wanted, tx_res.tx_result.gas_used);
|
||||
let gas_info = GasInfo::new(tx_res.deliver_tx.gas_wanted, tx_res.deliver_tx.gas_used);
|
||||
|
||||
Ok(ExecuteResult {
|
||||
logs: parse_raw_logs(tx_res.tx_result.log)?,
|
||||
data: tx_res.tx_result.data,
|
||||
logs: parse_raw_logs(tx_res.deliver_tx.log)?,
|
||||
transaction_hash: tx_res.hash,
|
||||
gas_info,
|
||||
})
|
||||
@@ -357,15 +352,14 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
let tx_res = self
|
||||
.sign_and_broadcast(sender_address, messages, fee, memo)
|
||||
.sign_and_broadcast_commit(sender_address, messages, fee, memo)
|
||||
.await?
|
||||
.check_response()?;
|
||||
|
||||
let gas_info = GasInfo::new(tx_res.tx_result.gas_wanted, tx_res.tx_result.gas_used);
|
||||
let gas_info = GasInfo::new(tx_res.deliver_tx.gas_wanted, tx_res.deliver_tx.gas_used);
|
||||
|
||||
Ok(ExecuteResult {
|
||||
logs: parse_raw_logs(tx_res.tx_result.log)?,
|
||||
data: tx_res.tx_result.data,
|
||||
logs: parse_raw_logs(tx_res.deliver_tx.log)?,
|
||||
transaction_hash: tx_res.hash,
|
||||
gas_info,
|
||||
})
|
||||
@@ -378,7 +372,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
amount: Vec<Coin>,
|
||||
fee: Fee,
|
||||
memo: impl Into<String> + Send + 'static,
|
||||
) -> Result<TxResponse, NymdError> {
|
||||
) -> Result<broadcast::tx_commit::Response, NymdError> {
|
||||
let send_msg = MsgSend {
|
||||
from_address: sender_address.clone(),
|
||||
to_address: recipient_address.clone(),
|
||||
@@ -387,7 +381,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
.to_any()
|
||||
.map_err(|_| NymdError::SerializationError("MsgSend".to_owned()))?;
|
||||
|
||||
self.sign_and_broadcast(sender_address, vec![send_msg], fee, memo)
|
||||
self.sign_and_broadcast_commit(sender_address, vec![send_msg], fee, memo)
|
||||
.await?
|
||||
.check_response()
|
||||
}
|
||||
@@ -398,7 +392,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
msgs: I,
|
||||
fee: Fee,
|
||||
memo: impl Into<String> + Send + 'static,
|
||||
) -> Result<TxResponse, NymdError>
|
||||
) -> Result<broadcast::tx_commit::Response, NymdError>
|
||||
where
|
||||
I: IntoIterator<Item = (AccountId, Vec<Coin>)> + Send,
|
||||
{
|
||||
@@ -415,7 +409,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
self.sign_and_broadcast(sender_address, messages, fee, memo)
|
||||
self.sign_and_broadcast_commit(sender_address, messages, fee, memo)
|
||||
.await?
|
||||
.check_response()
|
||||
}
|
||||
@@ -427,7 +421,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
amount: Coin,
|
||||
fee: Fee,
|
||||
memo: impl Into<String> + Send + 'static,
|
||||
) -> Result<TxResponse, NymdError> {
|
||||
) -> Result<broadcast::tx_commit::Response, NymdError> {
|
||||
let delegate_msg = MsgDelegate {
|
||||
delegator_address: delegator_address.to_owned(),
|
||||
validator_address: validator_address.to_owned(),
|
||||
@@ -436,7 +430,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
.to_any()
|
||||
.map_err(|_| NymdError::SerializationError("MsgDelegate".to_owned()))?;
|
||||
|
||||
self.sign_and_broadcast(delegator_address, vec![delegate_msg], fee, memo)
|
||||
self.sign_and_broadcast_commit(delegator_address, vec![delegate_msg], fee, memo)
|
||||
.await?
|
||||
.check_response()
|
||||
}
|
||||
@@ -448,7 +442,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
amount: Coin,
|
||||
fee: Fee,
|
||||
memo: impl Into<String> + Send + 'static,
|
||||
) -> Result<TxResponse, NymdError> {
|
||||
) -> Result<broadcast::tx_commit::Response, NymdError> {
|
||||
let undelegate_msg = MsgUndelegate {
|
||||
delegator_address: delegator_address.to_owned(),
|
||||
validator_address: validator_address.to_owned(),
|
||||
@@ -457,7 +451,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
.to_any()
|
||||
.map_err(|_| NymdError::SerializationError("MsgUndelegate".to_owned()))?;
|
||||
|
||||
self.sign_and_broadcast(delegator_address, vec![undelegate_msg], fee, memo)
|
||||
self.sign_and_broadcast_commit(delegator_address, vec![undelegate_msg], fee, memo)
|
||||
.await?
|
||||
.check_response()
|
||||
}
|
||||
@@ -468,7 +462,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
validator_address: &AccountId,
|
||||
fee: Fee,
|
||||
memo: impl Into<String> + Send + 'static,
|
||||
) -> Result<TxResponse, NymdError> {
|
||||
) -> Result<broadcast::tx_commit::Response, NymdError> {
|
||||
let withdraw_msg = MsgWithdrawDelegatorReward {
|
||||
delegator_address: delegator_address.to_owned(),
|
||||
validator_address: validator_address.to_owned(),
|
||||
@@ -476,7 +470,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
.to_any()
|
||||
.map_err(|_| NymdError::SerializationError("MsgWithdrawDelegatorReward".to_owned()))?;
|
||||
|
||||
self.sign_and_broadcast(delegator_address, vec![withdraw_msg], fee, memo)
|
||||
self.sign_and_broadcast_commit(delegator_address, vec![withdraw_msg], fee, memo)
|
||||
.await?
|
||||
.check_response()
|
||||
}
|
||||
@@ -579,27 +573,6 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
CosmWasmClient::broadcast_tx_commit(self, tx_bytes.into()).await
|
||||
}
|
||||
|
||||
/// Broadcast a transaction to the network and monitors its inclusion in a block.
|
||||
async fn sign_and_broadcast(
|
||||
&self,
|
||||
signer_address: &AccountId,
|
||||
messages: Vec<Any>,
|
||||
fee: Fee,
|
||||
memo: impl Into<String> + Send + 'static,
|
||||
) -> Result<TxResponse, NymdError> {
|
||||
let memo = memo.into();
|
||||
let fee = self
|
||||
.determine_transaction_fee(signer_address, &messages, fee, &memo)
|
||||
.await?;
|
||||
|
||||
let tx_raw = self.sign(signer_address, messages, fee, memo).await?;
|
||||
let tx_bytes = tx_raw
|
||||
.to_bytes()
|
||||
.map_err(|_| NymdError::SerializationError("Tx".to_owned()))?;
|
||||
|
||||
self.broadcast_tx(tx_bytes.into()).await
|
||||
}
|
||||
|
||||
fn sign_direct(
|
||||
&self,
|
||||
signer_address: &AccountId,
|
||||
@@ -665,9 +638,6 @@ pub struct Client {
|
||||
rpc_client: HttpClient,
|
||||
signer: DirectSecp256k1HdWallet,
|
||||
gas_price: GasPrice,
|
||||
|
||||
broadcast_polling_rate: Duration,
|
||||
broadcast_timeout: Duration,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
@@ -684,18 +654,8 @@ impl Client {
|
||||
rpc_client,
|
||||
signer,
|
||||
gas_price,
|
||||
broadcast_polling_rate: DEFAULT_BROADCAST_POLLING_RATE,
|
||||
broadcast_timeout: DEFAULT_BROADCAST_TIMEOUT,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_broadcast_polling_rate(&mut self, broadcast_polling_rate: Duration) {
|
||||
self.broadcast_polling_rate = broadcast_polling_rate
|
||||
}
|
||||
|
||||
pub fn set_broadcast_timeout(&mut self, broadcast_timeout: Duration) {
|
||||
self.broadcast_timeout = broadcast_timeout
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -709,15 +669,7 @@ impl rpc::Client for Client {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl CosmWasmClient for Client {
|
||||
fn broadcast_polling_rate(&self) -> Duration {
|
||||
self.broadcast_polling_rate
|
||||
}
|
||||
|
||||
fn broadcast_timeout(&self) -> Duration {
|
||||
self.broadcast_timeout
|
||||
}
|
||||
}
|
||||
impl CosmWasmClient for Client {}
|
||||
|
||||
#[async_trait]
|
||||
impl SigningCosmWasmClient for Client {
|
||||
|
||||
@@ -25,7 +25,6 @@ use cosmrs::proto::cosmwasm::wasm::v1::{
|
||||
CodeInfoResponse, ContractCodeHistoryEntry as ProtoContractCodeHistoryEntry,
|
||||
ContractCodeHistoryOperationType, ContractInfo as ProtoContractInfo,
|
||||
};
|
||||
use cosmrs::tendermint::abci::Data;
|
||||
use cosmrs::tendermint::{abci, chain};
|
||||
use cosmrs::tx::{AccountNumber, Gas, SequenceNumber};
|
||||
use cosmrs::{tx, AccountId, Any, Coin};
|
||||
@@ -673,8 +672,6 @@ pub struct MigrateResult {
|
||||
pub struct ExecuteResult {
|
||||
pub logs: Vec<Log>,
|
||||
|
||||
pub data: Data,
|
||||
|
||||
/// Transaction hash (might be used as transaction ID)
|
||||
pub transaction_hash: tx::Hash,
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ use crate::nymd::cosmwasm_client::types::ContractCodeId;
|
||||
use cosmrs::tendermint::{abci, block};
|
||||
use cosmrs::{bip32, tx, AccountId};
|
||||
use std::io;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error;
|
||||
|
||||
pub use cosmrs::rpc::error::{
|
||||
@@ -82,21 +81,21 @@ pub enum NymdError {
|
||||
MalformedLogString,
|
||||
|
||||
#[error(
|
||||
"Error when broadcasting tx {hash} at height {height:?}. Error occurred during CheckTx phase. Code: {code}; Raw log: {raw_log}"
|
||||
"Error when broadcasting tx {hash} at height {height}. Error occurred during CheckTx phase. Code: {code}; Raw log: {raw_log}"
|
||||
)]
|
||||
BroadcastTxErrorCheckTx {
|
||||
hash: tx::Hash,
|
||||
height: Option<block::Height>,
|
||||
height: block::Height,
|
||||
code: u32,
|
||||
raw_log: String,
|
||||
},
|
||||
|
||||
#[error(
|
||||
"Error when broadcasting tx {hash} at height {height:?}. Error occurred during DeliverTx phase. Code: {code}; Raw log: {raw_log}"
|
||||
"Error when broadcasting tx {hash} at height {height}. Error occurred during DeliverTx phase. Code: {code}; Raw log: {raw_log}"
|
||||
)]
|
||||
BroadcastTxErrorDeliverTx {
|
||||
hash: tx::Hash,
|
||||
height: Option<block::Height>,
|
||||
height: block::Height,
|
||||
code: u32,
|
||||
raw_log: String,
|
||||
},
|
||||
@@ -118,9 +117,6 @@ pub enum NymdError {
|
||||
|
||||
#[error("This account does not have BaseAccount information available to it")]
|
||||
NoBaseAccountInformationAvailable,
|
||||
|
||||
#[error("Transaction with ID {hash} has been submitted but not yet found on the chain. You might want to check for it later. There was a total wait of {} seconds", .timeout.as_secs())]
|
||||
BroadcastTimeout { hash: tx::Hash, timeout: Duration },
|
||||
}
|
||||
|
||||
impl NymdError {
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::nymd::cosmwasm_client::types::{
|
||||
};
|
||||
use crate::nymd::error::NymdError;
|
||||
use crate::nymd::wallet::DirectSecp256k1HdWallet;
|
||||
use cosmrs::rpc::endpoint::broadcast;
|
||||
use cosmrs::rpc::Error as TendermintRpcError;
|
||||
use cosmrs::rpc::HttpClientUrl;
|
||||
use cosmwasm_std::{Coin, Uint128};
|
||||
@@ -22,14 +23,12 @@ use mixnet_contract_common::{
|
||||
PagedRewardedSetResponse, QueryMsg, RewardedSetUpdateDetails,
|
||||
};
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
|
||||
pub use crate::nymd::cosmwasm_client::client::CosmWasmClient;
|
||||
pub use crate::nymd::cosmwasm_client::signing_client::SigningCosmWasmClient;
|
||||
pub use crate::nymd::fee::Fee;
|
||||
use crate::nymd::fee::DEFAULT_SIMULATED_GAS_MULTIPLIER;
|
||||
pub use cosmrs::bank::MsgSend;
|
||||
pub use cosmrs::rpc::endpoint::tx::Response as TxResponse;
|
||||
pub use cosmrs::rpc::endpoint::validators::Response as ValidatorResponse;
|
||||
pub use cosmrs::rpc::HttpClient as QueryNymdClient;
|
||||
@@ -44,6 +43,7 @@ pub use cosmrs::tx::{self, Gas};
|
||||
pub use cosmrs::Coin as CosmosCoin;
|
||||
pub use cosmrs::{AccountId, Decimal, Denom};
|
||||
pub use signing_client::Client as SigningNymdClient;
|
||||
use std::collections::HashMap;
|
||||
pub use traits::{VestingQueryClient, VestingSigningClient};
|
||||
|
||||
pub mod cosmwasm_client;
|
||||
@@ -640,7 +640,7 @@ impl<C> NymdClient<C> {
|
||||
recipient: &AccountId,
|
||||
amount: Vec<CosmosCoin>,
|
||||
memo: impl Into<String> + Send + 'static,
|
||||
) -> Result<TxResponse, NymdError>
|
||||
) -> Result<broadcast::tx_commit::Response, NymdError>
|
||||
where
|
||||
C: SigningCosmWasmClient + Sync,
|
||||
{
|
||||
@@ -655,7 +655,7 @@ impl<C> NymdClient<C> {
|
||||
&self,
|
||||
msgs: Vec<(AccountId, Vec<CosmosCoin>)>,
|
||||
memo: impl Into<String> + Send + 'static,
|
||||
) -> Result<TxResponse, NymdError>
|
||||
) -> Result<broadcast::tx_commit::Response, NymdError>
|
||||
where
|
||||
C: SigningCosmWasmClient + Sync,
|
||||
{
|
||||
|
||||
@@ -197,45 +197,38 @@ impl DirectSecp256k1HdWalletBuilder {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use network_defaults::all::Network::*;
|
||||
use network_defaults::DEFAULT_NETWORK;
|
||||
|
||||
#[test]
|
||||
fn generating_account_addresses() {
|
||||
let (addr1, addr2, addr3) = match DEFAULT_NETWORK.bech32_prefix() {
|
||||
"punk" => (
|
||||
"punk1jw6mp7d5xqc7w6xm79lha27glmd0vdt32a3fj2",
|
||||
"punk1h5hgn94nsq4kh99rjj794hr5h5q6yfm22mcqqn",
|
||||
"punk17n9flp6jflljg6fp05dsy07wcprf2uuujse962",
|
||||
),
|
||||
"nymt" => (
|
||||
"nymt1jw6mp7d5xqc7w6xm79lha27glmd0vdt339me94",
|
||||
"nymt1h5hgn94nsq4kh99rjj794hr5h5q6yfm23rjshv",
|
||||
"nymt17n9flp6jflljg6fp05dsy07wcprf2uuufgn4d4",
|
||||
),
|
||||
_ => panic!("Test needs to be updated with new bech32 prefix"),
|
||||
};
|
||||
// test vectors produced from our js wallet
|
||||
let mnemonics = vec![
|
||||
"crush minute paddle tobacco message debate cabin peace bar jacket execute twenty winner view sure mask popular couch penalty fragile demise fresh pizza stove",
|
||||
"acquire rebel spot skin gun such erupt pull swear must define ill chief turtle today flower chunk truth battle claw rigid detail gym feel",
|
||||
"step income throw wheat mobile ship wave drink pool sudden upset jaguar bar globe rifle spice frost bless glimpse size regular carry aspect ball"
|
||||
];
|
||||
let prefixes = vec![
|
||||
MAINNET.bech32_prefix(),
|
||||
SANDBOX.bech32_prefix(),
|
||||
QA.bech32_prefix(),
|
||||
let mnemonic_address = vec![
|
||||
("crush minute paddle tobacco message debate cabin peace bar jacket execute twenty winner view sure mask popular couch penalty fragile demise fresh pizza stove", addr1),
|
||||
("acquire rebel spot skin gun such erupt pull swear must define ill chief turtle today flower chunk truth battle claw rigid detail gym feel", addr2),
|
||||
("step income throw wheat mobile ship wave drink pool sudden upset jaguar bar globe rifle spice frost bless glimpse size regular carry aspect ball", addr3)
|
||||
];
|
||||
|
||||
for prefix in prefixes {
|
||||
let addrs = match prefix {
|
||||
"nymt" => vec![
|
||||
"nymt1jw6mp7d5xqc7w6xm79lha27glmd0vdt339me94",
|
||||
"nymt1h5hgn94nsq4kh99rjj794hr5h5q6yfm23rjshv",
|
||||
"nymt17n9flp6jflljg6fp05dsy07wcprf2uuufgn4d4",
|
||||
],
|
||||
"n" => vec![
|
||||
"n1jw6mp7d5xqc7w6xm79lha27glmd0vdt3l9artf",
|
||||
"n1h5hgn94nsq4kh99rjj794hr5h5q6yfm2lr52es",
|
||||
"n17n9flp6jflljg6fp05dsy07wcprf2uuu8g40rf",
|
||||
],
|
||||
_ => panic!("Test needs to be updated with new bech32 prefix"),
|
||||
};
|
||||
for (idx, mnemonic) in mnemonics.iter().enumerate() {
|
||||
let wallet =
|
||||
DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic.parse().unwrap())
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
wallet.try_derive_accounts().unwrap()[0].address,
|
||||
addrs[idx].parse().unwrap()
|
||||
)
|
||||
}
|
||||
for (mnemonic, address) in mnemonic_address.into_iter() {
|
||||
let prefix = DEFAULT_NETWORK.bech32_prefix();
|
||||
let wallet =
|
||||
DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic.parse().unwrap()).unwrap();
|
||||
assert_eq!(
|
||||
wallet.try_derive_accounts().unwrap()[0].address,
|
||||
address.parse().unwrap()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use std::collections::HashMap;
|
||||
use url::Url;
|
||||
use validator_api_requests::models::{
|
||||
CoreNodeStatusResponse, InclusionProbabilityResponse, MixnodeStatusResponse,
|
||||
RewardEstimationResponse, StakeSaturationResponse, UptimeResponse,
|
||||
RewardEstimationResponse, StakeSaturationResponse,
|
||||
};
|
||||
|
||||
pub mod error;
|
||||
@@ -253,36 +253,6 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_mixnode_avg_uptime(
|
||||
&self,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
) -> Result<UptimeResponse, ValidatorAPIError> {
|
||||
self.query_validator_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
routes::MIXNODE,
|
||||
identity,
|
||||
routes::AVG_UPTIME,
|
||||
],
|
||||
NO_PARAMS,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_mixnode_avg_uptimes(&self) -> Result<Vec<UptimeResponse>, ValidatorAPIError> {
|
||||
self.query_validator_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
routes::MIXNODES,
|
||||
routes::AVG_UPTIME,
|
||||
],
|
||||
NO_PARAMS,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn blind_sign(
|
||||
&self,
|
||||
request_body: &BlindSignRequestBody,
|
||||
|
||||
@@ -26,6 +26,5 @@ pub const SINCE_ARG: &str = "since";
|
||||
|
||||
pub const STATUS: &str = "status";
|
||||
pub const REWARD_ESTIMATION: &str = "reward-estimation";
|
||||
pub const AVG_UPTIME: &str = "avg_uptime";
|
||||
pub const STAKE_SATURATION: &str = "stake-saturation";
|
||||
pub const INCLUSION_CHANCE: &str = "inclusion-probability";
|
||||
|
||||
@@ -7,7 +7,6 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
cfg-if = "1.0.0"
|
||||
handlebars = "3.0.1"
|
||||
humantime-serde = "1.0"
|
||||
log = "0.4"
|
||||
|
||||
@@ -69,16 +69,14 @@ pub trait NymConfig: Default + Serialize + DeserializeOwned {
|
||||
let location = custom_location
|
||||
.unwrap_or_else(|| self.config_directory().join(Self::config_file_name()));
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(unix)] {
|
||||
fs::write(location.clone(), templated_config)?;
|
||||
let mut perms = fs::metadata(location.clone())?.permissions();
|
||||
perms.set_mode(0o600);
|
||||
fs::set_permissions(location, perms)?;
|
||||
} else {
|
||||
fs::write(location, templated_config)?;
|
||||
}
|
||||
}
|
||||
fs::write(location.clone(), templated_config)?;
|
||||
|
||||
#[cfg(unix)]
|
||||
let mut perms = fs::metadata(location.clone())?.permissions();
|
||||
#[cfg(unix)]
|
||||
perms.set_mode(0o600);
|
||||
#[cfg(unix)]
|
||||
fs::set_permissions(location, perms)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -13,11 +13,4 @@ pub enum MixnetContractError {
|
||||
},
|
||||
#[error("Error casting from U128")]
|
||||
CastError,
|
||||
#[error("{source}")]
|
||||
StdErr {
|
||||
#[from]
|
||||
source: cosmwasm_std::StdError,
|
||||
},
|
||||
#[error("Division by zero at {}", line!())]
|
||||
DivisionByZero,
|
||||
}
|
||||
|
||||
@@ -222,17 +222,11 @@ impl DelegatorRewardParams {
|
||||
}
|
||||
|
||||
pub fn determine_delegation_reward(&self, delegation_amount: Uint128) -> u128 {
|
||||
if self.sigma == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// change all values into their fixed representations
|
||||
let delegation_amount = U128::from_num(delegation_amount.u128());
|
||||
let circulating_supply = U128::from_num(self.reward_params.circulating_supply());
|
||||
|
||||
let scaled_delegation_amount = delegation_amount / circulating_supply;
|
||||
|
||||
// Div by zero checked above
|
||||
let delegator_reward =
|
||||
(ONE - self.profit_margin) * (scaled_delegation_amount / self.sigma) * self.node_profit;
|
||||
|
||||
@@ -256,14 +250,8 @@ impl DelegatorRewardParams {
|
||||
#[derive(Debug, Clone, JsonSchema, PartialEq, Serialize, Deserialize, Copy)]
|
||||
pub struct StoredNodeRewardResult {
|
||||
reward: Uint128,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "fixed_U128_as_string")]
|
||||
lambda: U128,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "fixed_U128_as_string")]
|
||||
sigma: U128,
|
||||
lambda: Uint128,
|
||||
sigma: Uint128,
|
||||
}
|
||||
|
||||
impl StoredNodeRewardResult {
|
||||
@@ -271,11 +259,11 @@ impl StoredNodeRewardResult {
|
||||
self.reward
|
||||
}
|
||||
|
||||
pub fn lambda(&self) -> U128 {
|
||||
pub fn lambda(&self) -> Uint128 {
|
||||
self.lambda
|
||||
}
|
||||
|
||||
pub fn sigma(&self) -> U128 {
|
||||
pub fn sigma(&self) -> Uint128 {
|
||||
self.sigma
|
||||
}
|
||||
}
|
||||
@@ -291,8 +279,18 @@ impl TryFrom<NodeRewardResult> for StoredNodeRewardResult {
|
||||
.checked_cast()
|
||||
.ok_or(MixnetContractError::CastError)?,
|
||||
),
|
||||
lambda: node_reward_result.lambda(),
|
||||
sigma: node_reward_result.sigma(),
|
||||
lambda: Uint128::new(
|
||||
node_reward_result
|
||||
.lambda()
|
||||
.checked_cast()
|
||||
.ok_or(MixnetContractError::CastError)?,
|
||||
),
|
||||
sigma: Uint128::new(
|
||||
node_reward_result
|
||||
.sigma()
|
||||
.checked_cast()
|
||||
.ok_or(MixnetContractError::CastError)?,
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -471,16 +469,12 @@ impl MixNodeBond {
|
||||
|
||||
pub fn operator_reward(&self, params: &RewardParams) -> u128 {
|
||||
let reward = self.reward(params);
|
||||
if reward.sigma == 0 {
|
||||
return 0;
|
||||
}
|
||||
let profit = if reward.reward < params.node.operator_cost() {
|
||||
U128::from_num(0u128)
|
||||
} else {
|
||||
reward.reward - params.node.operator_cost()
|
||||
};
|
||||
let operator_base_reward = reward.reward.min(params.node.operator_cost());
|
||||
// Div by zero checked above
|
||||
let operator_reward = (self.profit_margin()
|
||||
+ (ONE - self.profit_margin()) * reward.lambda / reward.sigma)
|
||||
* profit;
|
||||
|
||||
@@ -177,13 +177,6 @@ pub enum QueryMsg {
|
||||
owner_address: String,
|
||||
proxy_address: Option<String>,
|
||||
},
|
||||
GetCheckpointsForMixnode {
|
||||
mix_identity: IdentityKey,
|
||||
},
|
||||
GetMixnodeAtHeight {
|
||||
mix_identity: IdentityKey,
|
||||
height: u64,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
|
||||
@@ -25,11 +25,11 @@ impl NodeEpochRewards {
|
||||
self.epoch_id
|
||||
}
|
||||
|
||||
pub fn sigma(&self) -> U128 {
|
||||
pub fn sigma(&self) -> Uint128 {
|
||||
self.result.sigma()
|
||||
}
|
||||
|
||||
pub fn lambda(&self) -> U128 {
|
||||
pub fn lambda(&self) -> Uint128 {
|
||||
self.result.lambda()
|
||||
}
|
||||
|
||||
@@ -47,19 +47,20 @@ impl NodeEpochRewards {
|
||||
|
||||
pub fn node_profit(&self) -> U128 {
|
||||
let reward = U128::from_num(self.reward().u128());
|
||||
// if operating cost is higher then the reward node profit is 0
|
||||
reward.saturating_sub(self.operator_cost())
|
||||
if reward < self.operator_cost() {
|
||||
U128::from_num(0u128)
|
||||
} else {
|
||||
reward - self.operator_cost()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn operator_reward(&self, profit_margin: U128) -> Result<Uint128, MixnetContractError> {
|
||||
let reward = self.node_profit();
|
||||
let operator_base_reward = reward.min(self.operator_cost());
|
||||
let div_by_zero_check = if let Some(value) = self.lambda().checked_div(self.sigma()) {
|
||||
value
|
||||
} else {
|
||||
return Err(MixnetContractError::DivisionByZero);
|
||||
};
|
||||
let operator_reward = (profit_margin + (ONE - profit_margin) * div_by_zero_check) * reward;
|
||||
let operator_reward = (profit_margin
|
||||
+ (ONE - profit_margin) * U128::from_num(self.lambda().u128())
|
||||
/ U128::from_num(self.sigma().u128()))
|
||||
* reward;
|
||||
|
||||
let reward = (operator_reward + operator_base_reward).max(U128::from_num(0u128));
|
||||
|
||||
@@ -81,15 +82,9 @@ impl NodeEpochRewards {
|
||||
let circulating_supply = U128::from_num(epoch_reward_params.circulating_supply());
|
||||
|
||||
let scaled_delegation_amount = delegation_amount / circulating_supply;
|
||||
|
||||
let check_div_by_zero =
|
||||
if let Some(value) = scaled_delegation_amount.checked_div(self.sigma()) {
|
||||
value
|
||||
} else {
|
||||
return Err(MixnetContractError::DivisionByZero);
|
||||
};
|
||||
|
||||
let delegator_reward = (ONE - profit_margin) * check_div_by_zero * self.node_profit();
|
||||
let delegator_reward = (ONE - profit_margin) * scaled_delegation_amount
|
||||
/ U128::from_num(self.sigma().u128())
|
||||
* self.node_profit();
|
||||
|
||||
let reward = delegator_reward.max(U128::ZERO);
|
||||
if let Some(int_reward) = reward.checked_cast() {
|
||||
@@ -206,11 +201,6 @@ impl RewardParams {
|
||||
let denom = self.active_set_work_factor() * U128::from_num(self.rewarded_set_size())
|
||||
- (self.active_set_work_factor() - ONE) * U128::from_num(self.idle_nodes().u128());
|
||||
|
||||
if denom == 0 {
|
||||
return U128::ZERO;
|
||||
}
|
||||
|
||||
// Div by zero checked above
|
||||
if self.in_active_set() {
|
||||
// work_active = factor / (factor * self.network.k[month] - (factor - 1) * idle_nodes)
|
||||
self.active_set_work_factor() / denom * self.rewarded_set_size()
|
||||
|
||||
@@ -19,8 +19,6 @@ cipher = { version = "0.4.3", optional = true }
|
||||
x25519-dalek = { version = "1.1", optional = true }
|
||||
ed25519-dalek = { version = "1.0", optional = true }
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"], optional = true }
|
||||
serde_bytes = { version = "0.11.6", optional = true }
|
||||
serde_crate = { version = "1.0", optional = true, default_features = false, package = "serde" }
|
||||
subtle-encoding = { version = "0.5", features = ["bech32-preview"]}
|
||||
|
||||
# internal
|
||||
@@ -32,7 +30,6 @@ config = { path="../../common/config" }
|
||||
rand_chacha = "0.2"
|
||||
|
||||
[features]
|
||||
serde = ["serde_crate", "serde_bytes", "ed25519-dalek/serde", "x25519-dalek/serde"]
|
||||
asymmetric = ["x25519-dalek", "ed25519-dalek"]
|
||||
hashing = ["blake3", "digest", "hkdf", "hmac", "generic-array"]
|
||||
symmetric = ["aes", "ctr", "cipher", "generic-array"]
|
||||
|
||||
@@ -68,7 +68,6 @@ pub fn creating_dealing_for_3_parties(c: &mut Criterion) {
|
||||
threshold,
|
||||
epoch,
|
||||
&receivers,
|
||||
None,
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -90,7 +89,6 @@ pub fn verifying_dealing_made_for_3_parties_and_recovering_share(c: &mut Criteri
|
||||
threshold,
|
||||
epoch,
|
||||
&receivers,
|
||||
None,
|
||||
);
|
||||
|
||||
let first_key = dks.get_mut(0).unwrap();
|
||||
@@ -101,7 +99,7 @@ pub fn verifying_dealing_made_for_3_parties_and_recovering_share(c: &mut Criteri
|
||||
|b| {
|
||||
b.iter(|| {
|
||||
assert!(dealing
|
||||
.verify(¶ms, epoch, threshold, &receivers, None)
|
||||
.verify(¶ms, epoch, threshold, &receivers)
|
||||
.is_ok());
|
||||
black_box(decrypt_share(first_key, 0, &dealing.ciphertexts, epoch, None).unwrap());
|
||||
})
|
||||
@@ -130,7 +128,6 @@ pub fn creating_dealing_for_20_parties(c: &mut Criterion) {
|
||||
threshold,
|
||||
epoch,
|
||||
&receivers,
|
||||
None,
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -153,7 +150,6 @@ pub fn verifying_dealing_made_for_20_parties_and_recovering_share(c: &mut Criter
|
||||
threshold,
|
||||
epoch,
|
||||
&receivers,
|
||||
None,
|
||||
);
|
||||
|
||||
let first_key = dks.get_mut(0).unwrap();
|
||||
@@ -164,7 +160,7 @@ pub fn verifying_dealing_made_for_20_parties_and_recovering_share(c: &mut Criter
|
||||
|b| {
|
||||
b.iter(|| {
|
||||
assert!(dealing
|
||||
.verify(¶ms, epoch, threshold, &receivers, None)
|
||||
.verify(¶ms, epoch, threshold, &receivers)
|
||||
.is_ok());
|
||||
black_box(decrypt_share(first_key, 0, &dealing.ciphertexts, epoch, None).unwrap());
|
||||
})
|
||||
@@ -193,7 +189,6 @@ pub fn creating_dealing_for_100_parties(c: &mut Criterion) {
|
||||
threshold,
|
||||
epoch,
|
||||
&receivers,
|
||||
None,
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -216,7 +211,6 @@ pub fn verifying_dealing_made_for_100_parties_and_recovering_share(c: &mut Crite
|
||||
threshold,
|
||||
epoch,
|
||||
&receivers,
|
||||
None,
|
||||
);
|
||||
|
||||
let first_key = dks.get_mut(0).unwrap();
|
||||
@@ -227,7 +221,7 @@ pub fn verifying_dealing_made_for_100_parties_and_recovering_share(c: &mut Crite
|
||||
|b| {
|
||||
b.iter(|| {
|
||||
assert!(dealing
|
||||
.verify(¶ms, epoch, threshold, &receivers, None)
|
||||
.verify(¶ms, epoch, threshold, &receivers)
|
||||
.is_ok());
|
||||
black_box(decrypt_share(first_key, 0, &dealing.ciphertexts, epoch, None).unwrap());
|
||||
})
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
use pemstore::traits::{PemStorableKey, PemStorableKeyPair};
|
||||
#[cfg(feature = "rand")]
|
||||
use rand::{CryptoRng, RngCore};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
/// Size of a X25519 private key
|
||||
@@ -129,28 +127,6 @@ impl PublicKey {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl Serialize for PublicKey {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.0.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'d> Deserialize<'d> for PublicKey {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'d>,
|
||||
{
|
||||
Ok(PublicKey(x25519_dalek::PublicKey::deserialize(
|
||||
deserializer,
|
||||
)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl PemStorableKey for PublicKey {
|
||||
type Error = KeyRecoveryError;
|
||||
|
||||
@@ -167,6 +143,7 @@ impl PemStorableKey for PublicKey {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PrivateKey(x25519_dalek::StaticSecret);
|
||||
|
||||
impl Display for PrivateKey {
|
||||
@@ -210,28 +187,6 @@ impl PrivateKey {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl Serialize for PrivateKey {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.0.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'d> Deserialize<'d> for PrivateKey {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'d>,
|
||||
{
|
||||
Ok(PrivateKey(x25519_dalek::StaticSecret::deserialize(
|
||||
deserializer,
|
||||
)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl PemStorableKey for PrivateKey {
|
||||
type Error = KeyRecoveryError;
|
||||
|
||||
|
||||
@@ -10,13 +10,6 @@ use pemstore::traits::{PemStorableKey, PemStorableKeyPair};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::de::Error as SerdeError;
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Ed25519RecoveryError {
|
||||
MalformedBytes(SignatureError),
|
||||
@@ -47,7 +40,6 @@ impl fmt::Display for Ed25519RecoveryError {
|
||||
impl std::error::Error for Ed25519RecoveryError {}
|
||||
|
||||
/// Keypair for usage in ed25519 EdDSA.
|
||||
#[derive(Debug)]
|
||||
pub struct KeyPair {
|
||||
private_key: PrivateKey,
|
||||
public_key: PublicKey,
|
||||
@@ -143,28 +135,6 @@ impl PublicKey {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl Serialize for PublicKey {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.0.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'d> Deserialize<'d> for PublicKey {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'d>,
|
||||
{
|
||||
Ok(PublicKey(ed25519_dalek::PublicKey::deserialize(
|
||||
deserializer,
|
||||
)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl PemStorableKey for PublicKey {
|
||||
type Error = Ed25519RecoveryError;
|
||||
|
||||
@@ -230,28 +200,6 @@ impl PrivateKey {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl Serialize for PrivateKey {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.0.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'d> Deserialize<'d> for PrivateKey {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'d>,
|
||||
{
|
||||
Ok(PrivateKey(ed25519_dalek::SecretKey::deserialize(
|
||||
deserializer,
|
||||
)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl PemStorableKey for PrivateKey {
|
||||
type Error = Ed25519RecoveryError;
|
||||
|
||||
@@ -268,7 +216,7 @@ impl PemStorableKey for PrivateKey {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct Signature(ed25519_dalek::Signature);
|
||||
|
||||
impl Signature {
|
||||
@@ -289,24 +237,3 @@ impl Signature {
|
||||
Ok(Signature(ed25519_dalek::Signature::from_bytes(bytes)?))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl Serialize for Signature {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
SerdeBytes::new(&self.to_bytes()).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'d> Deserialize<'d> for Signature {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'d>,
|
||||
{
|
||||
let bytes = <SerdeByteBuf>::deserialize(deserializer)?;
|
||||
Signature::from_bytes(bytes.as_ref()).map_err(SerdeError::custom)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,10 +69,9 @@ mod tests {
|
||||
#[test]
|
||||
fn wrong_prefix_fails() {
|
||||
assert_eq!(
|
||||
Err(Bech32Error::WrongPrefix(format!(
|
||||
"your bech32 address prefix should be {}, not punk",
|
||||
DEFAULT_NETWORK.bech32_prefix()
|
||||
))),
|
||||
Err(Bech32Error::WrongPrefix(
|
||||
"your bech32 address prefix should be nymt, not punk".to_string()
|
||||
)),
|
||||
validate_bech32_prefix("punk1h3w4nj7kny5dfyjw2le4vm74z03v9vd4dstpu0")
|
||||
)
|
||||
}
|
||||
@@ -81,9 +80,7 @@ mod tests {
|
||||
fn correct_prefix_works() {
|
||||
assert_eq!(
|
||||
Ok(()),
|
||||
validate_bech32_prefix(
|
||||
"n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g"
|
||||
)
|
||||
validate_bech32_prefix("nymt1z9egw0knv47nmur0p8vk4rcx59h9gg4zuxrrr9")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,5 +29,5 @@ pub use blake3;
|
||||
#[cfg(feature = "symmetric")]
|
||||
pub use ctr;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
extern crate serde_crate as serde;
|
||||
// TODO: this function uses all three modules: asymmetric crypto, symmetric crypto and derives key...,
|
||||
// so I don't know where to put it...
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
fn main() {
|
||||
match option_env!("NETWORK") {
|
||||
None | Some("mainnet") => println!("cargo:rustc-cfg=network=\"mainnet\"",),
|
||||
Some("sandbox") => println!("cargo:rustc-cfg=network=\"sandbox\"",),
|
||||
Some("mainnet") => println!("cargo:rustc-cfg=network=\"mainnet\"",),
|
||||
None | Some("sandbox") => println!("cargo:rustc-cfg=network=\"sandbox\"",),
|
||||
Some("qa") => println!("cargo:rustc-cfg=network=\"qa\""),
|
||||
_ => panic!("No such network"),
|
||||
}
|
||||
|
||||
@@ -56,10 +56,6 @@ impl Network {
|
||||
self.details().rewarding_validator_address
|
||||
}
|
||||
|
||||
pub fn stats_provider_network_address(&self) -> &str {
|
||||
self.details().stats_provider_network_address
|
||||
}
|
||||
|
||||
pub fn validators(&self) -> impl Iterator<Item = &ValidatorDetails> {
|
||||
self.details().validators.iter()
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ cfg_if::cfg_if! {
|
||||
if #[cfg(network = "mainnet")] {
|
||||
pub const DEFAULT_NETWORK: all::Network = all::Network::MAINNET;
|
||||
pub const DENOM: &str = mainnet::DENOM;
|
||||
pub const STAKE_DENOM: &str = mainnet::STAKE_DENOM;
|
||||
|
||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_CONTRACT_ADDRESS;
|
||||
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_ERC20_CONTRACT_ADDRESS;
|
||||
@@ -26,7 +25,6 @@ cfg_if::cfg_if! {
|
||||
} else if #[cfg(network = "qa")] {
|
||||
pub const DEFAULT_NETWORK: all::Network = all::Network::QA;
|
||||
pub const DENOM: &str = qa::DENOM;
|
||||
pub const STAKE_DENOM: &str = qa::STAKE_DENOM;
|
||||
|
||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = qa::_ETH_CONTRACT_ADDRESS;
|
||||
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = qa::_ETH_ERC20_CONTRACT_ADDRESS;
|
||||
@@ -34,7 +32,6 @@ cfg_if::cfg_if! {
|
||||
} else if #[cfg(network = "sandbox")] {
|
||||
pub const DEFAULT_NETWORK: all::Network = all::Network::SANDBOX;
|
||||
pub const DENOM: &str = sandbox::DENOM;
|
||||
pub const STAKE_DENOM: &str = sandbox::STAKE_DENOM;
|
||||
|
||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = sandbox::_ETH_CONTRACT_ADDRESS;
|
||||
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = sandbox::_ETH_ERC20_CONTRACT_ADDRESS;
|
||||
@@ -52,7 +49,6 @@ pub struct DefaultNetworkDetails<'a> {
|
||||
vesting_contract_address: &'a str,
|
||||
bandwidth_claim_contract_address: &'a str,
|
||||
rewarding_validator_address: &'a str,
|
||||
stats_provider_network_address: &'a str,
|
||||
validators: Vec<ValidatorDetails>,
|
||||
}
|
||||
|
||||
@@ -64,7 +60,6 @@ static MAINNET_DEFAULTS: Lazy<DefaultNetworkDetails<'static>> =
|
||||
vesting_contract_address: mainnet::VESTING_CONTRACT_ADDRESS,
|
||||
bandwidth_claim_contract_address: mainnet::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
||||
rewarding_validator_address: mainnet::REWARDING_VALIDATOR_ADDRESS,
|
||||
stats_provider_network_address: mainnet::STATS_PROVIDER_CLIENT_ADDRESS,
|
||||
validators: mainnet::validators(),
|
||||
});
|
||||
|
||||
@@ -76,7 +71,6 @@ static SANDBOX_DEFAULTS: Lazy<DefaultNetworkDetails<'static>> =
|
||||
vesting_contract_address: sandbox::VESTING_CONTRACT_ADDRESS,
|
||||
bandwidth_claim_contract_address: sandbox::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
||||
rewarding_validator_address: sandbox::REWARDING_VALIDATOR_ADDRESS,
|
||||
stats_provider_network_address: sandbox::STATS_PROVIDER_CLIENT_ADDRESS,
|
||||
validators: sandbox::validators(),
|
||||
});
|
||||
|
||||
@@ -87,7 +81,6 @@ static QA_DEFAULTS: Lazy<DefaultNetworkDetails<'static>> = Lazy::new(|| DefaultN
|
||||
vesting_contract_address: qa::VESTING_CONTRACT_ADDRESS,
|
||||
bandwidth_claim_contract_address: qa::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
||||
rewarding_validator_address: qa::REWARDING_VALIDATOR_ADDRESS,
|
||||
stats_provider_network_address: qa::STATS_PROVIDER_CLIENT_ADDRESS,
|
||||
validators: qa::validators(),
|
||||
});
|
||||
|
||||
@@ -108,13 +101,6 @@ impl ValidatorDetails {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_name(nymd_url: &str, api_url: Option<&str>) -> Self {
|
||||
ValidatorDetails {
|
||||
nymd_url: nymd_url.to_string(),
|
||||
api_url: api_url.map(ToString::to_string),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nymd_url(&self) -> Url {
|
||||
self.nymd_url
|
||||
.parse()
|
||||
|
||||
@@ -5,7 +5,6 @@ use crate::ValidatorDetails;
|
||||
|
||||
pub(crate) const BECH32_PREFIX: &str = "n";
|
||||
pub const DENOM: &str = "unym";
|
||||
pub const STAKE_DENOM: &str = "unyx";
|
||||
|
||||
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str =
|
||||
"n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g";
|
||||
@@ -19,11 +18,9 @@ pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
|
||||
hex_literal::hex!("0000000000000000000000000000000000000000");
|
||||
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy";
|
||||
|
||||
pub(crate) const STATS_PROVIDER_CLIENT_ADDRESS: &str = "3V3me68qkEYNNShSQ5yLkrzC8rUJmcmtrTFbLKPqytEZ.7dGmnRAheEozNeGAsp9LXM8oPgS5YgJraNmYguj2t7Bn@BNjYZPxzcJwczXHHgBxCAyVJKxN6LPteDRrKapxWmexv";
|
||||
|
||||
pub(crate) fn validators() -> Vec<ValidatorDetails> {
|
||||
vec![ValidatorDetails::new(
|
||||
"https://rpc.nyx.nodes.guru/",
|
||||
Some("https://validator.nymtech.net/api/"),
|
||||
Some("https://validator.nymtech.net/api"),
|
||||
)]
|
||||
}
|
||||
|
||||
@@ -3,27 +3,22 @@
|
||||
|
||||
use crate::ValidatorDetails;
|
||||
|
||||
pub(crate) const BECH32_PREFIX: &str = "n";
|
||||
pub const DENOM: &str = "unym";
|
||||
pub const STAKE_DENOM: &str = "unyx";
|
||||
pub(crate) const BECH32_PREFIX: &str = "nymt";
|
||||
pub const DENOM: &str = "unymt";
|
||||
|
||||
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str =
|
||||
"n1suhgf5svhu4usrurvxzlgn54ksxmn8gljarjtxqnapv8kjnp4nrsd3qaep";
|
||||
pub(crate) const VESTING_CONTRACT_ADDRESS: &str =
|
||||
"n1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3sjkxkav";
|
||||
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "nymt17x6pt4msccvawgxjeg5nmnygttu56tftg5l6j3";
|
||||
pub(crate) const VESTING_CONTRACT_ADDRESS: &str = "nymt1t4dmskxea0avvrj8xtmu66hv7dkyg9s8059t3c";
|
||||
pub(crate) const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str =
|
||||
"n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
|
||||
"nymt17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9f8xzkv";
|
||||
pub(crate) const _ETH_CONTRACT_ADDRESS: [u8; 20] =
|
||||
hex_literal::hex!("0000000000000000000000000000000000000000");
|
||||
pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
|
||||
hex_literal::hex!("0000000000000000000000000000000000000000");
|
||||
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n1tfzd4qz3a45u8p4mr5zmzv66457uwjgcl05jdq";
|
||||
|
||||
pub(crate) const STATS_PROVIDER_CLIENT_ADDRESS: &str = "BLFPkyQ68xtR3TmrUWJZUKJF4SVwJR23wzQEmLHi2QcZ.5zms2X4ANsgY1VB4iC9kTqvbsHWmWUNSuvTtYr4Cp5qT@ExyJVqTSrgHTwzXm2r9RawfF5qYpvZjSVN2dLTs6bnWH";
|
||||
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "nymt1dn52nx8wv9wkqmrvj6tcmdzh4es6jt8tr7f6j9";
|
||||
|
||||
pub(crate) fn validators() -> Vec<ValidatorDetails> {
|
||||
vec![ValidatorDetails::new(
|
||||
"https://qa-validator.nymtech.net",
|
||||
Some("https://qa-validator-api.nymtech.net/api"),
|
||||
Some("https://qa-validator.nymtech.net/api"),
|
||||
)]
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ use crate::ValidatorDetails;
|
||||
|
||||
pub(crate) const BECH32_PREFIX: &str = "nymt";
|
||||
pub const DENOM: &str = "unymt";
|
||||
pub const STAKE_DENOM: &str = "unyxt";
|
||||
|
||||
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "nymt1ghd753shjuwexxywmgs4xz7x2q732vcnstz02j";
|
||||
pub(crate) const VESTING_CONTRACT_ADDRESS: &str = "nymt14ejqjyq8um4p3xfqj74yld5waqljf88fn549lh";
|
||||
@@ -17,8 +16,6 @@ pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
|
||||
hex_literal::hex!("E8883BAeF3869e14E4823F46662e81D4F7d2A81F");
|
||||
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "nymt1jh0s6qu6tuw9ut438836mmn7f3f2wencrnmdj4";
|
||||
|
||||
pub(crate) const STATS_PROVIDER_CLIENT_ADDRESS: &str = "HqYWvCcB4sswYiyMj5Q8H5oc71kLf96vfrLK3npM7stH.CoeC5dcqurgdxr5zcgU77nZBSBCc8ntCiwUivQ9TX3KT@E3mvZTHQCdBvhfr178Swx9g4QG3kkRUun7YnToLMcMbM";
|
||||
|
||||
pub(crate) fn validators() -> Vec<ValidatorDetails> {
|
||||
vec![ValidatorDetails::new(
|
||||
"https://sandbox-validator.nymtech.net",
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
pub mod msg;
|
||||
pub mod request;
|
||||
pub mod response;
|
||||
|
||||
pub use msg::*;
|
||||
pub use request::*;
|
||||
pub use response::*;
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::request::{Request, RequestError};
|
||||
use crate::response::{Response, ResponseError};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MessageError {
|
||||
Request(RequestError),
|
||||
Response(ResponseError),
|
||||
NoData,
|
||||
UnknownMessageType,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for MessageError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
MessageError::Request(r) => write!(f, "{}", r),
|
||||
MessageError::Response(r) => write!(f, "{:?}", r),
|
||||
MessageError::NoData => write!(f, "no data provided"),
|
||||
MessageError::UnknownMessageType => write!(f, "unknown message type received"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Message {
|
||||
Request(Request),
|
||||
Response(Response),
|
||||
}
|
||||
|
||||
impl Message {
|
||||
const REQUEST_FLAG: u8 = 0;
|
||||
const RESPONSE_FLAG: u8 = 1;
|
||||
|
||||
pub fn try_from_bytes(b: &[u8]) -> Result<Message, MessageError> {
|
||||
if b.is_empty() {
|
||||
return Err(MessageError::NoData);
|
||||
}
|
||||
|
||||
if b[0] == Self::REQUEST_FLAG {
|
||||
Request::try_from_bytes(&b[1..])
|
||||
.map(Message::Request)
|
||||
.map_err(MessageError::Request)
|
||||
} else if b[0] == Self::RESPONSE_FLAG {
|
||||
Response::try_from_bytes(&b[1..])
|
||||
.map(Message::Response)
|
||||
.map_err(MessageError::Response)
|
||||
} else {
|
||||
Err(MessageError::UnknownMessageType)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_bytes(self) -> Vec<u8> {
|
||||
match self {
|
||||
Self::Request(r) => std::iter::once(Self::REQUEST_FLAG)
|
||||
.chain(r.into_bytes().iter().cloned())
|
||||
.collect(),
|
||||
Self::Response(r) => std::iter::once(Self::RESPONSE_FLAG)
|
||||
.chain(r.into_bytes().iter().cloned())
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+3
-4
@@ -41,7 +41,7 @@ checksum = "f771a5d1f5503f7f4279a30f3643d3421ba149848b89ecaaec0ea2acf04a5ac4"
|
||||
|
||||
[[package]]
|
||||
name = "bandwidth-claim"
|
||||
version = "1.0.0"
|
||||
version = "1.0.0-rc.2"
|
||||
dependencies = [
|
||||
"bandwidth-claim-contract",
|
||||
"config",
|
||||
@@ -227,7 +227,6 @@ dependencies = [
|
||||
name = "config"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"handlebars",
|
||||
"humantime-serde",
|
||||
"log",
|
||||
@@ -981,9 +980,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.16"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
|
||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "bandwidth-claim"
|
||||
version = "1.0.0"
|
||||
version = "1.0.0-rc.2"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// approximately 1 epoch (assuming 5s per block)
|
||||
pub const MINIMUM_BLOCK_AGE_FOR_REWARDING: u64 = 720;
|
||||
// approximately 1 week (assuming 5s per block)
|
||||
// i.e. approximately quarter of the interval (there are 3600 * 60 * 7 = 604800 seconds in a week, i.e. ~604800 / 5 = 120960 blocks)
|
||||
pub const MINIMUM_BLOCK_AGE_FOR_REWARDING: u64 = 120960;
|
||||
|
||||
pub const INTERVAL_REWARD_PERCENT: u8 = 2; // Used to calculate interval reward pool
|
||||
pub const SYBIL_RESISTANCE_PERCENT: u8 = 30;
|
||||
|
||||
@@ -24,17 +24,14 @@ use crate::mixnet_contract_settings::queries::{
|
||||
use crate::mixnet_contract_settings::storage as mixnet_params_storage;
|
||||
use crate::mixnet_contract_settings::transactions::try_update_rewarding_validator_address;
|
||||
use crate::mixnodes::bonding_queries as mixnode_queries;
|
||||
use crate::mixnodes::bonding_queries::{
|
||||
query_checkpoints_for_mixnode, query_mixnode_at_height, query_mixnodes_paged,
|
||||
};
|
||||
use crate::mixnodes::bonding_queries::query_mixnodes_paged;
|
||||
use crate::mixnodes::layer_queries::query_layer_distribution;
|
||||
use crate::rewards::queries::{
|
||||
query_circulating_supply, query_reward_pool, query_rewarding_status,
|
||||
};
|
||||
use crate::rewards::storage as rewards_storage;
|
||||
use cosmwasm_std::{
|
||||
entry_point, to_binary, Addr, Api, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response,
|
||||
Uint128,
|
||||
entry_point, to_binary, Addr, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response, Uint128,
|
||||
};
|
||||
use mixnet_contract_common::mixnode::DelegationEvent;
|
||||
use mixnet_contract_common::{
|
||||
@@ -57,10 +54,6 @@ pub const INITIAL_ACTIVE_SET_WORK_FACTOR: u8 = 10;
|
||||
pub const DEFAULT_FIRST_INTERVAL_START: OffsetDateTime =
|
||||
time::macros::datetime!(2022-01-01 12:00 UTC);
|
||||
|
||||
pub fn debug_with_visibility<S: Into<String>>(api: &dyn Api, msg: S) {
|
||||
api.debug(&*format!("\n\n\n=========================================\n{}\n=========================================\n\n\n", msg.into()));
|
||||
}
|
||||
|
||||
fn default_initial_state(owner: Addr, rewarding_validator_address: Addr) -> ContractState {
|
||||
ContractState {
|
||||
owner,
|
||||
@@ -394,19 +387,13 @@ pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result<QueryResponse, C
|
||||
QueryMsg::DebugGetAllDelegationValues {} => to_binary(
|
||||
&crate::delegations::queries::debug_query_all_delegation_values(deps.storage)?,
|
||||
),
|
||||
QueryMsg::GetCheckpointsForMixnode { mix_identity } => {
|
||||
to_binary(&query_checkpoints_for_mixnode(deps, mix_identity)?)
|
||||
}
|
||||
QueryMsg::GetMixnodeAtHeight {
|
||||
mix_identity,
|
||||
height,
|
||||
} => to_binary(&query_mixnode_at_height(deps, mix_identity, height)?),
|
||||
};
|
||||
|
||||
Ok(query_res?)
|
||||
}
|
||||
|
||||
fn deal_with_zero_delegations(deps: DepsMut<'_>) -> Result<(), ContractError> {
|
||||
#[entry_point]
|
||||
pub fn migrate(deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||
// if there exists any delegation of 0 value, remove it
|
||||
let zero_delegations = delegations()
|
||||
.range(deps.storage, None, None, cosmwasm_std::Order::Ascending)
|
||||
@@ -435,13 +422,6 @@ fn deal_with_zero_delegations(deps: DepsMut<'_>) -> Result<(), ContractError> {
|
||||
.remove(deps.storage, delegation_event);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[entry_point]
|
||||
pub fn migrate(deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||
deal_with_zero_delegations(deps)?;
|
||||
|
||||
Ok(Default::default())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
use super::storage::{self, PENDING_DELEGATION_EVENTS};
|
||||
// use crate::contract::debug_with_visibility;
|
||||
// use crate::contract::debug_with_visibility;
|
||||
use crate::error::ContractError;
|
||||
use crate::mixnet_contract_settings::storage as mixnet_params_storage;
|
||||
use crate::mixnodes::storage as mixnodes_storage;
|
||||
@@ -30,13 +28,12 @@ pub fn try_reconcile_all_delegation_events(
|
||||
return Err(ContractError::Unauthorized);
|
||||
}
|
||||
|
||||
_try_reconcile_all_delegation_events(deps.storage, deps.api)
|
||||
_try_reconcile_all_delegation_events(deps.storage)
|
||||
}
|
||||
|
||||
// TODO: Error handling?
|
||||
pub(crate) fn _try_reconcile_all_delegation_events(
|
||||
storage: &mut dyn Storage,
|
||||
api: &dyn Api,
|
||||
) -> Result<Response, ContractError> {
|
||||
let pending_delegation_events = PENDING_DELEGATION_EVENTS
|
||||
.range(storage, None, None, Order::Ascending)
|
||||
@@ -45,8 +42,6 @@ pub(crate) fn _try_reconcile_all_delegation_events(
|
||||
|
||||
let mut response = Response::new();
|
||||
|
||||
// debug_with_visibility(api, "Reconciling delegation events");
|
||||
|
||||
for (key, delegation_event) in pending_delegation_events {
|
||||
match delegation_event {
|
||||
DelegationEvent::Delegate(delegation) => {
|
||||
@@ -58,8 +53,7 @@ pub(crate) fn _try_reconcile_all_delegation_events(
|
||||
response = response.add_event(event);
|
||||
}
|
||||
DelegationEvent::Undelegate(pending_undelegate) => {
|
||||
let undelegate_response =
|
||||
try_reconcile_undelegation(storage, api, &pending_undelegate)?;
|
||||
let undelegate_response = try_reconcile_undelegation(storage, &pending_undelegate)?;
|
||||
response = response.add_event(undelegate_response.event);
|
||||
if let Some(msg) = undelegate_response.bank_msg {
|
||||
response = response.add_message(msg);
|
||||
@@ -107,7 +101,8 @@ pub(crate) fn try_delegate_to_mixnode(
|
||||
let amount = validate_delegation_stake(info.funds)?;
|
||||
|
||||
_try_delegate_to_mixnode(
|
||||
deps,
|
||||
deps.storage,
|
||||
deps.api,
|
||||
env.block.height,
|
||||
&mix_identity,
|
||||
info.sender.as_str(),
|
||||
@@ -127,7 +122,8 @@ pub(crate) fn try_delegate_to_mixnode_on_behalf(
|
||||
let amount = validate_delegation_stake(info.funds)?;
|
||||
|
||||
_try_delegate_to_mixnode(
|
||||
deps,
|
||||
deps.storage,
|
||||
deps.api,
|
||||
env.block.height,
|
||||
&mix_identity,
|
||||
&delegate,
|
||||
@@ -177,18 +173,19 @@ pub(crate) fn try_reconcile_delegation(
|
||||
}
|
||||
|
||||
pub(crate) fn _try_delegate_to_mixnode(
|
||||
deps: DepsMut<'_>,
|
||||
storage: &mut dyn Storage,
|
||||
api: &dyn Api,
|
||||
block_height: u64,
|
||||
mix_identity: &str,
|
||||
delegate: &str,
|
||||
amount: Coin,
|
||||
proxy: Option<Addr>,
|
||||
) -> Result<Response, ContractError> {
|
||||
let delegate = deps.api.addr_validate(delegate)?;
|
||||
let delegate = api.addr_validate(delegate)?;
|
||||
|
||||
// check if the target node actually exists
|
||||
if mixnodes_storage::mixnodes()
|
||||
.may_load(deps.storage, mix_identity)?
|
||||
.may_load(storage, mix_identity)?
|
||||
.is_none()
|
||||
{
|
||||
return Err(ContractError::MixNodeBondNotFound {
|
||||
@@ -205,7 +202,7 @@ pub(crate) fn _try_delegate_to_mixnode(
|
||||
);
|
||||
|
||||
if storage::PENDING_DELEGATION_EVENTS
|
||||
.may_load(deps.storage, delegation.event_storage_key())?
|
||||
.may_load(storage, delegation.event_storage_key())?
|
||||
.is_some()
|
||||
{
|
||||
return Err(ContractError::DelegationEventAlreadyPending {
|
||||
@@ -216,7 +213,7 @@ pub(crate) fn _try_delegate_to_mixnode(
|
||||
}
|
||||
|
||||
storage::PENDING_DELEGATION_EVENTS.save(
|
||||
deps.storage,
|
||||
storage,
|
||||
delegation.event_storage_key(),
|
||||
&DelegationEvent::Delegate(delegation),
|
||||
)?;
|
||||
@@ -256,13 +253,10 @@ pub struct ReconcileUndelegateResponse {
|
||||
|
||||
pub(crate) fn try_reconcile_undelegation(
|
||||
storage: &mut dyn Storage,
|
||||
api: &dyn Api,
|
||||
pending_undelegate: &PendingUndelegate,
|
||||
) -> Result<ReconcileUndelegateResponse, ContractError> {
|
||||
let delegation_map = storage::delegations();
|
||||
|
||||
// debug_with_visibility(api, "Reconciling undelegations");
|
||||
|
||||
let any_delegations = delegation_map
|
||||
.prefix(pending_undelegate.storage_key())
|
||||
.keys(storage, None, None, cosmwasm_std::Order::Ascending)
|
||||
@@ -286,13 +280,10 @@ pub(crate) fn try_reconcile_undelegation(
|
||||
|
||||
let reward = crate::rewards::transactions::calculate_delegator_reward(
|
||||
storage,
|
||||
api,
|
||||
pending_undelegate.proxy_storage_key(),
|
||||
&pending_undelegate.mix_identity(),
|
||||
)?;
|
||||
|
||||
// debug_with_visibility(api, format!("Delegator reward: {}", reward));
|
||||
|
||||
// Might want to introduce paging here
|
||||
let delegation_heights = delegation_map
|
||||
.prefix(pending_undelegate.storage_key())
|
||||
@@ -316,23 +307,12 @@ pub(crate) fn try_reconcile_undelegation(
|
||||
|
||||
let mut total_delegation = Uint128::zero();
|
||||
|
||||
// debug_with_visibility(api, "Reducing accumulated rewards");
|
||||
|
||||
if crate::mixnodes::storage::mixnodes()
|
||||
.may_load(storage, &pending_undelegate.mix_identity())?
|
||||
.is_none()
|
||||
{
|
||||
if let Some(mut bond) = crate::mixnodes::storage::mixnodes()
|
||||
.may_load(storage, &pending_undelegate.mix_identity())?
|
||||
{
|
||||
let remaining = bond.accumulated_rewards().saturating_sub(reward);
|
||||
// debug_with_visibility(api, format!("Remaining accumulated rewards: {}", remaining));
|
||||
bond.accumulated_rewards = Some(remaining);
|
||||
|
||||
crate::mixnodes::storage::mixnodes().save(
|
||||
storage,
|
||||
&pending_undelegate.mix_identity(),
|
||||
&bond,
|
||||
pending_undelegate.block_height(),
|
||||
)?;
|
||||
}
|
||||
// Since the mixnode is no longer bonded the reward did not compound and we need to manually add it to the total
|
||||
total_delegation = reward;
|
||||
}
|
||||
|
||||
for h in delegation_heights {
|
||||
@@ -347,40 +327,6 @@ pub(crate) fn try_reconcile_undelegation(
|
||||
)?;
|
||||
}
|
||||
|
||||
mixnodes_storage::TOTAL_DELEGATION.update::<_, ContractError>(
|
||||
storage,
|
||||
&pending_undelegate.mix_identity(),
|
||||
|total_node_delegation| {
|
||||
// debug_with_visibility(api, "Setting total delegation");
|
||||
let remaining = match total_node_delegation.unwrap().checked_sub(total_delegation) {
|
||||
Ok(remaining) => remaining,
|
||||
Err(_) => {
|
||||
// debug_with_visibility(
|
||||
// api,
|
||||
// format!(
|
||||
// "Overflowed delegation subsctraction, {} - {}",
|
||||
// total_node_delegation.unwrap(),
|
||||
// total_delegation
|
||||
// ),
|
||||
// );
|
||||
return Err(ContractError::TotalDelegationSubOverflow {
|
||||
mix_identity: pending_undelegate.mix_identity(),
|
||||
total_node_delegation: total_node_delegation.unwrap().u128(),
|
||||
to_subtract: total_delegation.u128(),
|
||||
});
|
||||
}
|
||||
};
|
||||
// debug_with_visibility(api, format!("Remaining total delegation: {}", remaining));
|
||||
// the first unwrap is fine because the delegation information MUST exist, otherwise we would
|
||||
// have never gotten here in the first place
|
||||
// the second unwrap is also fine because we should NEVER underflow here,
|
||||
// if we do, it means we have some serious error in our logic
|
||||
Ok(remaining)
|
||||
},
|
||||
)?;
|
||||
|
||||
let total_funds = total_delegation + reward;
|
||||
|
||||
// don't add a bank message if it would have resulted in attempting to send 0 tokens
|
||||
let bank_msg = if total_delegation != Uint128::zero() {
|
||||
Some(BankMsg::Send {
|
||||
@@ -389,19 +335,34 @@ pub(crate) fn try_reconcile_undelegation(
|
||||
.as_ref()
|
||||
.unwrap_or(&pending_undelegate.delegate())
|
||||
.to_string(),
|
||||
amount: coins(total_funds.u128(), DENOM),
|
||||
amount: coins(total_delegation.u128(), DENOM),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
mixnodes_storage::TOTAL_DELEGATION.update::<_, ContractError>(
|
||||
storage,
|
||||
&pending_undelegate.mix_identity(),
|
||||
|total_node_delegation| {
|
||||
// the first unwrap is fine because the delegation information MUST exist, otherwise we would
|
||||
// have never gotten here in the first place
|
||||
// the second unwrap is also fine because we should NEVER underflow here,
|
||||
// if we do, it means we have some serious error in our logic
|
||||
Ok(total_node_delegation
|
||||
.unwrap()
|
||||
.checked_sub(total_delegation)
|
||||
.unwrap())
|
||||
},
|
||||
)?;
|
||||
|
||||
let mut wasm_msg = None;
|
||||
|
||||
if let Some(proxy) = &pending_undelegate.proxy() {
|
||||
let msg = Some(VestingContractExecuteMsg::TrackUndelegation {
|
||||
owner: pending_undelegate.delegate().as_str().to_string(),
|
||||
mix_identity: pending_undelegate.mix_identity(),
|
||||
amount: Coin::new(total_funds.u128(), DENOM),
|
||||
amount: Coin::new(total_delegation.u128(), DENOM),
|
||||
});
|
||||
|
||||
wasm_msg = Some(wasm_execute(proxy, &msg, vec![one_ucoin()])?);
|
||||
@@ -411,11 +372,9 @@ pub(crate) fn try_reconcile_undelegation(
|
||||
&pending_undelegate.delegate(),
|
||||
&pending_undelegate.proxy(),
|
||||
&pending_undelegate.mix_identity(),
|
||||
total_funds,
|
||||
total_delegation,
|
||||
);
|
||||
|
||||
// debug_with_visibility(api, "Done");
|
||||
|
||||
Ok(ReconcileUndelegateResponse {
|
||||
bank_msg,
|
||||
wasm_msg,
|
||||
@@ -568,7 +527,7 @@ mod tests {
|
||||
)
|
||||
.is_ok());
|
||||
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage, &deps.api).unwrap();
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage).unwrap();
|
||||
|
||||
let expected = Delegation::new(
|
||||
delegation_owner.clone(),
|
||||
@@ -647,7 +606,7 @@ mod tests {
|
||||
)
|
||||
.is_ok());
|
||||
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage, &deps.api).unwrap();
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage).unwrap();
|
||||
|
||||
let expected = Delegation::new(
|
||||
delegation_owner.clone(),
|
||||
@@ -710,7 +669,7 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage, &deps.api).unwrap();
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage).unwrap();
|
||||
|
||||
// let expected = Delegation::new(
|
||||
// delegation_owner.clone(),
|
||||
@@ -765,7 +724,7 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage, &deps.api).unwrap();
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
initial_height,
|
||||
@@ -786,7 +745,7 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage, &deps.api).unwrap();
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage).unwrap();
|
||||
|
||||
let delegations = crate::delegations::queries::query_mixnode_delegation(
|
||||
&deps.storage,
|
||||
@@ -831,7 +790,7 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage, &deps.api).unwrap();
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
initial_height,
|
||||
@@ -852,7 +811,7 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage, &deps.api).unwrap();
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
initial_height,
|
||||
@@ -940,7 +899,7 @@ mod tests {
|
||||
)
|
||||
.is_ok());
|
||||
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage, &deps.api).unwrap();
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage).unwrap();
|
||||
|
||||
let expected1 = Delegation::new(
|
||||
delegation_owner.clone(),
|
||||
@@ -1005,7 +964,7 @@ mod tests {
|
||||
identity.clone(),
|
||||
)
|
||||
.is_ok());
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage, &deps.api).unwrap();
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage).unwrap();
|
||||
|
||||
// node's "total_delegation" is sum of both
|
||||
assert_eq!(
|
||||
@@ -1035,7 +994,7 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage, &deps.api).unwrap();
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage).unwrap();
|
||||
|
||||
try_remove_mixnode(mock_env(), deps.as_mut(), mock_info(mixnode_owner, &[])).unwrap();
|
||||
|
||||
@@ -1123,7 +1082,7 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage, &deps.api).unwrap();
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage).unwrap();
|
||||
|
||||
let _delegation = query_mixnode_delegation(
|
||||
&deps.storage,
|
||||
@@ -1193,7 +1152,7 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage, &deps.api).unwrap();
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage).unwrap();
|
||||
|
||||
let delegation = query_mixnode_delegation(
|
||||
&deps.storage,
|
||||
@@ -1228,7 +1187,7 @@ mod tests {
|
||||
)
|
||||
);
|
||||
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage, &deps.api).unwrap();
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage).unwrap();
|
||||
|
||||
assert!(test_helpers::read_delegation(
|
||||
&deps.storage,
|
||||
@@ -1261,7 +1220,7 @@ mod tests {
|
||||
)
|
||||
.is_ok());
|
||||
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage, &deps.api).unwrap();
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage).unwrap();
|
||||
|
||||
assert!(try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
@@ -1271,7 +1230,7 @@ mod tests {
|
||||
)
|
||||
.is_ok());
|
||||
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage, &deps.api).unwrap();
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage).unwrap();
|
||||
|
||||
// sender1 undelegates
|
||||
try_remove_delegation_from_mixnode(
|
||||
@@ -1282,7 +1241,7 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage, &deps.api).unwrap();
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage).unwrap();
|
||||
// but total delegation should still equal to what sender2 sent
|
||||
// node's "total_delegation" is sum of both
|
||||
assert_eq!(
|
||||
|
||||
@@ -168,15 +168,4 @@ pub enum ContractError {
|
||||
identity: String,
|
||||
kind: String, // delegation | undelegation
|
||||
},
|
||||
#[error("Attempted to subsctract more then the total delegation, this MUST never happen! mix: {mix_identity}, total_node_delegation {total_node_delegation}, to_subtract {to_subtract}")]
|
||||
TotalDelegationSubOverflow {
|
||||
mix_identity: String,
|
||||
total_node_delegation: u128,
|
||||
to_subtract: u128,
|
||||
},
|
||||
#[error("Profit margin can be updated only once during a rolling 30 day interval, last update was at {last_update_time} and current block time is {current_block_time}")]
|
||||
UpdatePMTooSoon {
|
||||
last_update_time: u64,
|
||||
current_block_time: u64,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,33 +1,13 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::storage::{self, StoredMixnodeBond};
|
||||
use super::storage;
|
||||
use cosmwasm_std::{Deps, Order, StdResult};
|
||||
use cw_storage_plus::Bound;
|
||||
use mixnet_contract_common::{
|
||||
IdentityKey, MixNodeBond, MixOwnershipResponse, PagedMixnodeResponse,
|
||||
};
|
||||
|
||||
pub fn query_mixnode_at_height(
|
||||
deps: Deps<'_>,
|
||||
mix_identity: String,
|
||||
height: u64,
|
||||
) -> StdResult<Option<StoredMixnodeBond>> {
|
||||
storage::mixnodes().may_load_at_height(deps.storage, &mix_identity, height)
|
||||
}
|
||||
|
||||
pub fn query_checkpoints_for_mixnode(
|
||||
deps: Deps<'_>,
|
||||
mix_identity: IdentityKey,
|
||||
) -> StdResult<Vec<u64>> {
|
||||
Ok(storage::mixnodes()
|
||||
.changelog()
|
||||
.prefix(&mix_identity)
|
||||
.keys(deps.storage, None, None, Order::Ascending)
|
||||
.filter_map(|x| x.ok())
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub fn query_mixnodes_paged(
|
||||
deps: Deps<'_>,
|
||||
start_after: Option<IdentityKey>,
|
||||
|
||||
@@ -19,8 +19,6 @@ const MIXNODES_PK_CHANGELOG: &str = "mn__change";
|
||||
const MIXNODES_OWNER_IDX_NAMESPACE: &str = "mno";
|
||||
const MIXNODES_SPHINX_IDX_NAMESPACE: &str = "mns";
|
||||
|
||||
const LAST_PM_UPDATE_NAMESPACE: &str = "lpm";
|
||||
|
||||
// paged retrieval limits for all queries and transactions
|
||||
pub(crate) const BOND_PAGE_MAX_LIMIT: u32 = 75;
|
||||
pub(crate) const BOND_PAGE_DEFAULT_LIMIT: u32 = 50;
|
||||
@@ -28,9 +26,6 @@ pub(crate) const BOND_PAGE_DEFAULT_LIMIT: u32 = 50;
|
||||
pub(crate) const TOTAL_DELEGATION: Map<'_, IdentityKeyRef<'_>, Uint128> =
|
||||
Map::new(TOTAL_DELEGATION_NAMESPACE);
|
||||
|
||||
pub(crate) const LAST_PM_UPDATE_TIME: Map<'_, IdentityKeyRef<'_>, u64> =
|
||||
Map::new(LAST_PM_UPDATE_NAMESPACE);
|
||||
|
||||
pub(crate) struct MixnodeBondIndex<'a> {
|
||||
pub(crate) owner: UniqueIndex<'a, Addr, StoredMixnodeBond>,
|
||||
|
||||
@@ -60,7 +55,7 @@ pub(crate) fn mixnodes<'a>(
|
||||
MIXNODES_PK_NAMESPACE,
|
||||
MIXNODES_PK_CHECKPOINTS,
|
||||
MIXNODES_PK_CHANGELOG,
|
||||
Strategy::Selected,
|
||||
Strategy::Never,
|
||||
indexes,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::storage::{self, LAST_PM_UPDATE_TIME};
|
||||
use super::storage;
|
||||
use crate::error::ContractError;
|
||||
use crate::mixnet_contract_settings::storage as mixnet_params_storage;
|
||||
use crate::mixnodes::layer_queries::query_layer_distribution;
|
||||
@@ -18,8 +18,6 @@ use mixnet_contract_common::MixNode;
|
||||
use vesting_contract_common::messages::ExecuteMsg as VestingContractExecuteMsg;
|
||||
use vesting_contract_common::one_ucoin;
|
||||
|
||||
const MIN_PM_UPDATE_INTERVAL: u64 = 60 * 60 * 24 * 30; // one month roughly
|
||||
|
||||
pub fn try_checkpoint_mixnodes(
|
||||
storage: &mut dyn Storage,
|
||||
block_height: u64,
|
||||
@@ -154,8 +152,6 @@ fn _try_add_mixnode(
|
||||
storage::TOTAL_DELEGATION.save(deps.storage, identity, &Uint128::zero())?;
|
||||
}
|
||||
|
||||
storage::LAST_PM_UPDATE_TIME.save(deps.storage, identity, &env.block.time.seconds())?;
|
||||
|
||||
mixnet_params_storage::increment_layer_count(deps.storage, stored_bond.layer)?;
|
||||
|
||||
Ok(Response::new().add_event(new_mixnode_bonding_event(
|
||||
@@ -195,7 +191,6 @@ pub(crate) fn _try_remove_mixnode(
|
||||
|
||||
crate::rewards::transactions::_try_compound_operator_reward(
|
||||
deps.storage,
|
||||
deps.api,
|
||||
env.block.height,
|
||||
&owner,
|
||||
None,
|
||||
@@ -298,19 +293,6 @@ pub(crate) fn _try_update_mixnode_config(
|
||||
});
|
||||
}
|
||||
|
||||
let last_update_time = storage::LAST_PM_UPDATE_TIME
|
||||
.load(deps.storage, mixnode_bond.identity())
|
||||
.unwrap_or(0);
|
||||
|
||||
let current_block_time = env.block.time.seconds();
|
||||
|
||||
if current_block_time - last_update_time < MIN_PM_UPDATE_INTERVAL {
|
||||
return Err(ContractError::UpdatePMTooSoon {
|
||||
last_update_time,
|
||||
current_block_time,
|
||||
});
|
||||
}
|
||||
|
||||
// We don't have to check lower bound as its an u8
|
||||
if profit_margin_percent > 100 {
|
||||
return Err(ContractError::InvalidProfitMarginPercent(
|
||||
@@ -333,8 +315,6 @@ pub(crate) fn _try_update_mixnode_config(
|
||||
},
|
||||
)?;
|
||||
|
||||
LAST_PM_UPDATE_TIME.save(deps.storage, mixnode_bond.identity(), ¤t_block_time)?;
|
||||
|
||||
let mut response = Response::new();
|
||||
|
||||
if let Some(proxy) = proxy {
|
||||
@@ -381,8 +361,6 @@ fn validate_mixnode_pledge(
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use std::f64::MIN;
|
||||
|
||||
use super::*;
|
||||
use crate::contract::{execute, query, INITIAL_MIXNODE_PLEDGE};
|
||||
use crate::error::ContractError;
|
||||
@@ -736,7 +714,6 @@ pub mod tests {
|
||||
#[test]
|
||||
fn updating_mixnode_config() {
|
||||
let sender = "bob";
|
||||
let mut env = mock_env();
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let info = mock_info(sender, &[]);
|
||||
|
||||
@@ -744,7 +721,7 @@ pub mod tests {
|
||||
let msg = ExecuteMsg::UpdateMixnodeConfig {
|
||||
profit_margin_percent: 10,
|
||||
};
|
||||
let ret = execute(deps.as_mut(), env.clone(), info.clone(), msg);
|
||||
let ret = execute(deps.as_mut(), mock_env(), info.clone(), msg);
|
||||
assert_eq!(
|
||||
ret,
|
||||
Err(ContractError::NoAssociatedMixNodeBond {
|
||||
@@ -773,14 +750,12 @@ pub mod tests {
|
||||
.profit_margin_percent
|
||||
);
|
||||
|
||||
env.block.time = env.block.time.plus_seconds(MIN_PM_UPDATE_INTERVAL + 1);
|
||||
|
||||
// try updating with an invalid value
|
||||
let profit_margin_percent = 101;
|
||||
let msg = ExecuteMsg::UpdateMixnodeConfig {
|
||||
profit_margin_percent,
|
||||
};
|
||||
let ret = execute(deps.as_mut(), env.clone(), info.clone(), msg);
|
||||
let ret = execute(deps.as_mut(), mock_env(), info.clone(), msg);
|
||||
assert_eq!(
|
||||
ret,
|
||||
Err(ContractError::InvalidProfitMarginPercent(
|
||||
@@ -792,7 +767,7 @@ pub mod tests {
|
||||
let msg = ExecuteMsg::UpdateMixnodeConfig {
|
||||
profit_margin_percent,
|
||||
};
|
||||
execute(deps.as_mut(), env, info, msg).unwrap();
|
||||
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
|
||||
assert_eq!(
|
||||
profit_margin_percent,
|
||||
storage::mixnodes()
|
||||
@@ -906,51 +881,4 @@ pub mod tests {
|
||||
// change identity but reuse sphinx key
|
||||
assert!(try_add_mixnode(deps.as_mut(), mock_env(), info_bob, mixnode, sig2).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn updating_pm_too_often_fails() {
|
||||
use super::MIN_PM_UPDATE_INTERVAL;
|
||||
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let mut env = mock_env();
|
||||
|
||||
let keypair1 = crypto::asymmetric::identity::KeyPair::new(&mut thread_rng());
|
||||
let sig1 = keypair1.private_key().sign_text("alice");
|
||||
|
||||
let info_alice = mock_info("alice", &tests::fixtures::good_mixnode_pledge());
|
||||
|
||||
let mixnode = MixNode {
|
||||
host: "1.2.3.4".to_string(),
|
||||
mix_port: 1234,
|
||||
verloc_port: 1234,
|
||||
http_api_port: 1234,
|
||||
sphinx_key: crypto::asymmetric::encryption::KeyPair::new(&mut thread_rng())
|
||||
.public_key()
|
||||
.to_base58_string(),
|
||||
identity_key: keypair1.public_key().to_base58_string(),
|
||||
version: "v0.1.2.3".to_string(),
|
||||
profit_margin_percent: 10,
|
||||
};
|
||||
|
||||
assert!(try_add_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
info_alice.clone(),
|
||||
mixnode.clone(),
|
||||
sig1
|
||||
)
|
||||
.is_ok());
|
||||
|
||||
env.block.time = env.block.time.plus_seconds(MIN_PM_UPDATE_INTERVAL - 1);
|
||||
|
||||
// fails if too soon after bonding
|
||||
assert!(
|
||||
try_update_mixnode_config(deps.as_mut(), env.clone(), info_alice.clone(), 20).is_err()
|
||||
);
|
||||
|
||||
env.block.time = env.block.time.plus_seconds(2);
|
||||
|
||||
// succeds after some time
|
||||
assert!(try_update_mixnode_config(deps.as_mut(), env, info_alice, 20).is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ pub fn query_operator_reward(deps: Deps, owner: String) -> Result<Uint128, Contr
|
||||
}
|
||||
};
|
||||
|
||||
super::transactions::calculate_operator_reward(deps.storage, deps.api, &owner_address, &bond)
|
||||
super::transactions::calculate_operator_reward(deps.storage, &owner_address, &bond)
|
||||
}
|
||||
|
||||
pub fn query_delegator_reward(
|
||||
@@ -48,20 +48,17 @@ pub fn query_delegator_reward(
|
||||
mix_identity: IdentityKey,
|
||||
proxy: Option<String>,
|
||||
) -> Result<Uint128, ContractError> {
|
||||
let proxy = match proxy {
|
||||
Some(proxy) => Some(
|
||||
deps.api
|
||||
.addr_validate(&proxy)
|
||||
.map_err(|_| ContractError::InvalidAddress(proxy))?,
|
||||
),
|
||||
None => None,
|
||||
};
|
||||
|
||||
let proxy = proxy.map(|p| {
|
||||
deps.api
|
||||
.addr_validate(&p)
|
||||
.map_err(|_| ContractError::InvalidAddress(p))
|
||||
.expect("proxy address is invalid")
|
||||
});
|
||||
let key = mixnet_contract_common::delegation::generate_storage_key(
|
||||
&deps.api.addr_validate(&owner)?,
|
||||
proxy.as_ref(),
|
||||
);
|
||||
super::transactions::calculate_delegator_reward(deps.storage, deps.api, key, &mix_identity)
|
||||
super::transactions::calculate_delegator_reward(deps.storage, key, &mix_identity)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -60,5 +60,5 @@ pub fn decr_reward_pool(
|
||||
|
||||
pub fn circulating_supply(storage: &dyn Storage) -> StdResult<Uint128> {
|
||||
let reward_pool = REWARD_POOL.load(storage)?;
|
||||
Ok(Uint128::new(TOTAL_SUPPLY).saturating_sub(reward_pool))
|
||||
Ok(Uint128::new(TOTAL_SUPPLY) - reward_pool)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ use super::storage::{
|
||||
OPERATOR_REWARD_CLAIMED_HEIGHT,
|
||||
};
|
||||
use crate::constants;
|
||||
use crate::contract::debug_with_visibility;
|
||||
use crate::delegations::storage as delegations_storage;
|
||||
use crate::delegations::transactions::_try_delegate_to_mixnode;
|
||||
use crate::error::ContractError;
|
||||
@@ -16,7 +15,6 @@ use crate::rewards::helpers;
|
||||
use crate::support::helpers::is_authorized;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{Addr, Api, Coin, DepsMut, Env, MessageInfo, Order, Response, Storage, Uint128};
|
||||
use cw_storage_plus::Bound;
|
||||
use mixnet_contract_common::events::{
|
||||
new_compound_delegator_reward_event, new_compound_operator_reward_event,
|
||||
new_mix_operator_rewarding_event, new_not_found_mix_operator_rewarding_event,
|
||||
@@ -37,13 +35,8 @@ pub fn try_compound_operator_reward_on_behalf(
|
||||
let proxy = deps.api.addr_validate(info.sender.as_str())?;
|
||||
let owner = deps.api.addr_validate(&owner)?;
|
||||
|
||||
let reward = _try_compound_operator_reward(
|
||||
deps.storage,
|
||||
deps.api,
|
||||
env.block.height,
|
||||
&owner,
|
||||
Some(proxy),
|
||||
)?;
|
||||
let reward =
|
||||
_try_compound_operator_reward(deps.storage, env.block.height, &owner, Some(proxy))?;
|
||||
|
||||
Ok(Response::new().add_event(new_compound_operator_reward_event(&owner, reward)))
|
||||
}
|
||||
@@ -54,15 +47,13 @@ pub fn try_compound_operator_reward(
|
||||
info: MessageInfo,
|
||||
) -> Result<Response, ContractError> {
|
||||
let owner = deps.api.addr_validate(info.sender.as_str())?;
|
||||
let reward =
|
||||
_try_compound_operator_reward(deps.storage, deps.api, env.block.height, &owner, None)?;
|
||||
let reward = _try_compound_operator_reward(deps.storage, env.block.height, &owner, None)?;
|
||||
|
||||
Ok(Response::new().add_event(new_compound_operator_reward_event(&owner, reward)))
|
||||
}
|
||||
|
||||
pub fn _try_compound_operator_reward(
|
||||
storage: &mut dyn Storage,
|
||||
api: &dyn Api,
|
||||
block_height: u64,
|
||||
owner: &Addr,
|
||||
proxy: Option<Addr>,
|
||||
@@ -81,9 +72,8 @@ pub fn _try_compound_operator_reward(
|
||||
}
|
||||
|
||||
let mut updated_bond = bond.clone();
|
||||
let reward = calculate_operator_reward(storage, api, owner, &bond)?;
|
||||
updated_bond.accumulated_rewards =
|
||||
Some(updated_bond.accumulated_rewards().saturating_sub(reward));
|
||||
let reward = calculate_operator_reward(storage, owner, &bond)?;
|
||||
updated_bond.accumulated_rewards = Some(updated_bond.accumulated_rewards() - reward);
|
||||
updated_bond.pledge_amount.amount += reward;
|
||||
mixnodes().replace(
|
||||
storage,
|
||||
@@ -104,7 +94,6 @@ pub fn _try_compound_operator_reward(
|
||||
|
||||
pub fn calculate_operator_reward(
|
||||
storage: &dyn Storage,
|
||||
api: &dyn Api,
|
||||
owner: &Addr,
|
||||
bond: &StoredMixnodeBond,
|
||||
) -> Result<Uint128, ContractError> {
|
||||
@@ -115,33 +104,26 @@ pub fn calculate_operator_reward(
|
||||
let accumulated_rewards = mixnodes()
|
||||
.changelog()
|
||||
.prefix(bond.identity())
|
||||
.keys(
|
||||
storage,
|
||||
Some(Bound::exclusive(last_claimed_height)),
|
||||
None,
|
||||
Order::Ascending,
|
||||
)
|
||||
.keys(storage, None, None, Order::Ascending)
|
||||
.filter_map(|height| height.ok())
|
||||
.filter(|height| last_claimed_height <= *height)
|
||||
.fold(
|
||||
Ok(Uint128::zero()),
|
||||
|acc, height| -> Result<Uint128, ContractError> {
|
||||
let accumulated_reward = acc?;
|
||||
if let Some(bond) = mixnodes()
|
||||
.may_load_at_height(storage, bond.identity().as_str(), height)
|
||||
.ok()
|
||||
.flatten()
|
||||
if let Some(bond) =
|
||||
mixnodes().may_load_at_height(storage, bond.identity().as_str(), height)?
|
||||
{
|
||||
if let Some(ref epoch_rewards) = bond.epoch_rewards {
|
||||
if let Some(epoch_rewards) = bond.epoch_rewards {
|
||||
let epoch_reward_params =
|
||||
epoch_reward_params_for_id(storage, epoch_rewards.epoch_id())?;
|
||||
// Compound rewards from previous heights
|
||||
match epoch_rewards.operator_reward(bond.profit_margin()) {
|
||||
Ok(reward) => return Ok(accumulated_reward + reward),
|
||||
Err(err) => {
|
||||
debug_with_visibility(
|
||||
api,
|
||||
format!("Failed to calculate operator reward: {:?}", err),
|
||||
);
|
||||
}
|
||||
};
|
||||
let reward_at_height = epoch_rewards.delegation_reward(
|
||||
bond.pledge_amount().amount + accumulated_reward,
|
||||
bond.profit_margin(),
|
||||
epoch_reward_params,
|
||||
)?;
|
||||
return Ok(accumulated_reward + reward_at_height);
|
||||
}
|
||||
};
|
||||
Ok(accumulated_reward)
|
||||
@@ -168,7 +150,8 @@ pub fn try_compound_delegator_reward_on_behalf(
|
||||
let owner = deps.api.addr_validate(&owner)?;
|
||||
let reward = _try_compound_delegator_reward(
|
||||
env.block.height,
|
||||
deps,
|
||||
deps.api,
|
||||
deps.storage,
|
||||
owner.as_str(),
|
||||
&mix_identity,
|
||||
Some(proxy.clone()),
|
||||
@@ -193,7 +176,8 @@ pub fn try_compound_delegator_reward(
|
||||
let owner = deps.api.addr_validate(info.sender.as_str())?;
|
||||
let reward = _try_compound_delegator_reward(
|
||||
env.block.height,
|
||||
deps,
|
||||
deps.api,
|
||||
deps.storage,
|
||||
owner.as_str(),
|
||||
&mix_identity,
|
||||
None,
|
||||
@@ -211,7 +195,8 @@ pub fn try_compound_delegator_reward(
|
||||
|
||||
pub fn _try_compound_delegator_reward(
|
||||
block_height: u64,
|
||||
mut deps: DepsMut<'_>,
|
||||
api: &dyn Api,
|
||||
storage: &mut dyn Storage,
|
||||
owner_address: &str,
|
||||
mix_identity: &str,
|
||||
proxy: Option<Addr>,
|
||||
@@ -219,25 +204,25 @@ pub fn _try_compound_delegator_reward(
|
||||
let delegation_map = crate::delegations::storage::delegations();
|
||||
|
||||
let key = mixnet_contract_common::delegation::generate_storage_key(
|
||||
&deps.api.addr_validate(owner_address)?,
|
||||
&api.addr_validate(owner_address)?,
|
||||
proxy.as_ref(),
|
||||
);
|
||||
let reward = calculate_delegator_reward(deps.storage, deps.api, key.clone(), mix_identity)?;
|
||||
let reward = calculate_delegator_reward(storage, key.clone(), mix_identity)?;
|
||||
let mut compounded_delegation = reward;
|
||||
|
||||
// Might want to introduce paging here
|
||||
let delegation_heights = delegation_map
|
||||
.prefix((mix_identity.to_string(), key.clone()))
|
||||
.keys(deps.storage, None, None, cosmwasm_std::Order::Ascending)
|
||||
.keys(storage, None, None, cosmwasm_std::Order::Ascending)
|
||||
.filter_map(|v| v.ok())
|
||||
.collect::<Vec<u64>>();
|
||||
|
||||
for h in delegation_heights {
|
||||
let delegation =
|
||||
delegation_map.load(deps.storage, (mix_identity.to_string(), key.clone(), h))?;
|
||||
delegation_map.load(storage, (mix_identity.to_string(), key.clone(), h))?;
|
||||
compounded_delegation += delegation.amount.amount;
|
||||
delegation_map.replace(
|
||||
deps.storage,
|
||||
storage,
|
||||
(mix_identity.to_string(), key.clone(), h),
|
||||
None,
|
||||
Some(&delegation),
|
||||
@@ -246,12 +231,13 @@ pub fn _try_compound_delegator_reward(
|
||||
|
||||
if compounded_delegation != Uint128::zero() {
|
||||
_try_delegate_to_mixnode(
|
||||
deps.branch(),
|
||||
storage,
|
||||
api,
|
||||
block_height,
|
||||
mix_identity,
|
||||
owner_address,
|
||||
Coin {
|
||||
amount: compounded_delegation,
|
||||
amount: reward,
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
proxy,
|
||||
@@ -259,14 +245,15 @@ pub fn _try_compound_delegator_reward(
|
||||
}
|
||||
|
||||
{
|
||||
if let Some(mut bond) = mixnodes().may_load(deps.storage, mix_identity)? {
|
||||
bond.accumulated_rewards = Some(bond.accumulated_rewards().saturating_sub(reward));
|
||||
mixnodes().save(deps.storage, mix_identity, &bond, block_height)?;
|
||||
//TODO: Node exists all is well, life goes on, if it does not exist we'll just return the reward to the caller as there is nothing to do on the bond
|
||||
if let Some(mut bond) = mixnodes().may_load(storage, mix_identity)? {
|
||||
bond.accumulated_rewards = Some(bond.accumulated_rewards() - reward);
|
||||
mixnodes().save(storage, mix_identity, &bond, block_height)?;
|
||||
}
|
||||
}
|
||||
|
||||
DELEGATOR_REWARD_CLAIMED_HEIGHT.save(
|
||||
deps.storage,
|
||||
storage,
|
||||
(key, mix_identity.to_string()),
|
||||
&block_height,
|
||||
)?;
|
||||
@@ -279,7 +266,6 @@ pub fn _try_compound_delegator_reward(
|
||||
// + last_reward_claimed height is correctly used
|
||||
pub fn calculate_delegator_reward(
|
||||
storage: &dyn Storage,
|
||||
api: &dyn Api,
|
||||
key: Vec<u8>,
|
||||
mix_identity: &str,
|
||||
) -> Result<Uint128, ContractError> {
|
||||
@@ -289,96 +275,45 @@ pub fn calculate_delegator_reward(
|
||||
|
||||
// Get delegations newer then last_claimed_height, it would be nice to also fold this into the iteration bellow but it should be ok for now, as
|
||||
// I doubt folks refresh their delegations often
|
||||
let mut delegations = delegations_storage::delegations()
|
||||
let delegations = delegations_storage::delegations()
|
||||
.prefix((mix_identity.to_string(), key))
|
||||
.range(
|
||||
storage,
|
||||
Some(Bound::exclusive(last_claimed_height)),
|
||||
None,
|
||||
Order::Descending,
|
||||
)
|
||||
.range(storage, None, None, Order::Descending)
|
||||
.filter_map(|record| record.ok())
|
||||
.filter(|(height, _)| last_claimed_height <= *height)
|
||||
.map(|(_, delegation)| delegation)
|
||||
.collect::<Vec<Delegation>>();
|
||||
|
||||
// Accumulate outside of the loop to gain some speed, on a log of checkpoints
|
||||
let mut delegation_at_height = Uint128::zero();
|
||||
|
||||
// This is a bit gnarly, but we want to avoid loading all heights, the loading mixnodes, so we're doing it all in the iterator
|
||||
let accumulated_rewards = mixnodes()
|
||||
.changelog()
|
||||
.prefix(mix_identity)
|
||||
.keys(
|
||||
storage,
|
||||
Some(Bound::exclusive(last_claimed_height)),
|
||||
None,
|
||||
Order::Ascending,
|
||||
)
|
||||
.keys(storage, None, None, Order::Ascending)
|
||||
.filter_map(|height| height.ok())
|
||||
// Get all checkpoints greater then last claimed delegation height
|
||||
.filter(|height| last_claimed_height <= *height)
|
||||
.fold(
|
||||
Ok(Uint128::zero()),
|
||||
|acc, height| -> Result<Uint128, ContractError> {
|
||||
let accumulated_reward = acc?;
|
||||
delegation_at_height = delegations
|
||||
let delegation_at_height = delegations
|
||||
.iter()
|
||||
.filter(|d| d.block_height <= height)
|
||||
.fold(delegation_at_height, |total, delegation| {
|
||||
.filter(|d| height <= d.block_height)
|
||||
.fold(Uint128::zero(), |total, delegation| {
|
||||
total + delegation.amount.amount
|
||||
});
|
||||
// Drop what we've processed
|
||||
// This should be replaced with drain_filter once it stabilizes
|
||||
delegations.retain(|d| d.block_height > height);
|
||||
// debug_with_visibility(
|
||||
// api,
|
||||
// format!("delegation at height {} - {}", height, delegation_at_height),
|
||||
// );
|
||||
if delegation_at_height != Uint128::zero() {
|
||||
// debug_with_visibility(
|
||||
// api,
|
||||
// format!("Loading bond {} at height {}", mix_identity, height),
|
||||
// );
|
||||
if let Some(bond) = mixnodes()
|
||||
.may_load_at_height(storage, mix_identity, height)
|
||||
.ok()
|
||||
.flatten()
|
||||
if let Some(bond) =
|
||||
mixnodes().may_load_at_height(storage, mix_identity, height)?
|
||||
{
|
||||
if let Some(ref epoch_rewards) = bond.epoch_rewards {
|
||||
if let Some(epoch_rewards) = bond.epoch_rewards {
|
||||
// Compound rewards from previous heights
|
||||
match epoch_reward_params_for_id(storage, epoch_rewards.epoch_id()) {
|
||||
Ok(params) => {
|
||||
let reward_at_height = match epoch_rewards.delegation_reward(
|
||||
delegation_at_height + accumulated_reward,
|
||||
bond.profit_margin(),
|
||||
params,
|
||||
) {
|
||||
Ok(reward) => {
|
||||
// debug_with_visibility(
|
||||
// api,
|
||||
// format!("Reward at height {} - {}", height, reward),
|
||||
// );
|
||||
reward
|
||||
}
|
||||
Err(err) => {
|
||||
debug_with_visibility(
|
||||
api,
|
||||
format!(
|
||||
"Error calculating reward at {} - {}",
|
||||
height, err
|
||||
),
|
||||
);
|
||||
Uint128::zero()
|
||||
}
|
||||
};
|
||||
return Ok(accumulated_reward + reward_at_height);
|
||||
}
|
||||
Err(_err) => {
|
||||
debug_with_visibility(
|
||||
api,
|
||||
format!("No epoch reward params for epoch {}", height),
|
||||
);
|
||||
}
|
||||
}
|
||||
let epoch_reward_params =
|
||||
epoch_reward_params_for_id(storage, epoch_rewards.epoch_id())?;
|
||||
let reward_at_height = epoch_rewards.delegation_reward(
|
||||
delegation_at_height + accumulated_reward,
|
||||
bond.profit_margin(),
|
||||
epoch_reward_params,
|
||||
)?;
|
||||
return Ok(accumulated_reward + reward_at_height);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -520,9 +455,7 @@ pub(crate) fn try_reward_mixnode(
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use crate::constants::EPOCHS_IN_INTERVAL;
|
||||
use crate::delegations::transactions::{
|
||||
_try_remove_delegation_from_mixnode, try_delegate_to_mixnode,
|
||||
};
|
||||
use crate::delegations::transactions::try_delegate_to_mixnode;
|
||||
use crate::error::ContractError;
|
||||
use crate::interval::storage::{
|
||||
current_epoch_reward_params, save_epoch, save_epoch_reward_params,
|
||||
@@ -539,7 +472,7 @@ pub mod tests {
|
||||
use az::CheckedCast;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::testing::{mock_env, mock_info};
|
||||
use cosmwasm_std::{coin, coins, Addr, StdError, Timestamp, Uint128};
|
||||
use cosmwasm_std::{coin, coins, Addr, Timestamp, Uint128};
|
||||
use mixnet_contract_common::events::{
|
||||
must_find_attribute, BOND_TOO_FRESH_VALUE, NO_REWARD_REASON_KEY,
|
||||
OPERATOR_REWARDING_EVENT_TYPE,
|
||||
@@ -875,13 +808,9 @@ pub mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reward_additivity_and_snapshots() {
|
||||
fn test_reward_additivity() {
|
||||
use crate::constants::INTERVAL_REWARD_PERCENT;
|
||||
use crate::contract::INITIAL_REWARD_POOL;
|
||||
use crate::mixnodes::transactions::try_add_mixnode;
|
||||
use rand::thread_rng;
|
||||
|
||||
let mixnodes = crate::mixnodes::storage::mixnodes();
|
||||
|
||||
type U128 = fixed::types::U75F53;
|
||||
|
||||
@@ -891,81 +820,14 @@ pub mod tests {
|
||||
.load(deps.as_ref().storage)
|
||||
.unwrap();
|
||||
let rewarding_validator_address = current_state.rewarding_validator_address;
|
||||
|
||||
let info = mock_info(rewarding_validator_address.as_str(), &[]);
|
||||
|
||||
crate::mixnodes::transactions::try_checkpoint_mixnodes(
|
||||
&mut deps.storage,
|
||||
env.block.height,
|
||||
info.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
let checkpoints = mixnodes
|
||||
.changelog()
|
||||
.keys(&deps.storage, None, None, Order::Ascending)
|
||||
.filter_map(|x| x.ok())
|
||||
.collect::<Vec<(IdentityKey, u64)>>();
|
||||
assert_eq!(0, checkpoints.len());
|
||||
|
||||
let period_reward_pool = (INITIAL_REWARD_POOL / 100 / EPOCHS_IN_INTERVAL as u128)
|
||||
* INTERVAL_REWARD_PERCENT as u128;
|
||||
assert_eq!(period_reward_pool, 6_944_444_444);
|
||||
let circulating_supply = storage::circulating_supply(&deps.storage).unwrap().u128();
|
||||
assert_eq!(circulating_supply, 750_000_000_000_000u128);
|
||||
|
||||
let sender = Addr::unchecked("alice");
|
||||
let stake = coins(10_000_000_000, DENOM);
|
||||
|
||||
let keypair = crypto::asymmetric::identity::KeyPair::new(&mut thread_rng());
|
||||
let owner_signature = keypair
|
||||
.private_key()
|
||||
.sign(sender.as_bytes())
|
||||
.to_base58_string();
|
||||
|
||||
let legit_sphinx_key = crypto::asymmetric::encryption::KeyPair::new(&mut thread_rng());
|
||||
|
||||
let info = mock_info(sender.as_str(), &stake);
|
||||
|
||||
let node_identity_1 = keypair.public_key().to_base58_string();
|
||||
|
||||
env.block.height;
|
||||
|
||||
try_add_mixnode(
|
||||
deps.as_mut(),
|
||||
env.clone(),
|
||||
info.clone(),
|
||||
MixNode {
|
||||
identity_key: node_identity_1.clone(),
|
||||
sphinx_key: legit_sphinx_key.public_key().to_base58_string(),
|
||||
..tests::fixtures::mix_node_fixture()
|
||||
},
|
||||
owner_signature,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// tick
|
||||
|
||||
env.block.height += 1;
|
||||
|
||||
let info = mock_info(rewarding_validator_address.as_str(), &[]);
|
||||
crate::mixnodes::transactions::try_checkpoint_mixnodes(
|
||||
&mut deps.storage,
|
||||
env.block.height,
|
||||
info.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
mixnodes
|
||||
.assert_checkpointed(&deps.storage, env.block.height)
|
||||
.unwrap();
|
||||
let checkpoints = mixnodes
|
||||
.changelog()
|
||||
.keys(&deps.storage, None, None, Order::Ascending)
|
||||
.filter_map(|x| x.ok())
|
||||
.collect::<Vec<(IdentityKey, u64)>>();
|
||||
assert_eq!(checkpoints.len(), 1);
|
||||
|
||||
let node_owner: Addr = Addr::unchecked("johnny");
|
||||
let node_identity_2 = test_helpers::add_mixnode(
|
||||
let node_owner: Addr = Addr::unchecked("alice");
|
||||
let node_identity = test_helpers::add_mixnode(
|
||||
node_owner.as_str(),
|
||||
coins(10_000_000_000, DENOM),
|
||||
deps.as_mut(),
|
||||
@@ -975,7 +837,7 @@ pub mod tests {
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info("alice_d1", &[coin(8000_000000, DENOM)]),
|
||||
node_identity_1.clone(),
|
||||
node_identity.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -983,10 +845,17 @@ pub mod tests {
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info("alice_d2", &[coin(2000_000000, DENOM)]),
|
||||
node_identity_1.clone(),
|
||||
node_identity.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let node_owner: Addr = Addr::unchecked("bob");
|
||||
let node_identity_2 = test_helpers::add_mixnode(
|
||||
node_owner.as_str(),
|
||||
coins(10_000_000_000, DENOM),
|
||||
deps.as_mut(),
|
||||
);
|
||||
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
@@ -1026,16 +895,13 @@ pub mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
crate::delegations::transactions::_try_reconcile_all_delegation_events(
|
||||
&mut deps.storage,
|
||||
&deps.api,
|
||||
)
|
||||
.unwrap();
|
||||
crate::delegations::transactions::_try_reconcile_all_delegation_events(&mut deps.storage)
|
||||
.unwrap();
|
||||
|
||||
let info = mock_info(rewarding_validator_address.as_ref(), &[]);
|
||||
env.block.height += 2 * constants::MINIMUM_BLOCK_AGE_FOR_REWARDING;
|
||||
|
||||
let mix_1 = mixnodes_storage::read_full_mixnode_bond(&deps.storage, &node_identity_1)
|
||||
let mix_1 = mixnodes_storage::read_full_mixnode_bond(&deps.storage, &node_identity)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let mix_1_uptime = 100;
|
||||
@@ -1076,230 +942,6 @@ pub mod tests {
|
||||
|
||||
let mix_1_reward_result = mix_1.reward(¶ms);
|
||||
|
||||
let info = mock_info(rewarding_validator_address.as_str(), &[]);
|
||||
crate::mixnodes::transactions::try_checkpoint_mixnodes(
|
||||
&mut deps.storage,
|
||||
env.block.height,
|
||||
info.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
mixnodes
|
||||
.assert_checkpointed(&deps.storage, env.block.height)
|
||||
.unwrap();
|
||||
|
||||
try_reward_mixnode(
|
||||
deps.as_mut(),
|
||||
env.clone(),
|
||||
info.clone(),
|
||||
node_identity_1.clone(),
|
||||
node_reward_params,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mix_after_reward = mixnodes.may_load(&deps.storage, &node_identity_1).unwrap();
|
||||
// println!("{:?}", mix_after_reward);
|
||||
|
||||
let checkpoints = mixnodes
|
||||
.changelog()
|
||||
.prefix(&node_identity_1)
|
||||
.keys(&deps.storage, None, None, Order::Ascending)
|
||||
.filter_map(|x| x.ok())
|
||||
.collect::<Vec<u64>>();
|
||||
assert_eq!(checkpoints.len(), 2);
|
||||
|
||||
env.block.height += 10000;
|
||||
env.block.time = env.block.time.plus_seconds(3601);
|
||||
|
||||
try_advance_epoch(
|
||||
env.clone(),
|
||||
&mut deps.storage,
|
||||
rewarding_validator_address.to_string(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// After two snapshots we should see an increase in delegation
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
env.clone(),
|
||||
mock_info("alice_d1", &[coin(8000_000000, DENOM)]),
|
||||
node_identity_1.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
crate::delegations::transactions::_try_reconcile_all_delegation_events(
|
||||
&mut deps.storage,
|
||||
&deps.api,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let info = mock_info(rewarding_validator_address.as_str(), &[]);
|
||||
crate::mixnodes::transactions::try_checkpoint_mixnodes(
|
||||
&mut deps.storage,
|
||||
env.block.height,
|
||||
info.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
mixnodes
|
||||
.assert_checkpointed(&deps.storage, env.block.height)
|
||||
.unwrap();
|
||||
|
||||
try_reward_mixnode(
|
||||
deps.as_mut(),
|
||||
env.clone(),
|
||||
info.clone(),
|
||||
node_identity_1.clone(),
|
||||
node_reward_params,
|
||||
)
|
||||
.unwrap();
|
||||
let mix_after_reward_2 = mixnodes.may_load(&deps.storage, &node_identity_1).unwrap();
|
||||
|
||||
assert_ne!(mix_after_reward, mix_after_reward_2);
|
||||
|
||||
let checkpoints = mixnodes
|
||||
.changelog()
|
||||
.prefix(&node_identity_1)
|
||||
.keys(&deps.storage, None, None, Order::Ascending)
|
||||
.collect::<Vec<Result<u64, StdError>>>();
|
||||
assert_eq!(checkpoints.len(), 3);
|
||||
|
||||
env.block.height += 10000;
|
||||
env.block.time = env.block.time.plus_seconds(3601);
|
||||
|
||||
try_advance_epoch(
|
||||
env.clone(),
|
||||
&mut deps.storage,
|
||||
rewarding_validator_address.to_string(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let info = mock_info(rewarding_validator_address.as_str(), &[]);
|
||||
crate::mixnodes::transactions::try_checkpoint_mixnodes(
|
||||
&mut deps.storage,
|
||||
env.block.height,
|
||||
info.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
mixnodes
|
||||
.assert_checkpointed(&deps.storage, env.block.height)
|
||||
.unwrap();
|
||||
|
||||
try_reward_mixnode(
|
||||
deps.as_mut(),
|
||||
env.clone(),
|
||||
info.clone(),
|
||||
node_identity_1.clone(),
|
||||
node_reward_params,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let checkpoints = mixnodes
|
||||
.changelog()
|
||||
.prefix(&node_identity_1)
|
||||
.keys(&deps.storage, None, None, Order::Ascending)
|
||||
.filter_map(|x| x.ok())
|
||||
.collect::<Vec<u64>>();
|
||||
assert_eq!(checkpoints.len(), 4);
|
||||
|
||||
let delegation_map = crate::delegations::storage::delegations();
|
||||
let key = "alice_d1".as_bytes().to_vec();
|
||||
|
||||
let last_claimed_height = storage::DELEGATOR_REWARD_CLAIMED_HEIGHT
|
||||
.load(&deps.storage, (key.clone(), node_identity_1.to_string()))
|
||||
.unwrap_or(0);
|
||||
|
||||
assert_eq!(last_claimed_height, 0);
|
||||
|
||||
let viable_delegations = delegation_map
|
||||
.prefix((node_identity_1.to_string(), key.clone()))
|
||||
.range(&deps.storage, None, None, Order::Descending)
|
||||
.filter_map(|record| record.ok())
|
||||
.filter(|(height, _)| last_claimed_height <= *height)
|
||||
.map(|(_, delegation)| delegation)
|
||||
.collect::<Vec<Delegation>>();
|
||||
|
||||
assert_eq!(viable_delegations.len(), 2);
|
||||
|
||||
let viable_heights = mixnodes
|
||||
.changelog()
|
||||
.prefix(&node_identity_1)
|
||||
.keys(&deps.storage, None, None, Order::Ascending)
|
||||
.filter_map(|height| height.ok())
|
||||
.filter(|height| last_claimed_height <= *height)
|
||||
.collect::<Vec<u64>>();
|
||||
|
||||
// Should be equal to the number of checkpoints
|
||||
assert_eq!(viable_heights.len(), 4);
|
||||
|
||||
for (i, h) in viable_heights.into_iter().enumerate() {
|
||||
let delegation_at_height = viable_delegations
|
||||
.iter()
|
||||
.filter(|d| d.block_height <= h)
|
||||
.fold(Uint128::zero(), |total, delegation| {
|
||||
total + delegation.amount.amount
|
||||
});
|
||||
if i < 2 {
|
||||
assert_eq!(delegation_at_height, Uint128::new(8000000000));
|
||||
} else {
|
||||
assert_eq!(delegation_at_height, Uint128::new(16000000000));
|
||||
}
|
||||
}
|
||||
|
||||
let alice_reward =
|
||||
calculate_delegator_reward(&deps.storage, &deps.api, key.clone(), &node_identity_1)
|
||||
.unwrap();
|
||||
assert_eq!(alice_reward, Uint128::new(304552));
|
||||
|
||||
let mix_0 = mixnodes.load(&deps.storage, &node_identity_1).unwrap();
|
||||
|
||||
_try_compound_delegator_reward(
|
||||
env.block.height,
|
||||
deps.as_mut(),
|
||||
"alice_d1",
|
||||
&node_identity_1,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
crate::delegations::transactions::_try_reconcile_all_delegation_events(
|
||||
&mut deps.storage,
|
||||
&deps.api,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let delegations = crate::delegations::storage::delegations()
|
||||
.prefix((node_identity_1.to_string(), key.clone()))
|
||||
.range(&deps.storage, None, None, Order::Ascending)
|
||||
.filter_map(|x| x.ok())
|
||||
.map(|(_, delegation)| delegation)
|
||||
.collect::<Vec<Delegation>>();
|
||||
assert_eq!(delegations.len(), 1);
|
||||
|
||||
let delegation = delegations.first().unwrap();
|
||||
assert_eq!(delegation.amount.amount, Uint128::new(16000000000 + 304552));
|
||||
|
||||
let mix_1 = mixnodes
|
||||
.load(&deps.storage, &node_identity_1.clone())
|
||||
.unwrap();
|
||||
|
||||
_try_remove_delegation_from_mixnode(deps.as_mut(), env, node_identity_1, "alice_d1", None)
|
||||
.unwrap();
|
||||
|
||||
crate::delegations::transactions::_try_reconcile_all_delegation_events(
|
||||
&mut deps.storage,
|
||||
&deps.api,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
mix_0.accumulated_rewards(),
|
||||
mix_1.accumulated_rewards() + alice_reward
|
||||
);
|
||||
|
||||
let operator_reward =
|
||||
calculate_operator_reward(&deps.storage, &deps.api, &Addr::unchecked("alice"), &mix_1)
|
||||
.unwrap();
|
||||
assert_eq!(operator_reward, Uint128::new(352532));
|
||||
|
||||
assert_eq!(
|
||||
mix_1_reward_result.sigma(),
|
||||
U128::from_num(0.0000266666666666f64)
|
||||
@@ -1369,11 +1011,8 @@ pub mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
crate::delegations::transactions::_try_reconcile_all_delegation_events(
|
||||
&mut deps.storage,
|
||||
&deps.api,
|
||||
)
|
||||
.unwrap();
|
||||
crate::delegations::transactions::_try_reconcile_all_delegation_events(&mut deps.storage)
|
||||
.unwrap();
|
||||
|
||||
let info = mock_info(rewarding_validator_address.as_ref(), &[]);
|
||||
env.block.height += 2 * constants::MINIMUM_BLOCK_AGE_FOR_REWARDING;
|
||||
|
||||
@@ -334,7 +334,6 @@ fn try_create_periodic_vesting_account(
|
||||
if info.sender != ADMIN.load(deps.storage)? {
|
||||
return Err(ContractError::NotAdmin(info.sender.as_str().to_string()));
|
||||
}
|
||||
|
||||
let account_exists = account_from_address(owner_address, deps.storage, deps.api).is_ok();
|
||||
if account_exists {
|
||||
return Err(ContractError::AccountAlreadyExists(
|
||||
@@ -345,7 +344,6 @@ fn try_create_periodic_vesting_account(
|
||||
let vesting_spec = vesting_spec.unwrap_or_default();
|
||||
|
||||
let coin = validate_funds(&info.funds)?;
|
||||
|
||||
let owner_address = deps.api.addr_validate(owner_address)?;
|
||||
let staking_address = if let Some(staking_address) = staking_address {
|
||||
Some(deps.api.addr_validate(&staking_address)?)
|
||||
@@ -359,9 +357,6 @@ fn try_create_periodic_vesting_account(
|
||||
let periods = populate_vesting_periods(start_time, vesting_spec);
|
||||
|
||||
let start_time = Timestamp::from_seconds(start_time);
|
||||
|
||||
let response = Response::new();
|
||||
|
||||
Account::new(
|
||||
owner_address.clone(),
|
||||
staking_address.clone(),
|
||||
@@ -371,6 +366,24 @@ fn try_create_periodic_vesting_account(
|
||||
deps.storage,
|
||||
)?;
|
||||
|
||||
let mut response = Response::new();
|
||||
|
||||
let send_tokens_owner = BankMsg::Send {
|
||||
to_address: owner_address.as_str().to_string(),
|
||||
amount: vec![Coin::new(1_000_000, DENOM)],
|
||||
};
|
||||
|
||||
response = response.add_message(send_tokens_owner);
|
||||
|
||||
if let Some(staking_address) = staking_address.as_ref() {
|
||||
let send_tokens_staking = BankMsg::Send {
|
||||
to_address: staking_address.clone().as_str().to_string(),
|
||||
amount: vec![Coin::new(1_000_000, DENOM)],
|
||||
};
|
||||
|
||||
response = response.add_message(send_tokens_staking);
|
||||
}
|
||||
|
||||
Ok(response.add_event(new_periodic_vesting_account_event(
|
||||
&owner_address,
|
||||
&coin,
|
||||
|
||||
@@ -44,6 +44,4 @@ pub enum ContractError {
|
||||
InvalidAddress(String),
|
||||
#[error("VESTING ({}): Account already exists: {0}", line!())]
|
||||
AccountAlreadyExists(String),
|
||||
#[error("VESTING ({}): Too few coins sent for vesting account creation, sent {sent}, need at least {need}", line!())]
|
||||
MinVestingFunds { sent: u128, need: u128 },
|
||||
}
|
||||
|
||||
@@ -14,22 +14,24 @@ impl VestingAccount for Account {
|
||||
env: &Env,
|
||||
storage: &dyn Storage,
|
||||
) -> Result<Coin, ContractError> {
|
||||
// Returns 0 in case of underflow. Which is fine, as the amount of pledged and delegated tokens can be larger then vesting_coins due to rewards and vesting periods expiring
|
||||
// Returns 0 in case of underflow.
|
||||
Ok(Coin {
|
||||
amount: Uint128::new(
|
||||
self.get_vesting_coins(block_time, env)?
|
||||
.amount
|
||||
.u128()
|
||||
.saturating_sub(
|
||||
.checked_sub(
|
||||
self.get_delegated_vesting(block_time, env, storage)?
|
||||
.amount
|
||||
.u128(),
|
||||
)
|
||||
.saturating_sub(
|
||||
.ok_or(ContractError::Underflow)?
|
||||
.checked_sub(
|
||||
self.get_pledged_vesting(block_time, env, storage)?
|
||||
.amount
|
||||
.u128(),
|
||||
),
|
||||
)
|
||||
.ok_or(ContractError::Underflow)?,
|
||||
),
|
||||
denom: DENOM.to_string(),
|
||||
})
|
||||
|
||||
@@ -77,7 +77,6 @@ mod tests {
|
||||
assert_eq!(created_account_test_by_staking, created_account);
|
||||
assert_eq!(
|
||||
created_account.load_balance(&deps.storage).unwrap(),
|
||||
// One was liquidated
|
||||
Uint128::new(1_000_000_000_000)
|
||||
);
|
||||
// Try create the same account again
|
||||
|
||||
+100
-116
@@ -1,122 +1,106 @@
|
||||
version: '3.7'
|
||||
|
||||
x-network: &NETWORK
|
||||
BECH32_PREFIX: nymt
|
||||
DENOM: nymt
|
||||
STAKE_DENOM: nyxt
|
||||
WASMD_VERSION: v0.26.0
|
||||
WASMD_COMMIT_HASH: dc5ef6fe84f0a5e3b0894692a18cc48fb5b00adf
|
||||
x-bech32-prefix: &BECH32_PREFIX
|
||||
nymt
|
||||
x-wasmd-version: &WASMD_VERSION
|
||||
v0.21.0
|
||||
x-wasmd-commit-hash: &WASMD_COMMIT_HASH
|
||||
1d436638af7cacb5aeeb7248b57b085c64f3ae35
|
||||
|
||||
services:
|
||||
genesis_validator:
|
||||
build:
|
||||
context: docker/validator
|
||||
args: *NETWORK
|
||||
image: validator:latest
|
||||
ports:
|
||||
- "26657:26657"
|
||||
- "1317:1317"
|
||||
container_name: genesis_validator
|
||||
volumes:
|
||||
- "genesis_volume:/genesis_volume"
|
||||
- "genesis_nymd:/root/.nymd"
|
||||
environment: *NETWORK
|
||||
networks:
|
||||
localnet:
|
||||
ipv4_address: 172.168.10.2
|
||||
command: [ "genesis" ]
|
||||
secondary_validator:
|
||||
build:
|
||||
context: docker/validator
|
||||
args: *NETWORK
|
||||
image: validator:latest
|
||||
ports:
|
||||
- "36657:26657"
|
||||
- "2317:1317"
|
||||
volumes:
|
||||
- "genesis_volume:/genesis_volume"
|
||||
- "secondary_nymd:/root/.nymd"
|
||||
environment: *NETWORK
|
||||
networks:
|
||||
localnet:
|
||||
ipv4_address: 172.168.10.3
|
||||
depends_on:
|
||||
- "genesis_validator"
|
||||
command: [ "secondary" ]
|
||||
# mixnet_contract:
|
||||
# build: docker/mixnet_contract
|
||||
# image: contract:latest
|
||||
# volumes:
|
||||
# - ".:/nym"
|
||||
# vesting_contract:
|
||||
# build: docker/vesting_contract
|
||||
# image: vesting_contract:latest
|
||||
# volumes:
|
||||
# - ".:/nym"
|
||||
# contract_uploader:
|
||||
# build: docker/typescript_client
|
||||
# image: contract_uploader:typescript
|
||||
# volumes:
|
||||
# - "genesis_volume:/genesis_volume:ro"
|
||||
# - "contract_volume:/contract_volume"
|
||||
# - ".:/nym"
|
||||
# depends_on:
|
||||
# - "genesis_validator"
|
||||
# - "secondary_validator"
|
||||
# - "mixnet_contract"
|
||||
# environment:
|
||||
# BECH32_PREFIX: *BECH32_PREFIX
|
||||
mnemonic_echo:
|
||||
build: docker/mnemonic_echo
|
||||
image: mnemonic_echo:latest
|
||||
volumes:
|
||||
- "genesis_volume:/genesis_volume:ro"
|
||||
depends_on:
|
||||
- "genesis_validator"
|
||||
- "secondary_validator"
|
||||
genesis_validator:
|
||||
build:
|
||||
context: docker/validator
|
||||
args:
|
||||
BECH32_PREFIX: *BECH32_PREFIX
|
||||
WASMD_VERSION: *WASMD_VERSION
|
||||
WASMD_COMMIT_HASH: *WASMD_COMMIT_HASH
|
||||
image: validator:latest
|
||||
ports:
|
||||
- "26657:26657"
|
||||
- "1317:1317"
|
||||
container_name: genesis_validator
|
||||
volumes:
|
||||
- "genesis_volume:/genesis_volume"
|
||||
environment:
|
||||
BECH32_PREFIX: *BECH32_PREFIX
|
||||
WASMD_VERSION: *WASMD_VERSION
|
||||
command: ["genesis"]
|
||||
secondary_validator:
|
||||
build:
|
||||
context: docker/validator
|
||||
args:
|
||||
BECH32_PREFIX: *BECH32_PREFIX
|
||||
WASMD_VERSION: *WASMD_VERSION
|
||||
image: validator:latest
|
||||
volumes:
|
||||
- "genesis_volume:/genesis_volume:ro"
|
||||
environment:
|
||||
BECH32_PREFIX: *BECH32_PREFIX
|
||||
WASMD_VERSION: *WASMD_VERSION
|
||||
depends_on:
|
||||
- "genesis_validator"
|
||||
command: ["secondary"]
|
||||
mixnet_contract:
|
||||
build: docker/mixnet_contract
|
||||
image: contract:latest
|
||||
volumes:
|
||||
- ".:/nym"
|
||||
vesting_contract:
|
||||
build: docker/vesting_contract
|
||||
image: vesting_contract:latest
|
||||
volumes:
|
||||
- ".:/nym"
|
||||
contract_uploader:
|
||||
build: docker/typescript_client
|
||||
image: contract_uploader:typescript
|
||||
volumes:
|
||||
- "genesis_volume:/genesis_volume:ro"
|
||||
- "contract_volume:/contract_volume"
|
||||
- ".:/nym"
|
||||
depends_on:
|
||||
- "genesis_validator"
|
||||
- "secondary_validator"
|
||||
- "mixnet_contract"
|
||||
environment:
|
||||
BECH32_PREFIX: *BECH32_PREFIX
|
||||
mnemonic_echo:
|
||||
build: docker/mnemonic_echo
|
||||
image: mnemonic_echo:latest
|
||||
volumes:
|
||||
- "genesis_volume:/genesis_volume:ro"
|
||||
depends_on:
|
||||
- "genesis_validator"
|
||||
|
||||
# mongo:
|
||||
# image: mongo:latest
|
||||
# command:
|
||||
# - --storageEngine=wiredTiger
|
||||
# volumes:
|
||||
# - mongo_data:/data/db
|
||||
# block_explorer:
|
||||
# build:
|
||||
# context: https://github.com/forbole/big-dipper.git#v0.41.x-7
|
||||
# image: block_explorer:v0.41.x-7
|
||||
# ports:
|
||||
# - "3080:3000"
|
||||
# depends_on:
|
||||
# - "mongo"
|
||||
# environment:
|
||||
# ROOT_URL: ${APP_ROOT_URL:-http://localhost}
|
||||
# MONGO_URL: mongodb://mongo:27017/meteor
|
||||
# PORT: 3000
|
||||
# METEOR_SETTINGS: ${METEOR_SETTINGS}
|
||||
# explorer:
|
||||
# build:
|
||||
# context: docker/explorer
|
||||
# image: explorer:latest
|
||||
# ports:
|
||||
# - "3040:3000"
|
||||
# depends_on:
|
||||
# - "genesis_validator"
|
||||
# - "block_explorer"
|
||||
mongo:
|
||||
image: mongo:latest
|
||||
command:
|
||||
- --storageEngine=wiredTiger
|
||||
volumes:
|
||||
- mongo_data:/data/db
|
||||
block_explorer:
|
||||
build:
|
||||
context: https://github.com/forbole/big-dipper.git#v0.41.x-7
|
||||
image: block_explorer:v0.41.x-7
|
||||
ports:
|
||||
- "3080:3000"
|
||||
depends_on:
|
||||
- "mongo"
|
||||
environment:
|
||||
ROOT_URL: ${APP_ROOT_URL:-http://localhost}
|
||||
MONGO_URL: mongodb://mongo:27017/meteor
|
||||
PORT: 3000
|
||||
METEOR_SETTINGS: ${METEOR_SETTINGS}
|
||||
explorer:
|
||||
build:
|
||||
context: docker/explorer
|
||||
image: explorer:latest
|
||||
ports:
|
||||
- "3040:3000"
|
||||
depends_on:
|
||||
- "genesis_validator"
|
||||
- "block_explorer"
|
||||
|
||||
volumes:
|
||||
genesis_volume:
|
||||
genesis_nymd:
|
||||
secondary_nymd:
|
||||
|
||||
# contract_volume:
|
||||
# mongo_data:
|
||||
|
||||
|
||||
networks:
|
||||
localnet:
|
||||
driver: bridge
|
||||
ipam:
|
||||
driver: default
|
||||
config:
|
||||
- subnet: 172.168.10.0/25
|
||||
genesis_volume:
|
||||
contract_volume:
|
||||
mongo_data:
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Wait for the mnemonic(s) to be generated
|
||||
# Wait for the mnemonic to be generated
|
||||
while ! [ -s /genesis_volume/genesis_mnemonic ]; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
while ! [ -s /genesis_volume/secondary_mnemonic ]; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "This is the current genesis mnemonic:"
|
||||
echo "This is the current mnemonic:"
|
||||
cat /genesis_volume/genesis_mnemonic
|
||||
|
||||
echo "This is the current secondary mnemonic:"
|
||||
cat /genesis_volume/secondary_mnemonic
|
||||
|
||||
@@ -6,29 +6,17 @@ PASSPHRASE=passphrase
|
||||
cd /root
|
||||
|
||||
if [ "$1" = "genesis" ]; then
|
||||
if [ ! -f "/root/.nymd/config/genesis.json" ]; then
|
||||
if [ ! -d "/root/.nymd" ]; then
|
||||
./nymd init nymnet --chain-id nymnet 2> /dev/null
|
||||
# staking/governance token is hardcoded in config, change this
|
||||
sed -i "s/\"stake\"/\"u${STAKE_DENOM}\"/" /root/.nymd/config/genesis.json
|
||||
sed -i 's/minimum-gas-prices = ""/minimum-gas-prices = "0.025u'"${DENOM}"'"/' /root/.nymd/config/app.toml
|
||||
sed -i 's/minimum-gas-prices = ""/minimum-gas-prices = "0.025u'"${BECH32_PREFIX}"'"/' /root/.nymd/config/app.toml
|
||||
sed -i '0,/enable = false/s//enable = true/g' /root/.nymd/config/app.toml
|
||||
sed -i 's/cors_allowed_origins = \[\]/cors_allowed_origins = \["*"\]/' /root/.nymd/config/config.toml
|
||||
sed -i 's/create_empty_blocks = true/create_empty_blocks = false/' /root/.nymd/config/config.toml
|
||||
sed -i 's/laddr = "tcp:\/\/127.0.0.1:26657"/laddr = "tcp:\/\/0.0.0.0:26657"/' /root/.nymd/config/config.toml
|
||||
|
||||
# create accounts
|
||||
yes "${PASSPHRASE}" | ./nymd keys add node_admin 2>&1 >/dev/null | tail -n 1 > /root/.nymd/mnemonic
|
||||
yes "${PASSPHRASE}" | ./nymd keys add secondary 2>&1 >/dev/null | tail -n 1 > /root/.nymd/secondary_mnemonic
|
||||
cp /root/.nymd/mnemonic /genesis_volume/genesis_mnemonic
|
||||
cp /root/.nymd/secondary_mnemonic /genesis_volume/secondary_mnemonic
|
||||
|
||||
# add genesis accounts with some initial tokens
|
||||
GENESIS_ADDRESS=$(yes "${PASSPHRASE}" | ./nymd keys show node_admin -a)
|
||||
SECONDARY_ADDRESS=$(yes "${PASSPHRASE}" | ./nymd keys show secondary -a)
|
||||
yes "${PASSPHRASE}" | ./nymd add-genesis-account "${GENESIS_ADDRESS}" 1000000000000000u"${DENOM}",1000000000000000u"${STAKE_DENOM}"
|
||||
yes "${PASSPHRASE}" | ./nymd add-genesis-account "${SECONDARY_ADDRESS}" 1000000000000000u"${DENOM}",1000000000000000u"${STAKE_DENOM}"
|
||||
|
||||
yes "${PASSPHRASE}" | ./nymd gentx node_admin 1000000000u"${STAKE_DENOM}" --chain-id nymnet 2> /dev/null
|
||||
yes "${PASSPHRASE}" | ./nymd keys add node_admin 2>&1 >/dev/null | tail -n 1 > /genesis_volume/genesis_mnemonic
|
||||
ADDRESS=$(yes "${PASSPHRASE}" | ./nymd keys show node_admin -a)
|
||||
yes "${PASSPHRASE}" | ./nymd add-genesis-account "${ADDRESS}" 1000000000000000u${BECH32_PREFIX},1000000000000000stake
|
||||
yes "${PASSPHRASE}" | ./nymd gentx node_admin 1000000000stake --chain-id nymnet 2> /dev/null
|
||||
./nymd collect-gentxs 2> /dev/null
|
||||
./nymd validate-genesis > /dev/null
|
||||
cp /root/.nymd/config/genesis.json /genesis_volume/genesis.json
|
||||
@@ -38,7 +26,7 @@ if [ "$1" = "genesis" ]; then
|
||||
fi
|
||||
./nymd start
|
||||
elif [ "$1" = "secondary" ]; then
|
||||
if [ ! -f "/root/.nymd/config/genesis.json" ]; then
|
||||
if [ ! -d "/root/.nymd" ]; then
|
||||
./nymd init nymnet --chain-id nym-secondary 2> /dev/null
|
||||
|
||||
# Wait until the genesis node writes the genesis.json to the shared volume
|
||||
@@ -46,27 +34,16 @@ elif [ "$1" = "secondary" ]; then
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# wait for the actual validator to start up
|
||||
sleep 5
|
||||
|
||||
cp /genesis_volume/genesis.json /root/.nymd/config/genesis.json
|
||||
GENESIS_PEER=$(cat /root/.nymd/config/genesis.json | grep '"memo"' | cut -d'"' -f 4)
|
||||
GENESIS_IP=$(cat /root/.nymd/config/genesis.json | grep '"memo"' | cut -d'@' -f2 | cut -d: -f1)
|
||||
sed -i 's/persistent_peers = ""/persistent_peers = "'"${GENESIS_PEER}"'"/' /root/.nymd/config/config.toml
|
||||
sed -i 's/minimum-gas-prices = ""/minimum-gas-prices = "0.025u'"${BECH32_PREFIX}"'"/' /root/.nymd/config/app.toml
|
||||
sed -i '0,/enable = false/s//enable = true/g' /root/.nymd/config/app.toml
|
||||
sed -i 's/cors_allowed_origins = \[\]/cors_allowed_origins = \["*"\]/' /root/.nymd/config/config.toml
|
||||
sed -i 's/create_empty_blocks = true/create_empty_blocks = false/' /root/.nymd/config/config.toml
|
||||
sed -i 's/laddr = "tcp:\/\/127.0.0.1:26657"/laddr = "tcp:\/\/0.0.0.0:26657"/' /root/.nymd/config/config.toml
|
||||
|
||||
# import mnemonic generated by the genesis validator (have a local copy for ease of use)
|
||||
cp /genesis_volume/secondary_mnemonic /root/.nymd/mnemonic
|
||||
{ cat /root/.nymd/mnemonic; echo "${PASSPHRASE}"; echo "${PASSPHRASE}"; } | ./nymd keys add node_admin --recover #> /dev/null
|
||||
yes "${PASSPHRASE}" | ./nymd keys add node_admin 2> mnemonic > /dev/null
|
||||
./nymd validate-genesis > /dev/null
|
||||
|
||||
# create validator
|
||||
# don't even ask about those sleeps...
|
||||
{ echo "${PASSPHRASE}"; sleep 10; yes; sleep 10; } | ./nymd tx staking create-validator --amount=10000000u"${STAKE_DENOM}" --fees 100000u"${DENOM}" --pubkey="$(./nymd tendermint show-validator)" --moniker="secondary" --commission-rate="0.10" --commission-max-rate="0.20" --commission-max-change-rate="0.01" --min-self-delegation="1" --chain-id=nymnet --from=node_admin -b async --node http://"${GENESIS_IP}":26657
|
||||
else
|
||||
echo "Validator already initialized, starting with the existing configuration."
|
||||
echo "If you want to re-init the validator, destroy the existing container"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "explorer-api"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0-rc.2"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -28,7 +28,6 @@ pub(crate) struct PrettyDetailedMixNodeBond {
|
||||
pub owner: Addr,
|
||||
pub layer: Layer,
|
||||
pub mix_node: MixNode,
|
||||
pub avg_uptime: Option<u8>,
|
||||
}
|
||||
|
||||
pub(crate) struct MixNodeCache {
|
||||
|
||||
@@ -9,9 +9,7 @@ use serde::Serialize;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use mixnet_contract_common::MixNodeBond;
|
||||
use validator_client::models::UptimeResponse;
|
||||
|
||||
use crate::cache::Cache;
|
||||
use crate::mix_node::models::{MixnodeStatus, PrettyDetailedMixNodeBond};
|
||||
use crate::mix_nodes::location::{Location, LocationCache, LocationCacheItem};
|
||||
use crate::mix_nodes::CACHE_ENTRY_TTL;
|
||||
@@ -78,16 +76,10 @@ impl MixNodesResult {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct MixNodeHealth {
|
||||
avg_uptime: u8,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct ThreadsafeMixNodesCache {
|
||||
mixnodes: Arc<RwLock<MixNodesResult>>,
|
||||
locations: Arc<RwLock<LocationCache>>,
|
||||
mixnode_health: Arc<RwLock<Cache<MixNodeHealth>>>,
|
||||
}
|
||||
|
||||
impl ThreadsafeMixNodesCache {
|
||||
@@ -95,7 +87,6 @@ impl ThreadsafeMixNodesCache {
|
||||
ThreadsafeMixNodesCache {
|
||||
mixnodes: Arc::new(RwLock::new(MixNodesResult::new())),
|
||||
locations: Arc::new(RwLock::new(LocationCache::new())),
|
||||
mixnode_health: Arc::new(RwLock::new(Cache::new())),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +94,6 @@ impl ThreadsafeMixNodesCache {
|
||||
ThreadsafeMixNodesCache {
|
||||
mixnodes: Arc::new(RwLock::new(MixNodesResult::new())),
|
||||
locations: Arc::new(RwLock::new(locations)),
|
||||
mixnode_health: Arc::new(RwLock::new(Cache::new())),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,11 +132,9 @@ impl ThreadsafeMixNodesCache {
|
||||
) -> Option<PrettyDetailedMixNodeBond> {
|
||||
let mixnodes_guard = self.mixnodes.read().await;
|
||||
let location_guard = self.locations.read().await;
|
||||
let mixnode_health_guard = self.mixnode_health.read().await;
|
||||
|
||||
let bond = mixnodes_guard.get_mixnode(identity_key);
|
||||
let location = location_guard.get(identity_key);
|
||||
let health = mixnode_health_guard.get(identity_key);
|
||||
|
||||
match bond {
|
||||
Some(bond) => Some(PrettyDetailedMixNodeBond {
|
||||
@@ -157,7 +145,6 @@ impl ThreadsafeMixNodesCache {
|
||||
owner: bond.owner,
|
||||
layer: bond.layer,
|
||||
mix_node: bond.mix_node,
|
||||
avg_uptime: health.map(|m| m.avg_uptime),
|
||||
}),
|
||||
None => None,
|
||||
}
|
||||
@@ -166,7 +153,6 @@ impl ThreadsafeMixNodesCache {
|
||||
pub(crate) async fn get_detailed_mixnodes(&self) -> Vec<PrettyDetailedMixNodeBond> {
|
||||
let mixnodes_guard = self.mixnodes.read().await;
|
||||
let location_guard = self.locations.read().await;
|
||||
let mixnode_health_guard = self.mixnode_health.read().await;
|
||||
|
||||
mixnodes_guard
|
||||
.all_mixnodes
|
||||
@@ -174,7 +160,6 @@ impl ThreadsafeMixNodesCache {
|
||||
.map(|bond| {
|
||||
let location = location_guard.get(&bond.mix_node.identity_key);
|
||||
let copy = bond.clone();
|
||||
let health = mixnode_health_guard.get(&bond.mix_node.identity_key);
|
||||
PrettyDetailedMixNodeBond {
|
||||
location: location.and_then(|l| l.location.clone()),
|
||||
status: mixnodes_guard.determine_node_status(&bond.mix_node.identity_key),
|
||||
@@ -183,7 +168,6 @@ impl ThreadsafeMixNodesCache {
|
||||
owner: copy.owner,
|
||||
layer: copy.layer,
|
||||
mix_node: copy.mix_node,
|
||||
avg_uptime: health.map(|m| m.avg_uptime),
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
@@ -204,14 +188,4 @@ impl ThreadsafeMixNodesCache {
|
||||
guard.active_mixnodes = active_nodes;
|
||||
guard.valid_until = SystemTime::now() + CACHE_ENTRY_TTL;
|
||||
}
|
||||
|
||||
pub(crate) async fn update_health_cache(&self, all_uptimes: Vec<UptimeResponse>) {
|
||||
let mut mixnode_health = self.mixnode_health.write().await;
|
||||
for uptime in all_uptimes {
|
||||
let health = MixNodeHealth {
|
||||
avg_uptime: uptime.avg_uptime,
|
||||
};
|
||||
mixnode_health.set(&uptime.identity, health);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
use std::future::Future;
|
||||
|
||||
use mixnet_contract_common::{GatewayBond, MixNodeBond};
|
||||
use validator_client::models::UptimeResponse;
|
||||
use validator_client::nymd::error::NymdError;
|
||||
use validator_client::nymd::{Paging, QueryNymdClient, ValidatorResponse};
|
||||
use validator_client::ValidatorClientError;
|
||||
@@ -89,17 +88,6 @@ impl ExplorerApiTasks {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn retrieve_all_mixnode_avg_uptimes(
|
||||
&self,
|
||||
) -> Result<Vec<UptimeResponse>, ValidatorClientError> {
|
||||
self.state
|
||||
.inner
|
||||
.validator_client
|
||||
.0
|
||||
.get_mixnode_avg_uptimes()
|
||||
.await
|
||||
}
|
||||
|
||||
async fn update_mixnode_cache(&self) {
|
||||
let all_bonds = self.retrieve_all_mixnodes().await;
|
||||
let rewarded_nodes = self
|
||||
@@ -121,21 +109,6 @@ impl ExplorerApiTasks {
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn update_mixnode_health_cache(&self) {
|
||||
match self.retrieve_all_mixnode_avg_uptimes().await {
|
||||
Ok(response) => {
|
||||
self.state
|
||||
.inner
|
||||
.mixnodes
|
||||
.update_health_cache(response)
|
||||
.await
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to get mixnode avg uptimes: {:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn update_validators_cache(&self) {
|
||||
match self.retrieve_all_validators().await {
|
||||
Ok(response) => self.state.inner.validators.update_cache(response).await,
|
||||
@@ -172,9 +145,6 @@ impl ExplorerApiTasks {
|
||||
|
||||
info!("Updating mix node cache...");
|
||||
self.update_mixnode_cache().await;
|
||||
|
||||
info!("Updating mix node health cache...");
|
||||
self.update_mixnode_health_cache().await;
|
||||
info!("Done");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
module.exports = {
|
||||
extends: [
|
||||
'@nymproject/eslint-config-react-typescript'
|
||||
],
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.ts'],
|
||||
parserOptions: {
|
||||
project: 'tsconfig.json',
|
||||
tsconfigRootDir: __dirname,
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": [
|
||||
"@nymproject/eslint-config-react-typescript"
|
||||
]
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
||||
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
|
||||
addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-interactions'],
|
||||
framework: '@storybook/react',
|
||||
core: {
|
||||
builder: 'webpack5',
|
||||
},
|
||||
// webpackFinal: async (config, { configType }) => {
|
||||
// // `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
|
||||
// // You can change the configuration based on that.
|
||||
// // 'PRODUCTION' is used when building the static version of storybook.
|
||||
webpackFinal: async (config) => {
|
||||
config.module.rules.forEach((rule) => {
|
||||
// look for SVG import rule and replace
|
||||
// NOTE: the rule before modification is /\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/
|
||||
if (rule.test?.toString().includes('svg')) {
|
||||
rule.test = /\.(ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/;
|
||||
}
|
||||
});
|
||||
|
||||
// handle asset loading with this
|
||||
config.module.rules.unshift({
|
||||
test: /\.svg(\?.*)?$/i,
|
||||
issuer: /\.[jt]sx?$/,
|
||||
use: ['@svgr/webpack'],
|
||||
});
|
||||
|
||||
config.resolve.extensions = ['.tsx', '.ts', '.js'];
|
||||
config.resolve.plugins = [new TsconfigPathsPlugin()];
|
||||
|
||||
config.resolve.fallback = {
|
||||
fs: false,
|
||||
tls: false,
|
||||
path: false,
|
||||
http: false,
|
||||
https: false,
|
||||
stream: false,
|
||||
crypto: false,
|
||||
net: false,
|
||||
zlib: false,
|
||||
};
|
||||
|
||||
config.plugins.push(new ForkTsCheckerWebpackPlugin({
|
||||
typescript: {
|
||||
mode: 'write-references',
|
||||
diagnosticOptions: {
|
||||
semantic: true,
|
||||
syntactic: true,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
// Return the altered config
|
||||
return config;
|
||||
},
|
||||
features: {
|
||||
emotionAlias: false,
|
||||
},
|
||||
};
|
||||
@@ -1,56 +0,0 @@
|
||||
/* eslint-disable react/react-in-jsx-scope */
|
||||
import { NymNetworkExplorerThemeProvider } from '@nymproject/mui-theme';
|
||||
import { Box } from '@mui/material';
|
||||
|
||||
export const parameters = {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const withThemeProvider = (Story, context) => (
|
||||
<div style={{ display: 'grid', height: '100%', gridTemplateColumns: '50% 50%' }}>
|
||||
<div>
|
||||
<NymNetworkExplorerThemeProvider mode="light">
|
||||
<Box
|
||||
p={4}
|
||||
sx={{
|
||||
display: 'grid',
|
||||
gridTemplateRows: '80vh 2rem',
|
||||
background: (theme) => theme.palette.background.default,
|
||||
color: (theme) => theme.palette.text.primary,
|
||||
}}
|
||||
>
|
||||
<Box sx={{ overflowY: 'auto' }}>
|
||||
<Story {...context} />
|
||||
</Box>
|
||||
<h4 style={{ textAlign: 'center' }}>Light mode</h4>
|
||||
</Box>
|
||||
</NymNetworkExplorerThemeProvider>
|
||||
</div>
|
||||
<div>
|
||||
<NymNetworkExplorerThemeProvider mode="dark">
|
||||
<Box
|
||||
p={4}
|
||||
sx={{
|
||||
display: 'grid',
|
||||
gridTemplateRows: '80vh 2rem',
|
||||
background: (theme) => theme.palette.background.default,
|
||||
color: (theme) => theme.palette.text.primary,
|
||||
}}
|
||||
>
|
||||
<Box sx={{ overflowY: 'auto' }}>
|
||||
<Story {...context} />
|
||||
</Box>
|
||||
<h4 style={{ textAlign: 'center' }}>Dark mode</h4>
|
||||
</Box>
|
||||
</NymNetworkExplorerThemeProvider>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const decorators = [withThemeProvider];
|
||||
+3
-13
@@ -30,15 +30,8 @@
|
||||
"use-clipboard-copy": "^0.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.0",
|
||||
"@nymproject/eslint-config-react-typescript": "^1.0.0",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.4",
|
||||
"@storybook/addon-actions": "^6.4.19",
|
||||
"@storybook/addon-essentials": "^6.4.19",
|
||||
"@storybook/addon-interactions": "^6.4.19",
|
||||
"@storybook/addon-links": "^6.4.19",
|
||||
"@storybook/react": "^6.4.19",
|
||||
"@storybook/testing-library": "^0.0.9",
|
||||
"@svgr/webpack": "^6.1.1",
|
||||
"@testing-library/jest-dom": "^5.14.1",
|
||||
"@testing-library/react": "^12.0.0",
|
||||
@@ -102,13 +95,10 @@
|
||||
"build:serve": "npx serve dist",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"tsc": "tsc --noEmit true",
|
||||
"tsc:watch": "tsc --watch --noEmit true",
|
||||
"tsc": "tsc",
|
||||
"tsc:watch": "tsc --watch",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"prestorybook": "yarn --cwd .. build",
|
||||
"storybook": "start-storybook -p 6006",
|
||||
"storybook:build": "build-storybook"
|
||||
"lint:fix": "eslint src --fix"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
||||
@@ -18,7 +18,6 @@ import {
|
||||
MixNodeResponse,
|
||||
MixNodeResponseItem,
|
||||
MixnodeStatus,
|
||||
MixNodeEconomicDynamicsStatsResponse,
|
||||
StatsResponse,
|
||||
StatusResponse,
|
||||
SummaryOverviewResponse,
|
||||
@@ -123,9 +122,6 @@ export class Api {
|
||||
static fetchMixnodeDescriptionById = async (id: string): Promise<MixNodeDescriptionResponse> =>
|
||||
(await fetch(`${MIXNODE_API}/${id}/description`)).json();
|
||||
|
||||
static fetchMixnodeEconomicDynamicsStatsById = async (id: string): Promise<MixNodeEconomicDynamicsStatsResponse> =>
|
||||
(await fetch(`${MIXNODE_API}/${id}/economic-dynamics-stats`)).json();
|
||||
|
||||
static fetchStatusById = async (id: string): Promise<StatusResponse> => (await fetch(`${MIXNODE_PING}/${id}`)).json();
|
||||
|
||||
static fetchUptimeStoryById = async (id: string): Promise<UptimeStoryResponse> =>
|
||||
|
||||
@@ -12,13 +12,12 @@ export type ColumnsType = {
|
||||
headerAlign: string;
|
||||
flex?: number;
|
||||
width?: number;
|
||||
tooltipInfo?: string;
|
||||
};
|
||||
|
||||
export interface UniversalTableProps<T = any> {
|
||||
export interface UniversalTableProps {
|
||||
tableName: string;
|
||||
columnsData: ColumnsType[];
|
||||
rows: T[];
|
||||
rows: any[];
|
||||
}
|
||||
|
||||
function formatCellValues(val: string | number, field: string) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { Alert, Box, CircularProgress, useMediaQuery, Typography } from '@mui/material';
|
||||
import { Alert, Box, CircularProgress, useMediaQuery } from '@mui/material';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import Table from '@mui/material/Table';
|
||||
import TableBody from '@mui/material/TableBody';
|
||||
@@ -98,7 +98,7 @@ export const BondBreakdownTable: React.FC = () => {
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell align="left">Self</TableCell>
|
||||
<TableCell align="left">Pledge total</TableCell>
|
||||
<TableCell align="left" data-testid="pledge-total-amount">
|
||||
{bonds.pledges}
|
||||
</TableCell>
|
||||
@@ -127,62 +127,21 @@ export const BondBreakdownTable: React.FC = () => {
|
||||
sx={{
|
||||
maxHeight: 400,
|
||||
overflowY: 'scroll',
|
||||
p: 2,
|
||||
background: theme.palette.background.paper,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'baseline',
|
||||
width: '100%',
|
||||
p: 2,
|
||||
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||
}}
|
||||
data-testid="delegations-total-amount"
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: 16,
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
Delegations
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: 12,
|
||||
fontWeight: 400,
|
||||
}}
|
||||
>
|
||||
{`(${delegations?.data?.length} delegators)`}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Table stickyHeader>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell
|
||||
sx={{
|
||||
fontWeight: 600,
|
||||
background: theme.palette.background.paper,
|
||||
}}
|
||||
align="left"
|
||||
>
|
||||
<TableCell sx={{ fontWeight: 600, background: '#242C3D' }} align="left">
|
||||
Delegators
|
||||
</TableCell>
|
||||
<TableCell
|
||||
sx={{
|
||||
fontWeight: 600,
|
||||
background: theme.palette.background.paper,
|
||||
}}
|
||||
align="left"
|
||||
>
|
||||
<TableCell sx={{ fontWeight: 600, background: '#242C3D' }} align="left">
|
||||
Stake
|
||||
</TableCell>
|
||||
<TableCell
|
||||
sx={{
|
||||
fontWeight: 600,
|
||||
background: theme.palette.background.paper,
|
||||
background: '#242C3D',
|
||||
width: '200px',
|
||||
}}
|
||||
align="left"
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import { ColumnsType } from '../../DetailTable';
|
||||
|
||||
export const EconomicsInfoColumns: ColumnsType[] = [
|
||||
{
|
||||
field: 'estimatedTotalReward',
|
||||
title: 'Estimated Total Reward',
|
||||
flex: 1,
|
||||
headerAlign: 'left',
|
||||
tooltipInfo: 'Estimated reward per epoch for this profit margin if your node is selected in the active set.',
|
||||
},
|
||||
{
|
||||
field: 'estimatedOperatorReward',
|
||||
title: 'Estimated Operator Reward',
|
||||
flex: 1,
|
||||
headerAlign: 'left',
|
||||
tooltipInfo: 'Estimated reward per epoch for this profit margin if your node is selected in the active set.',
|
||||
},
|
||||
{
|
||||
field: 'selectionChance',
|
||||
title: 'Active Set Probability',
|
||||
flex: 1,
|
||||
headerAlign: 'left',
|
||||
tooltipInfo:
|
||||
'Probability of getting selected in the reward set (active and standby nodes) in the next epoch. The more your stake, the higher the chances to be selected.',
|
||||
},
|
||||
{
|
||||
field: 'stakeSaturation',
|
||||
title: 'Stake Saturation',
|
||||
flex: 1,
|
||||
headerAlign: 'left',
|
||||
tooltipInfo:
|
||||
'Level of stake saturation for this node. Nodes receive more rewards the higher their saturation level, up to 100%. Beyond 100% no additional rewards are granted. The current stake saturation level is: 1 million NYM, computed as S/K where S is total amount of tokens available to stakeholders and K is the number of nodes in the reward set.',
|
||||
},
|
||||
{
|
||||
field: 'profitMargin',
|
||||
title: 'Profit Margin',
|
||||
flex: 1,
|
||||
headerAlign: 'left',
|
||||
tooltipInfo:
|
||||
'Percentage of the delegates rewards that the operator takes as fee before rewards are distributed to the delegates.',
|
||||
},
|
||||
{
|
||||
field: 'avgUptime',
|
||||
title: 'Avg. Uptime',
|
||||
flex: 1,
|
||||
headerAlign: 'left',
|
||||
tooltipInfo: 'Node’s average uptime in the last 24h.',
|
||||
},
|
||||
];
|
||||
@@ -1,31 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { ComponentMeta, ComponentStory } from '@storybook/react';
|
||||
import { EconomicsProgress } from './EconomicsProgress';
|
||||
|
||||
export default {
|
||||
title: 'Mix Node Detail/Economics/ProgressBar',
|
||||
component: EconomicsProgress,
|
||||
} as ComponentMeta<typeof EconomicsProgress>;
|
||||
|
||||
const Template: ComponentStory<typeof EconomicsProgress> = (args) => <EconomicsProgress {...args} />;
|
||||
|
||||
export const Empty = Template.bind({});
|
||||
Empty.args = {};
|
||||
|
||||
export const OverThreshold = Template.bind({});
|
||||
OverThreshold.args = {
|
||||
threshold: 100,
|
||||
value: 120,
|
||||
};
|
||||
|
||||
export const UnderThreshold = Template.bind({});
|
||||
UnderThreshold.args = {
|
||||
threshold: 100,
|
||||
value: 80,
|
||||
};
|
||||
|
||||
export const OnThreshold = Template.bind({});
|
||||
OnThreshold.args = {
|
||||
threshold: 100,
|
||||
value: 100,
|
||||
};
|
||||
@@ -1,38 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import LinearProgress, { LinearProgressProps } from '@mui/material/LinearProgress';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { Box } from '@mui/system';
|
||||
|
||||
const parseToNumber = (value: number | undefined | string) =>
|
||||
typeof value === 'string' ? parseInt(value || '', 10) : value || 0;
|
||||
|
||||
export const EconomicsProgress: React.FC<
|
||||
LinearProgressProps & {
|
||||
threshold?: number;
|
||||
}
|
||||
> = ({ threshold, ...props }) => {
|
||||
const theme = useTheme();
|
||||
const { value } = props;
|
||||
|
||||
const valueNumber: number = parseToNumber(value);
|
||||
const thresholdNumber: number = parseToNumber(threshold);
|
||||
const percentageColor = valueNumber > (threshold || 100) ? 'warning' : 'inherit';
|
||||
const percentageToDisplay = Math.min(valueNumber, thresholdNumber);
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
width: 6 / 10,
|
||||
color: valueNumber > (threshold || 100) ? theme.palette.warning.main : theme.palette.nym.wallet.fee,
|
||||
}}
|
||||
>
|
||||
<LinearProgress
|
||||
{...props}
|
||||
variant="determinate"
|
||||
color={percentageColor}
|
||||
value={percentageToDisplay}
|
||||
sx={{ width: '100%', borderRadius: '5px', backgroundColor: theme.palette.common.white }}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -1,129 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { ComponentMeta, ComponentStory } from '@storybook/react';
|
||||
import { DelegatorsInfoTable } from './Table';
|
||||
import { EconomicsInfoColumns } from './Columns';
|
||||
import { EconomicsInfoRowWithIndex } from './types';
|
||||
|
||||
export default {
|
||||
title: 'Mix Node Detail/Economics',
|
||||
component: DelegatorsInfoTable,
|
||||
} as ComponentMeta<typeof DelegatorsInfoTable>;
|
||||
|
||||
const row: EconomicsInfoRowWithIndex = {
|
||||
id: 1,
|
||||
selectionChance: {
|
||||
value: 'High',
|
||||
},
|
||||
avgUptime: {
|
||||
value: '65 %',
|
||||
},
|
||||
estimatedOperatorReward: {
|
||||
value: '80000.123456 NYM',
|
||||
},
|
||||
estimatedTotalReward: {
|
||||
value: '80000.123456 NYM',
|
||||
},
|
||||
profitMargin: {
|
||||
value: '10 %',
|
||||
},
|
||||
stakeSaturation: {
|
||||
value: '80 %',
|
||||
progressBarValue: 80,
|
||||
},
|
||||
};
|
||||
|
||||
const rowVeryHighProbabilitySelection: EconomicsInfoRowWithIndex = {
|
||||
...row,
|
||||
selectionChance: {
|
||||
value: 'Very High',
|
||||
},
|
||||
};
|
||||
|
||||
const rowModerateProbabilitySelection: EconomicsInfoRowWithIndex = {
|
||||
...row,
|
||||
selectionChance: {
|
||||
value: 'Moderate',
|
||||
},
|
||||
};
|
||||
|
||||
const rowLowProbabilitySelection: EconomicsInfoRowWithIndex = {
|
||||
...row,
|
||||
selectionChance: {
|
||||
value: 'Low',
|
||||
},
|
||||
};
|
||||
|
||||
const rowVeryLowProbabilitySelection: EconomicsInfoRowWithIndex = {
|
||||
...row,
|
||||
selectionChance: {
|
||||
value: 'Very Low',
|
||||
},
|
||||
};
|
||||
|
||||
const emptyRow: EconomicsInfoRowWithIndex = {
|
||||
id: 1,
|
||||
selectionChance: {
|
||||
value: '-',
|
||||
progressBarValue: 0,
|
||||
},
|
||||
avgUptime: {
|
||||
value: '-',
|
||||
},
|
||||
estimatedOperatorReward: {
|
||||
value: '-',
|
||||
},
|
||||
estimatedTotalReward: {
|
||||
value: '-',
|
||||
},
|
||||
profitMargin: {
|
||||
value: '-',
|
||||
},
|
||||
stakeSaturation: {
|
||||
value: '-',
|
||||
progressBarValue: 0,
|
||||
},
|
||||
};
|
||||
|
||||
const Template: ComponentStory<typeof DelegatorsInfoTable> = (args) => <DelegatorsInfoTable {...args} />;
|
||||
|
||||
export const Empty = Template.bind({});
|
||||
Empty.args = {
|
||||
rows: [emptyRow],
|
||||
columnsData: EconomicsInfoColumns,
|
||||
tableName: 'storybook',
|
||||
};
|
||||
|
||||
export const selectionChanceVeryHigh = Template.bind({});
|
||||
selectionChanceVeryHigh.args = {
|
||||
rows: [rowVeryHighProbabilitySelection],
|
||||
columnsData: EconomicsInfoColumns,
|
||||
tableName: 'storybook',
|
||||
};
|
||||
|
||||
export const selectionChanceHigh = Template.bind({});
|
||||
selectionChanceHigh.args = {
|
||||
rows: [row],
|
||||
columnsData: EconomicsInfoColumns,
|
||||
tableName: 'storybook',
|
||||
};
|
||||
|
||||
export const selectionChanceModerate = Template.bind({});
|
||||
selectionChanceModerate.args = {
|
||||
rows: [rowModerateProbabilitySelection],
|
||||
columnsData: EconomicsInfoColumns,
|
||||
tableName: 'storybook',
|
||||
};
|
||||
|
||||
export const selectionChanceLow = Template.bind({});
|
||||
selectionChanceLow.args = {
|
||||
rows: [rowLowProbabilitySelection],
|
||||
columnsData: EconomicsInfoColumns,
|
||||
tableName: 'storybook',
|
||||
};
|
||||
|
||||
export const selectionChanceVeryLow = Template.bind({});
|
||||
selectionChanceVeryLow.args = {
|
||||
rows: [rowVeryLowProbabilitySelection],
|
||||
columnsData: EconomicsInfoColumns,
|
||||
tableName: 'storybook',
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user