Compare commits

..

2 Commits

Author SHA1 Message Date
tommy 8f5dd00027 minor changes 2022-08-04 13:41:53 +02:00
tommy 84c43ebf54 Draft - Validator CLI
- validator  binary - to enable easy to use commands on the network
- contains all operations (vesting / normal)
2022-08-04 13:38:59 +02:00
348 changed files with 4325 additions and 20957 deletions
-36
View File
@@ -1,36 +0,0 @@
name: Daily security audit
on: workflow_dispatch
jobs:
security_audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions-rs/audit-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
notification:
if: ${{ failure() }}
needs: security_audit
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v2
- name: Keybase - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Keybase - Send Notification
env:
NYM_NOTIFICATION_KIND: nightly
NYM_PROJECT_NAME: "Nym daily audit"
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBTECH_TEAM }}"
KEYBASE_NYM_CHANNEL: "test"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
@@ -166,8 +166,8 @@ jobs:
GIT_BRANCH: "${GITHUB_REF##*/}"
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMTECH_TEAM }}"
KEYBASE_NYM_CHANNEL: "test"
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
KEYBASE_NYM_CHANNEL: "ci-nightly"
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
uses: docker://keybaseio/client:stable-node
with:
-50
View File
@@ -1,50 +0,0 @@
name: Publish Nym CLI binaries
on:
workflow_dispatch:
release:
types: [created]
env:
NETWORK: mainnet
jobs:
publish-nym-cli:
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v3
- name: Check the release tag starts with `nym-cli-`
if: startsWith(github.ref, 'refs/tags/nym-cli-') == false && github.event_name != 'workflow_dispatch'
uses: actions/github-script@v3
with:
script: |
core.setFailed('Release tag did not start with nym-cli-...')
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Build binary
run: make build-nym-cli
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: nym-cli-${{ matrix.platform }}
path: |
target/release/nym-cli*
retention-days: 30
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
target/release/nym-cli
+1 -21
View File
@@ -1,7 +1,5 @@
name: Publish Nym binaries
on:
workflow_dispatch:
release:
types: [created]
@@ -20,7 +18,7 @@ jobs:
- uses: actions/checkout@v3
- name: Check the release tag starts with `nym-binaries-`
if: startsWith(github.ref, 'refs/tags/nym-binaries-') == false && github.event_name != 'workflow_dispatch'
if: startsWith(github.ref, 'refs/tags/nym-binaries-') == false
uses: actions/github-script@v3
with:
script: |
@@ -37,24 +35,8 @@ jobs:
command: build
args: --workspace --release
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: my-artifact
path: |
target/release/nym-client
target/release/nym-gateway
target/release/nym-mixnode
target/release/nym-socks5-client
target/release/nym-validator-api
target/release/nym-network-requester
target/release/nym-network-statistics
target/release/nym-cli
retention-days: 30
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
target/release/nym-client
@@ -63,5 +45,3 @@ jobs:
target/release/nym-socks5-client
target/release/nym-validator-api
target/release/nym-network-requester
target/release/nym-network-statistics
target/release/nym-cli
+254 -27
View File
@@ -2,23 +2,8 @@
Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Added
- nym-cli: added CLI tool for interacting with the Nyx blockchain and Nym mixnet smart contracts ([#1577])
- validator-client: added `query_contract_smart` and `query_contract_raw` on `NymdClient` ([#1558])
### Changed
- validator-client: made `fee` argument optional for `execute` and `execute_multiple` ([#1541])
[#1541]: https://github.com/nymtech/nym/pull/1541
[#1558]: https://github.com/nymtech/nym/pull/1558
[#1577]: https://github.com/nymtech/nym/pull/1577
## [nym-binaries-1.0.2](https://github.com/nymtech/nym/tree/nym-binaries-1.0.2)
## [Unreleased]
### Added
@@ -34,14 +19,12 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
- validator-api: add Swagger to document the REST API ([#1249]).
- validator-api: Added new endpoints for coconut spending flow and communications with coconut & multisig contracts ([#1261])
- validator-api: add `uptime`, `estimated_operator_apy`, `estimated_delegators_apy` to `/mixnodes/detailed` endpoint ([#1393])
- validator-api: add node info cache storing simulated active set inclusion probabilities
- network-statistics: a new mixnet service that aggregates and exposes anonymized data about mixnet services ([#1328])
- mixnode: Added basic mixnode hardware reporting to the HTTP API ([#1308]).
- validator-api: endpoint, in coconut mode, for returning the validator-api cosmos address ([#1404]).
- validator-client: add `denom` argument and add simple test for querying an account balance
- gateway, validator-api: Checks for coconut credential double spending attempts, taking the coconut bandwidth contract as source of truth ([#1457])
- coconut-bandwidth-contract: Record the state of a coconut credential; create specific proposal for releasing funds ([#1457])
- inclusion-probability: add simulator for active set inclusion probability
### Fixed
@@ -54,7 +37,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
- validator: fixed local docker-compose setup to work on Apple M1 ([#1329])
- explorer-api: listen out for SIGTERM and SIGQUIT too, making it play nicely as a system service ([#1482]).
- network-requester: fix filter for suffix-only domains ([#1487])
- validator-api: listen out for SIGTERM and SIGQUIT too, making it play nicely as a system service; cleaner shutdown, without panics ([#1496], [#1573]).
### Changed
@@ -69,9 +51,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
- multisig-contract: Limit the proposal creating functionality to one address (coconut-bandwidth-contract address) ([#1457])
- All binaries and cosmwasm blobs are configured at runtime now; binaries are configured using environment variables or .env files and contracts keep the configuration parameters in storage ([#1463])
- gateway, network-statistics: include gateway id in the sent statistical data ([#1478])
- network explorer: tweak how active set probability is shown ([#1503])
- validator-api: rewarder set update fails without panicking on possible nymd queries ([#1520])
- network-requester, socks5 client (nym-connect): send and receive respectively a message error to be displayed about filter check failure ([#1576])
[#1249]: https://github.com/nymtech/nym/pull/1249
@@ -98,11 +77,90 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
[#1478]: https://github.com/nymtech/nym/pull/1478
[#1482]: https://github.com/nymtech/nym/pull/1482
[#1487]: https://github.com/nymtech/nym/pull/1487
[#1496]: https://github.com/nymtech/nym/pull/1496
[#1503]: https://github.com/nymtech/nym/pull/1503
[#1520]: https://github.com/nymtech/nym/pull/1520
[#1573]: https://github.com/nymtech/nym/pull/1573
[#1576]: https://github.com/nymtech/nym/pull/1576
## [nym-connect-v1.0.1](https://github.com/nymtech/nym/tree/nym-connect-v1.0.1) (2022-07-22)
### Added
- nym-connect: initial proof-of-concept of a UI around the socks5 client was added
- nym-connect: add ability to select network requester and gateway ([#1427])
- nym-connect: add ability to export gateway keys as JSON
- nym-connect: add auto updater
### Changed
- nym-connect: reuse config id instead of creating a new id on each connection
[#1427]: https://github.com/nymtech/nym/pull/1427
## [nym-wallet-v1.0.7](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.7) (2022-07-11)
- wallet: dark mode
- wallet: when simulating gas costs, an automatic adjustment is being used ([#1388]).
[#1388]: https://github.com/nymtech/nym/pull/1388
## [nym-contracts-v1.0.1](https://github.com/nymtech/nym/tree/nym-contracts-v1.0.1) (2022-06-22)
### Added
- mixnet-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
- mixnet-contract: Replace all naked `-` with `saturating_sub`.
- mixnet-contract: Added staking_supply field to ContractStateParams.
- mixnet-contract: Added a query to get MixnodeBond by identity key ([#1369]).
- mixnet-contract: Added a query to get GatewayBond by identity key ([#1369]).
- vesting-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
- vesting-contract: Added limit to the amount of tokens one can pledge ([#1331])
### Fixed
- mixnet-contract: `estimated_delegator_reward` calculation ([#1284])
- mixnet-contract: delegator and operator rewards use lambda and sigma instead of lambda_ticked and sigma_ticked ([#1284])
- mixnet-contract: removed `expect` in `query_delegator_reward` and queries containing invalid proxy address should now return a more human-readable error ([#1257])
- mixnet-contract: replaced integer division with fixed for performance calculations ([#1284])
- mixnet-contract: Under certain circumstances nodes could not be unbonded ([#1255](https://github.com/nymtech/nym/issues/1255)) ([#1258])
- mixnet-contract: Using correct staking supply when distributing rewards. ([#1373])
- vesting-contract: replaced `checked_sub` with `saturating_sub` to fix the underflow in `get_vesting_tokens` ([#1275])
[#1255]: https://github.com/nymtech/nym/pull/1255
[#1257]: https://github.com/nymtech/nym/pull/1257
[#1258]: https://github.com/nymtech/nym/pull/1258
[#1275]: https://github.com/nymtech/nym/pull/1275
[#1284]: https://github.com/nymtech/nym/pull/1284
[#1292]: https://github.com/nymtech/nym/pull/1292
[#1331]: https://github.com/nymtech/nym/pull/1331
[#1369]: https://github.com/nymtech/nym/pull/1369
[#1373]: https://github.com/nymtech/nym/pull/1373
## [nym-wallet-v1.0.6](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.6) (2022-06-21)
- wallet: undelegating now uses either the mixnet or vesting contract, or both, depending on how delegations were made
- wallet: redeeming and compounding now uses both the mixnet and vesting contract
- wallet: the wallet backend learned how to archive wallet files
- wallet: add ENABLE_QA_MODE environment variable to enable QA mode on built wallet
## [nym-wallet-v1.0.5](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.5) (2022-06-14)
- wallet: add simple CLI tool for decrypting and recovering the wallet file.
- wallet: added support for multiple accounts ([#1265])
- wallet: compound and claim reward endpoints for operators and delegators ([#1302])
- wallet: require password to switch accounts
- wallet: the wallet backend learned how to keep track of validator name, either hardcoded or by querying the status endpoint.
- wallet: new delegation and rewards UI
- wallet: show version in nav bar
- wallet: contract admin route put back
- wallet: staking_supply field to StateParams
- wallet: show transaction hash for redeeming or compounding rewards
[#1265]: https://github.com/nymtech/nym/pull/1265
[#1302]: https://github.com/nymtech/nym/pull/1302
## [nym-wallet-v1.0.4](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.4) (2022-05-04)
### 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)
@@ -135,10 +193,77 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
[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)
@@ -217,6 +342,108 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
- 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)
Generated
+693 -1088
View File
File diff suppressed because it is too large Load Diff
+9 -12
View File
@@ -22,24 +22,22 @@ members = [
"clients/native",
"clients/native/websocket-requests",
"clients/socks5",
"common/bandwidth-claim-contract",
"common/client-libs/gateway-client",
"common/client-libs/mixnet-client",
"common/client-libs/validator-client",
"common/credential-storage",
"common/coconut-interface",
"common/commands",
"common/config",
"common/credentials",
"common/crypto",
"common/crypto/dkg",
"common/execute",
"common/bandwidth-claim-contract",
"common/cosmwasm-smart-contracts/coconut-bandwidth-contract",
"common/cosmwasm-smart-contracts/contracts-common",
"common/cosmwasm-smart-contracts/mixnet-contract",
"common/cosmwasm-smart-contracts/multisig-contract",
"common/cosmwasm-smart-contracts/vesting-contract",
"common/credential-storage",
"common/credentials",
"common/crypto",
"common/crypto/dkg",
"common/execute",
"common/inclusion-probability",
"common/mixnode-common",
"common/network-defaults",
"common/nonexhaustive-delayqueue",
@@ -55,9 +53,9 @@ members = [
"common/nymsphinx/params",
"common/nymsphinx/types",
"common/pemstore",
"common/statistics",
"common/socks5/proxy-helpers",
"common/socks5/requests",
"common/statistics",
"common/task",
"common/topology",
"common/types",
@@ -70,8 +68,8 @@ members = [
"service-providers/network-statistics",
"validator-api",
"validator-api/validator-api-requests",
"tools/nym-cli",
"tools/ts-rs-cli"
"tools/ts-rs-cli",
"tools/validator-client-scripts"
]
default-members = [
@@ -79,7 +77,6 @@ default-members = [
"clients/socks5",
"gateway",
"service-providers/network-requester",
"service-providers/network-statistics",
"mixnode",
"validator-api",
"explorer-api",
-3
View File
@@ -69,9 +69,6 @@ build-wallet:
build-connect:
cargo build --manifest-path nym-connect/Cargo.toml --workspace
build-nym-cli:
cargo build --release --manifest-path tools/nym-cli/Cargo.toml
fmt-main:
cargo fmt --all
@@ -133,6 +133,7 @@ where
let prepared_fragment = self
.message_preparer
.prepare_chunk_for_sending(chunk_clone, topology, &self.ack_key, &recipient)
.await
.unwrap();
real_messages.push(RealMessage::new(
@@ -83,6 +83,7 @@ where
let prepared_fragment = self
.message_preparer
.prepare_chunk_for_sending(chunk_clone, topology_ref, &self.ack_key, packet_recipient)
.await
.unwrap();
// if we have the ONLY strong reference to the ack data, it means it was removed from the
-1
View File
@@ -18,7 +18,6 @@ url = "2.2"
tokio = { version = "1.19.1", features = ["rt-multi-thread", "net", "signal", "macros"] } # async runtime
coconut-interface = { path = "../../common/coconut-interface" }
config = { path = "../../common/config" }
credentials = { path = "../../common/credentials" }
credential-storage = { path = "../../common/credential-storage" }
crypto = { path = "../../common/crypto", features = ["rand", "asymmetric", "symmetric", "aes", "hashing"] }
+4 -3
View File
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::error::Result;
use crate::{MNEMONIC, NYMD_URL};
use bip39::Mnemonic;
use network_defaults::{NymNetworkDetails, VOUCHER_INFO};
use std::str::FromStr;
@@ -16,9 +17,9 @@ pub(crate) struct Client {
}
impl Client {
pub fn new(nymd_url: &str, mnemonic: &str) -> Self {
let nymd_url = Url::from_str(nymd_url).unwrap();
let mnemonic = Mnemonic::from_str(mnemonic).unwrap();
pub fn new() -> Self {
let nymd_url = Url::from_str(NYMD_URL).unwrap();
let mnemonic = Mnemonic::from_str(MNEMONIC).unwrap();
let network_details = NymNetworkDetails::new_from_env();
let config = nymd::Config::try_from_nym_network_details(&network_details)
.expect("failed to construct valid validator client config with the provided network");
+4 -13
View File
@@ -6,6 +6,7 @@ use clap::{Args, Subcommand};
use pickledb::PickleDb;
use rand::rngs::OsRng;
use std::str::FromStr;
use url::Url;
use coconut_interface::{Attribute, Base58, BlindSignRequest, Bytable, Parameters};
use credential_storage::storage::Storage;
@@ -19,6 +20,7 @@ use validator_client::nymd::tx::Hash;
use crate::client::Client;
use crate::error::{CredentialClientError, Result};
use crate::state::{KeyPair, RequestData, State};
use crate::SIGNER_AUTHORITIES;
#[derive(Subcommand)]
pub(crate) enum Commands {
@@ -37,12 +39,6 @@ pub(crate) trait Execute {
#[derive(Args, Clone)]
pub(crate) struct Deposit {
/// The nymd URL that should be used
#[clap(long)]
nymd_url: String,
/// A mnemonic for the account that does the deposit
#[clap(long)]
mnemonic: String,
/// The amount that needs to be deposited
#[clap(long)]
amount: u64,
@@ -55,7 +51,7 @@ impl Execute for Deposit {
let signing_keypair = KeyPair::from(identity::KeyPair::new(&mut rng));
let encryption_keypair = KeyPair::from(encryption::KeyPair::new(&mut rng));
let client = Client::new(&self.nymd_url, &self.mnemonic);
let client = Client::new();
let tx_hash = client
.deposit(
self.amount,
@@ -100,10 +96,6 @@ pub(crate) struct GetCredential {
/// The hash of a successful deposit transaction
#[clap(long)]
tx_hash: String,
/// The URLs to the validator-api endpoints the are run as coconut signer authorities, separated
/// by comma (,)
#[clap(long)]
signer_authorities: String,
/// If we want to get the signature without attaching a blind sign request; it is expected that
/// there is already a signature stored on the signer
#[clap(long, parse(from_flag))]
@@ -116,8 +108,7 @@ impl Execute for GetCredential {
let mut state = db
.get::<State>(&self.tx_hash)
.ok_or(CredentialClientError::NoDeposit)?;
let urls = config::parse_validators(&self.signer_authorities);
let urls = SIGNER_AUTHORITIES.map(|addr| Url::from_str(addr).unwrap());
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
let bandwidth_credential_attributes = if self.__no_request {
+8 -13
View File
@@ -11,24 +11,20 @@ cfg_if::cfg_if! {
use commands::{Commands, Execute};
use error::Result;
use network_defaults::setup_env;
use clap::Parser;
use pickledb::{PickleDb, PickleDbDumpPolicy, SerializationMethod};
pub const MNEMONIC: &str = "jazz fatigue diagram account outer wrist slide cherry mother grid network pause wolf pig round answer mail junior better hair dismiss toward access end";
pub const NYMD_URL: &str = "http://127.0.0.1:26657";
pub const CONTRACT_ADDRESS: &str = "nymt1nc5tatafv6eyq7llkr2gv50ff9e22mnfp9pc5s";
pub const SIGNER_AUTHORITIES: [&str; 1] = [
"http://127.0.0.1:8080",
];
#[derive(Parser)]
#[clap(author = "Nymtech", version, about)]
struct Cli {
/// Path pointing to an env file that configures the client.
#[clap(long)]
pub(crate) config_env_file: Option<std::path::PathBuf>,
/// Path where the sqlite credental database will be located.
/// It should point to a $HOME/$CLIENT_ID/data/db.sqlite file of
/// the client that is supposed to use the credential.
#[clap(long)]
pub(crate) credential_db_path: std::path::PathBuf,
#[clap(subcommand)]
command: Commands,
}
@@ -36,9 +32,8 @@ cfg_if::cfg_if! {
#[tokio::main]
async fn main() -> Result<()> {
let args = Cli::parse();
setup_env(args.config_env_file.clone());
let shared_storage = credential_storage::initialise_storage(args.credential_db_path.clone()).await;
let shared_storage = credential_storage::initialise_storage(std::path::PathBuf::from("/tmp/credential.db")).await;
let mut db = match PickleDb::load(
"credential.db",
PickleDbDumpPolicy::AutoDump,
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.0.2"
version = "1.0.1"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
-4
View File
@@ -50,10 +50,6 @@ impl NymConfig for Config {
.join("clients")
}
fn try_default_root_directory() -> Option<PathBuf> {
dirs::home_dir().map(|path| path.join(".nym").join("clients"))
}
fn root_directory(&self) -> PathBuf {
self.base.get_nym_root_directory()
}
+3 -3
View File
@@ -199,9 +199,9 @@ impl NymClient {
Some(bandwidth_controller),
);
gateway_client
.set_disabled_credentials_mode(self.config.get_base().get_disabled_credentials_mode());
if self.config.get_base().get_disabled_credentials_mode() {
gateway_client.set_disabled_credentials_mode(true)
}
gateway_client
.authenticate_and_start()
.await
+5 -4
View File
@@ -46,9 +46,10 @@ pub(crate) struct Init {
fastmode: bool,
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[cfg(any(feature = "eth", feature = "coconut"))]
#[clap(long)]
/// with bandwidth credential requirement. If this value is set, --eth-endpoint and
/// --eth-private_key don't need to be set.
#[cfg(all(feature = "eth", not(feature = "coconut")))]
#[clap(long, conflicts_with_all = &["eth-endpoint", "eth-private-key"])]
enabled_credentials_mode: bool,
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20
@@ -78,7 +79,7 @@ impl From<Init> for OverrideConfig {
port: init_config.port,
fastmode: init_config.fastmode,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(all(feature = "eth", not(feature = "coconut")))]
enabled_credentials_mode: init_config.enabled_credentials_mode,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
+17 -8
View File
@@ -3,6 +3,7 @@
use crate::client::config::{Config, SocketType};
use clap::{Parser, Subcommand};
use url::Url;
#[cfg(not(feature = "coconut"))]
pub(crate) const DEFAULT_ETH_ENDPOINT: &str =
@@ -78,7 +79,7 @@ pub(crate) struct OverrideConfig {
port: Option<u16>,
fastmode: bool,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(all(feature = "eth", not(feature = "coconut")))]
enabled_credentials_mode: bool,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
@@ -96,17 +97,28 @@ pub(crate) async fn execute(args: &Cli) {
}
}
fn parse_validators(raw: &str) -> Vec<Url> {
raw.split(',')
.map(|raw_validator| {
raw_validator
.trim()
.parse()
.expect("one of the provided validator api urls is invalid")
})
.collect()
}
pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Config {
if let Some(raw_validators) = args.validators {
config
.get_base_mut()
.set_custom_validator_apis(config::parse_validators(&raw_validators));
.set_custom_validator_apis(parse_validators(&raw_validators));
} else if std::env::var(network_defaults::var_names::CONFIGURED).is_ok() {
let raw_validators = std::env::var(network_defaults::var_names::API_VALIDATOR)
.expect("api validator not set");
config
.get_base_mut()
.set_custom_validator_apis(config::parse_validators(&raw_validators));
.set_custom_validator_apis(parse_validators(&raw_validators));
}
if args.disable_socket {
@@ -126,15 +138,12 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi
.get_base_mut()
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY.to_string());
}
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(all(feature = "eth", not(feature = "coconut")))]
{
if args.enabled_credentials_mode {
config.get_base_mut().with_disabled_credentials(false)
}
}
#[cfg(all(feature = "eth", not(feature = "coconut")))]
{
if let Some(eth_endpoint) = args.eth_endpoint {
config.get_base_mut().with_eth_endpoint(eth_endpoint);
}
+6 -5
View File
@@ -35,9 +35,10 @@ pub(crate) struct Run {
port: Option<u16>,
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[cfg(any(feature = "eth", feature = "coconut"))]
#[clap(long)]
/// with bandwidth credential requirement. If this value is set, --eth-endpoint and
/// --eth-private-key don't need to be set.
#[cfg(all(feature = "eth", not(feature = "coconut")))]
#[clap(long, conflicts_with_all = &["eth-endpoint", "eth-private-key"])]
enabled_credentials_mode: bool,
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20
@@ -61,7 +62,7 @@ impl From<Run> for OverrideConfig {
port: run_config.port,
fastmode: false,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(all(feature = "eth", not(feature = "coconut")))]
enabled_credentials_mode: run_config.enabled_credentials_mode,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
@@ -81,7 +82,7 @@ fn version_check(cfg: &Config) -> bool {
if binary_version == config_version {
true
} else {
warn!("The native-client binary has different version than what is specified in config file! {} and {}", binary_version, config_version);
warn!("The mixnode binary has different version than what is specified in config file! {} and {}", binary_version, config_version);
if is_minor_version_compatible(binary_version, config_version) {
info!("but they are still semver compatible. However, consider running the `upgrade` command");
true
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.0.2"
version = "1.0.1"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021"
-4
View File
@@ -33,10 +33,6 @@ impl NymConfig for Config {
.join("socks5-clients")
}
fn try_default_root_directory() -> Option<PathBuf> {
dirs::home_dir().map(|path| path.join(".nym").join("socks5-clients"))
}
fn root_directory(&self) -> PathBuf {
self.base.get_nym_root_directory()
}
+3 -3
View File
@@ -198,9 +198,9 @@ impl NymClient {
Some(bandwidth_controller),
);
gateway_client
.set_disabled_credentials_mode(self.config.get_base().get_disabled_credentials_mode());
if self.config.get_base().get_disabled_credentials_mode() {
gateway_client.set_disabled_credentials_mode(true)
}
gateway_client
.authenticate_and_start()
.await
+5 -4
View File
@@ -46,9 +46,10 @@ pub(crate) struct Init {
fastmode: bool,
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[cfg(any(feature = "eth", feature = "coconut"))]
#[clap(long)]
/// with bandwidth credential requirement. If this value is set, --eth-endpoint and
/// --eth-private_key don't need to be set.
#[cfg(all(feature = "eth", not(feature = "coconut")))]
#[clap(long, conflicts_with_all = &["eth-endpoint", "eth-private-key"])]
enabled_credentials_mode: bool,
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20
@@ -77,7 +78,7 @@ impl From<Init> for OverrideConfig {
port: init_config.port,
fastmode: init_config.fastmode,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(all(feature = "eth", not(feature = "coconut")))]
enabled_credentials_mode: init_config.enabled_credentials_mode,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
+14 -6
View File
@@ -3,7 +3,7 @@
use crate::client::config::Config;
use clap::{Parser, Subcommand};
use config::parse_validators;
use url::Url;
pub mod init;
pub(crate) mod run;
@@ -78,7 +78,7 @@ pub(crate) struct OverrideConfig {
port: Option<u16>,
fastmode: bool,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(all(feature = "eth", not(feature = "coconut")))]
enabled_credentials_mode: bool,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
@@ -96,6 +96,17 @@ pub(crate) async fn execute(args: &Cli) {
}
}
pub fn parse_validators(raw: &str) -> Vec<Url> {
raw.split(',')
.map(|raw_validator| {
raw_validator
.trim()
.parse()
.expect("one of the provided validator api urls is invalid")
})
.collect()
}
pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Config {
if let Some(raw_validators) = args.validators {
config
@@ -121,14 +132,11 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY.to_string());
}
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(all(feature = "eth", not(feature = "coconut")))]
{
if args.enabled_credentials_mode {
config.get_base_mut().with_disabled_credentials(false)
}
}
#[cfg(all(feature = "eth", not(feature = "coconut")))]
{
if let Some(eth_endpoint) = args.eth_endpoint {
config.get_base_mut().with_eth_endpoint(eth_endpoint);
}
+5 -4
View File
@@ -39,9 +39,10 @@ pub(crate) struct Run {
port: Option<u16>,
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[cfg(any(feature = "eth", feature = "coconut"))]
#[clap(long)]
/// with bandwidth credential requirement. If this value is set, --eth-endpoint and
/// --eth-private-key don't need to be set.
#[cfg(all(feature = "eth", not(feature = "coconut")))]
#[clap(long, conflicts_with_all = &["eth-endpoint", "eth-private-key"])]
enabled_credentials_mode: bool,
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20
@@ -64,7 +65,7 @@ impl From<Run> for OverrideConfig {
port: run_config.port,
fastmode: false,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(all(feature = "eth", not(feature = "coconut")))]
enabled_credentials_mode: run_config.enabled_credentials_mode,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
+5
View File
@@ -2,4 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
pub mod client;
// This is only used as we reach into the init functions in nym-connect. We need to refactor the
// init functions so that nym-connect can just call the same init function as the regular socks5
// client.
#[allow(unused)]
pub mod commands;
pub mod socks;
@@ -54,13 +54,6 @@ impl MixnetResponseListener {
return;
}
Ok(Message::Response(data)) => data,
Ok(Message::NetworkRequesterResponse(r)) => {
error!(
"Network requester failed on connection id {} with error: {}",
r.connection_id, r.network_requester_error
);
return;
}
};
self.controller_sender
+4 -1
View File
@@ -132,7 +132,9 @@ impl NymClient {
bandwidth_controller,
);
gateway_client.set_disabled_credentials_mode(disabled_credentials_mode);
if disabled_credentials_mode {
gateway_client.set_disabled_credentials_mode(true)
}
gateway_client
.authenticate_and_start()
@@ -197,6 +199,7 @@ impl NymClient {
// don't bother with acks etc. for time being
let prepared_fragment = message_preparer
.prepare_chunk_for_sending(message_chunk, topology, &self.ack_key, &recipient)
.await
.unwrap();
console_warn!("packet is going to have round trip time of {:?}, but we're not going to do anything for acks anyway ", prepared_fragment.total_delay);
@@ -162,10 +162,12 @@ impl PartiallyDelegated {
.expect("stream sender was somehow dropped without sending anything!");
if let Some(res) = receive_res {
let _res = res?;
panic!(
"This should have NEVER happened - returned a stream before receiving notification"
)
if let Err(err) = res {
// the receiver got an error. most likely a network one.
return Err(err);
} else {
panic!("This should have NEVER happened - returned a stream before receiving notification")
}
}
// this call failing is incredibly unlikely, but not impossible.
@@ -489,7 +489,7 @@ impl TryFrom<ProtoContractCodeHistoryEntry> for ContractCodeHistoryEntry {
}
}
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize)]
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct GasInfo {
/// GasWanted is the maximum units of work we allow this tx to perform.
pub gas_wanted: Gas,
@@ -645,7 +645,7 @@ impl InstantiateOptions {
}
}
#[derive(Debug, Serialize)]
#[derive(Debug)]
pub struct InstantiateResult {
/// The address of the newly instantiated contract
pub contract_address: AccountId,
@@ -658,7 +658,7 @@ pub struct InstantiateResult {
pub gas_info: GasInfo,
}
#[derive(Debug, Serialize)]
#[derive(Debug)]
pub struct ChangeAdminResult {
pub logs: Vec<Log>,
@@ -668,7 +668,7 @@ pub struct ChangeAdminResult {
pub gas_info: GasInfo,
}
#[derive(Debug, Serialize)]
#[derive(Debug)]
pub struct MigrateResult {
pub logs: Vec<Log>,
@@ -678,7 +678,7 @@ pub struct MigrateResult {
pub gas_info: GasInfo,
}
#[derive(Debug, Serialize)]
#[derive(Debug)]
pub struct ExecuteResult {
pub logs: Vec<Log>,
@@ -10,8 +10,6 @@ use crate::nymd::error::NymdError;
use crate::nymd::fee::DEFAULT_SIMULATED_GAS_MULTIPLIER;
use crate::nymd::wallet::DirectSecp256k1HdWallet;
use cosmrs::cosmwasm;
use cosmrs::rpc::endpoint::block::Response as BlockResponse;
use cosmrs::rpc::query::Query;
use cosmrs::rpc::Error as TendermintRpcError;
use cosmrs::rpc::HttpClientUrl;
use cosmrs::tx::Msg;
@@ -22,11 +20,11 @@ use mixnet_contract_common::{
ContractStateParams, Delegation, ExecuteMsg, Gateway, GatewayBond, GatewayBondResponse,
GatewayOwnershipResponse, IdentityKey, Interval, LayerDistribution, MixNode, MixNodeBond,
MixOwnershipResponse, MixnetContractVersion, MixnodeBondResponse,
MixnodeRewardingStatusResponse, PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse,
PagedGatewayResponse, PagedMixDelegationsResponse, PagedMixnodeResponse,
PagedRewardedSetResponse, QueryMsg, RewardedSetUpdateDetails,
MixnodeRewardingStatusResponse, PagedDelegatorDelegationsResponse, PagedGatewayResponse,
PagedMixDelegationsResponse, PagedMixnodeResponse, PagedRewardedSetResponse, QueryMsg,
RewardedSetUpdateDetails,
};
use serde::{Deserialize, Serialize};
use serde::Serialize;
use std::convert::TryInto;
use std::time::SystemTime;
use vesting_contract_common::ExecuteMsg as VestingExecuteMsg;
@@ -214,10 +212,6 @@ impl<C> NymdClient<C> {
&self.config
}
pub fn current_chain_details(&self) -> &ChainDetails {
&self.config.chain_details
}
pub fn set_mixnet_contract_address(&mut self, address: AccountId) {
self.config.mixnet_contract_address = Some(address);
}
@@ -288,30 +282,6 @@ impl<C> NymdClient<C> {
self.simulated_gas_multiplier = multiplier;
}
pub async fn query_contract_smart<M, T>(
&self,
contract: &AccountId,
query_msg: &M,
) -> Result<T, NymdError>
where
C: CosmWasmClient + Sync,
M: ?Sized + Serialize + Sync,
for<'a> T: Deserialize<'a>,
{
self.client.query_contract_smart(contract, query_msg).await
}
pub async fn query_contract_raw(
&self,
contract: &AccountId,
query_data: Vec<u8>,
) -> Result<Vec<u8>, NymdError>
where
C: CosmWasmClient + Sync,
{
self.client.query_contract_raw(contract, query_data).await
}
pub fn wrap_contract_execute_message<M>(
&self,
contract_address: &AccountId,
@@ -361,26 +331,11 @@ impl<C> NymdClient<C> {
address: &AccountId,
) -> Result<Option<Account>, NymdError>
where
C: CosmWasmClient + Sync,
C: SigningCosmWasmClient + Sync,
{
self.client.get_account(address).await
}
pub async fn get_account_public_key(
&self,
address: &AccountId,
) -> Result<Option<cosmrs::crypto::PublicKey>, NymdError>
where
C: CosmWasmClient + Sync,
{
if let Some(account) = self.client.get_account(address).await? {
let base_account = account.try_get_base_account()?;
return Ok(base_account.pubkey);
}
Ok(None)
}
pub async fn get_current_block_timestamp(&self) -> Result<TendermintTime, NymdError>
where
C: CosmWasmClient + Sync,
@@ -398,13 +353,6 @@ impl<C> NymdClient<C> {
Ok(self.client.get_block(height).await?.block.header.time)
}
pub async fn get_block(&self, height: Option<u32>) -> Result<BlockResponse, NymdError>
where
C: CosmWasmClient + Sync,
{
self.client.get_block(height).await
}
pub async fn get_current_block_height(&self) -> Result<Height, NymdError>
where
C: CosmWasmClient + Sync,
@@ -449,13 +397,6 @@ impl<C> NymdClient<C> {
self.client.get_balance(address, denom).await
}
pub async fn get_all_balances(&self, address: &AccountId) -> Result<Vec<Coin>, NymdError>
where
C: CosmWasmClient + Sync,
{
self.client.get_all_balances(address).await
}
pub async fn get_tx(&self, id: tx::Hash) -> Result<TxResponse, NymdError>
where
C: CosmWasmClient + Sync,
@@ -463,13 +404,6 @@ impl<C> NymdClient<C> {
self.client.get_tx(id).await
}
pub async fn search_tx(&self, query: Query) -> Result<Vec<TxResponse>, NymdError>
where
C: CosmWasmClient + Sync,
{
self.client.search_tx(query).await
}
pub async fn get_total_supply(&self) -> Result<Vec<Coin>, NymdError>
where
C: CosmWasmClient + Sync,
@@ -838,22 +772,6 @@ impl<C> NymdClient<C> {
.await
}
pub async fn get_all_delegations_paged(
&self,
start_after: Option<(IdentityKey, Vec<u8>, u64)>,
) -> Result<PagedAllDelegationsResponse, NymdError>
where
C: CosmWasmClient + Sync,
{
let request = QueryMsg::GetAllDelegationValuesPaged {
start_after,
limit: None,
};
self.client
.query_contract_smart(self.mixnet_contract_address(), &request)
.await
}
/// Checks value of delegation of given client towards particular mixnode.
pub async fn get_delegation_details(
&self,
@@ -975,7 +893,7 @@ impl<C> NymdClient<C> {
&self,
contract_address: &AccountId,
msg: &M,
fee: Option<Fee>,
fee: Fee,
memo: impl Into<String> + Send + 'static,
funds: Vec<Coin>,
) -> Result<ExecuteResult, NymdError>
@@ -983,7 +901,6 @@ impl<C> NymdClient<C> {
C: SigningCosmWasmClient + Sync,
M: ?Sized + Serialize + Sync,
{
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
self.client
.execute(self.address(), contract_address, msg, fee, memo, funds)
.await
@@ -993,7 +910,7 @@ impl<C> NymdClient<C> {
&self,
contract_address: &AccountId,
msgs: I,
fee: Option<Fee>,
fee: Fee,
memo: impl Into<String> + Send + 'static,
) -> Result<ExecuteResult, NymdError>
where
@@ -1001,7 +918,6 @@ impl<C> NymdClient<C> {
I: IntoIterator<Item = (M, Vec<Coin>)> + Send,
M: Serialize,
{
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
self.client
.execute_multiple(self.address(), contract_address, msgs, fee, memo)
.await
@@ -7,11 +7,9 @@ use crate::nymd::error::NymdError;
use crate::nymd::NymdClient;
use async_trait::async_trait;
use cosmwasm_std::{Coin as CosmWasmCoin, Timestamp};
use mixnet_contract_common::IdentityKey;
use vesting_contract::vesting::Account;
use vesting_contract_common::{
messages::QueryMsg as VestingQueryMsg, AllDelegationsResponse, DelegationTimesResponse,
OriginalVestingResponse, Period, PledgeData, VestingDelegation,
messages::QueryMsg as VestingQueryMsg, OriginalVestingResponse, Period, PledgeData,
};
#[async_trait]
@@ -72,37 +70,6 @@ pub trait VestingQueryClient {
&self,
vesting_account_address: &str,
) -> Result<Period, NymdError>;
async fn get_delegation_timestamps(
&self,
address: &str,
mix_identity: String,
) -> Result<DelegationTimesResponse, NymdError>;
async fn get_all_vesting_delegations_paged(
&self,
start_after: Option<(u32, IdentityKey, u64)>,
limit: Option<u32>,
) -> Result<AllDelegationsResponse, NymdError>;
async fn get_all_vesting_delegations(&self) -> Result<Vec<VestingDelegation>, NymdError> {
let mut delegations = Vec::new();
let mut start_after = None;
loop {
let mut paged_response = self
.get_all_vesting_delegations_paged(start_after.take(), None)
.await?;
delegations.append(&mut paged_response.delegations);
if let Some(start_after_res) = paged_response.start_next_after {
start_after = Some(start_after_res)
} else {
break;
}
}
Ok(delegations)
}
}
#[async_trait]
@@ -265,29 +232,4 @@ impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NymdClient<C> {
.query_contract_smart(self.vesting_contract_address(), &request)
.await
}
async fn get_delegation_timestamps(
&self,
address: &str,
mix_identity: String,
) -> Result<DelegationTimesResponse, NymdError> {
let request = VestingQueryMsg::GetDelegationTimes {
address: address.to_string(),
mix_identity,
};
self.client
.query_contract_smart(self.vesting_contract_address(), &request)
.await
}
async fn get_all_vesting_delegations_paged(
&self,
start_after: Option<(u32, IdentityKey, u64)>,
limit: Option<u32>,
) -> Result<AllDelegationsResponse, NymdError> {
let request = VestingQueryMsg::GetAllDelegations { start_after, limit };
self.client
.query_contract_smart(self.vesting_contract_address(), &request)
.await
}
}
@@ -4,7 +4,7 @@
use crate::nymd::error::NymdError;
use config::defaults;
use cosmrs::bip32::{DerivationPath, XPrv};
use cosmrs::crypto::secp256k1::{Signature, SigningKey};
use cosmrs::crypto::secp256k1::SigningKey;
use cosmrs::crypto::PublicKey;
use cosmrs::tx::SignDoc;
use cosmrs::{tx, AccountId};
@@ -105,17 +105,6 @@ impl DirectSecp256k1HdWallet {
self.secret.to_string()
}
pub fn sign_raw_with_account(
&self,
signer: &AccountData,
message: &[u8],
) -> Result<Signature, NymdError> {
signer
.private_key
.sign(message)
.map_err(|_| NymdError::SigningFailure)
}
pub fn sign_direct_with_account(
&self,
signer: &AccountData,
-32
View File
@@ -1,32 +0,0 @@
[package]
name = "nym-cli-commands"
version = "1.0.0"
authors = ["Nym Technologies SA"]
edition = "2021"
[dependencies]
base64 = "0.13.0"
bip39 = "1.0.1"
bs58 = "0.4"
comfy-table = "6.0.0"
cfg-if = "1.0.0"
clap = { version = "3.2", features = ["derive"] }
handlebars = "3.0.1"
humantime-serde = "1.0"
k256 = { version = "0.10", features = ["ecdsa", "sha256"] }
log = "0.4"
rand = {version = "0.6", features = ["std"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1"
thiserror = "1"
time = { version = "0.3.6", features = ["parsing", "formatting"] }
toml = "0.5.6"
url = "2.2"
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support" }
cosmwasm-std = { version = "1.0.0" }
validator-client = { path = "../client-libs/validator-client", features = ["nymd-client"] }
network-defaults = { path = "../network-defaults" }
mixnet-contract-common = { path = "../cosmwasm-smart-contracts/mixnet-contract" }
vesting-contract-common = { path = "../cosmwasm-smart-contracts/vesting-contract" }
-13
View File
@@ -1,13 +0,0 @@
# Common `clap` Command Crate
This crate contains `clap` commands for common operations:
- account creation and queries
- block queries
- cosmwasm uploads, instantiate, execution, query, etc
- mixnet actions and queries
- sign and verify messages
- query for transactions
- create vesting schedules and query for them
For how to use this crate, please see the [Nym CLI](../../tools/nym-cli).
-4
View File
@@ -1,4 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
// TODO: add coconut commands here
-18
View File
@@ -1,18 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ContextError {
#[error("mnemonic was not provided, pass as an argument or an env var called MNEMONIC")]
MnemonicNotProvided,
#[error("failed to parse mnemonic - {0}")]
Bip39Error(#[from] bip39::Error),
// there are lots of error that can occur in the nymd client, so just pass through their display details
// TODO: improve this to return known errors
#[error("failed to create client - {0}")]
NymdError(String),
}
-138
View File
@@ -1,138 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use network_defaults::{
setup_env,
var_names::{API_VALIDATOR, MIXNET_CONTRACT_ADDRESS, NYMD_VALIDATOR, VESTING_CONTRACT_ADDRESS},
NymNetworkDetails,
};
use validator_client::nymd::{self, AccountId, NymdClient, QueryNymdClient, SigningNymdClient};
pub use validator_client::validator_api::Client as ValidatorApiClient;
use crate::context::errors::ContextError;
pub mod errors;
pub type SigningClient = validator_client::nymd::NymdClient<SigningNymdClient>;
pub type QueryClient = validator_client::nymd::NymdClient<QueryNymdClient>;
pub type SigningClientWithValidatorAPI = validator_client::Client<SigningNymdClient>;
pub type QueryClientWithValidatorAPI = validator_client::Client<QueryNymdClient>;
#[derive(Debug)]
pub struct ClientArgs {
pub config_env_file: Option<std::path::PathBuf>,
pub nymd_url: Option<String>,
pub validator_api_url: Option<String>,
pub mnemonic: Option<bip39::Mnemonic>,
pub mixnet_contract_address: Option<AccountId>,
pub vesting_contract_address: Option<AccountId>,
}
pub fn get_network_details(args: &ClientArgs) -> Result<NymNetworkDetails, ContextError> {
// let the network defaults crate handle setting up the env vars if the file arg is set, otherwise
// it will default to what is already in env vars, falling back to mainnet
setup_env(args.config_env_file.clone());
// override the env vars with user supplied arguments, if set
if let Some(nymd_url) = args.nymd_url.as_ref() {
std::env::set_var(NYMD_VALIDATOR, nymd_url);
}
if let Some(validator_api_url) = args.validator_api_url.as_ref() {
std::env::set_var(API_VALIDATOR, validator_api_url);
}
if let Some(mixnet_contract_address) = args.mixnet_contract_address.as_ref() {
std::env::set_var(MIXNET_CONTRACT_ADDRESS, mixnet_contract_address.to_string());
}
if let Some(vesting_contract_address) = args.vesting_contract_address.as_ref() {
std::env::set_var(
VESTING_CONTRACT_ADDRESS,
vesting_contract_address.to_string(),
);
}
Ok(NymNetworkDetails::new_from_env())
}
pub fn create_signing_client(
args: ClientArgs,
network_details: &NymNetworkDetails,
) -> Result<SigningClient, ContextError> {
let client_config = nymd::Config::try_from_nym_network_details(network_details)
.expect("failed to construct valid validator client config with the provided network");
// get mnemonic
let mnemonic = match std::env::var("MNEMONIC") {
Ok(value) => bip39::Mnemonic::parse(value)?,
// env var MNEMONIC is not present, so try to fall back to arg --mnemonic ...
Err(_) => match args.mnemonic {
Some(value) => value,
None => return Err(ContextError::MnemonicNotProvided), // no env var or arg provided
},
};
let nymd_url = network_details
.endpoints
.first()
.expect("network details are not defined")
.nymd_url
.as_str();
match NymdClient::connect_with_mnemonic(client_config, nymd_url, mnemonic, None) {
Ok(client) => Ok(client),
Err(e) => Err(ContextError::NymdError(format!("{:?}", e))),
}
}
pub fn create_query_client(
network_details: &NymNetworkDetails,
) -> Result<QueryClient, ContextError> {
let client_config = nymd::Config::try_from_nym_network_details(network_details)
.expect("failed to construct valid validator client config with the provided network");
let nymd_url = network_details
.endpoints
.first()
.expect("network details are not defined")
.nymd_url
.as_str();
match NymdClient::connect(client_config, nymd_url) {
Ok(client) => Ok(client),
Err(e) => Err(ContextError::NymdError(format!("{:?}", e))),
}
}
pub fn create_signing_client_with_validator_api(
args: ClientArgs,
network_details: &NymNetworkDetails,
) -> Result<SigningClientWithValidatorAPI, ContextError> {
let client_config = validator_client::Config::try_from_nym_network_details(network_details)
.expect("failed to construct valid validator client config with the provided network");
// get mnemonic
let mnemonic = match std::env::var("MNEMONIC") {
Ok(value) => bip39::Mnemonic::parse(value)?,
// env var MNEMONIC is not present, so try to fall back to arg --mnemonic ...
Err(_) => match args.mnemonic {
Some(value) => value,
None => return Err(ContextError::MnemonicNotProvided), // no env var or arg provided
},
};
match validator_client::client::Client::new_signing(client_config, mnemonic) {
Ok(client) => Ok(client),
Err(e) => Err(ContextError::NymdError(format!("{:?}", e))),
}
}
pub fn create_query_client_with_validator_api(
network_details: &NymNetworkDetails,
) -> Result<QueryClientWithValidatorAPI, ContextError> {
let client_config = validator_client::Config::try_from_nym_network_details(network_details)
.expect("failed to construct valid validator client config with the provided network");
match validator_client::client::Client::new_query(client_config) {
Ok(client) => Ok(client),
Err(e) => Err(ContextError::NymdError(format!("{:?}", e))),
}
}
-7
View File
@@ -1,7 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod coconut;
pub mod context;
pub mod utils;
pub mod validator;
-44
View File
@@ -1,44 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::error::Error;
use std::fmt::Display;
use cosmwasm_std::{Coin as CosmWasmCoin, Decimal};
use log::error;
use validator_client::nymd::Coin;
pub fn pretty_coin(coin: &Coin) -> String {
let amount = Decimal::from_ratio(coin.amount, 1_000_000u128);
let denom = if coin.denom.starts_with('u') {
&coin.denom[1..]
} else {
&coin.denom
};
format!("{} {}", amount, denom)
}
pub fn pretty_cosmwasm_coin(coin: &CosmWasmCoin) -> String {
let amount = Decimal::from_ratio(coin.amount, 1_000_000u128);
let denom = if coin.denom.starts_with('u') {
&coin.denom[1..]
} else {
&coin.denom
};
format!("{} {}", amount, denom)
}
pub fn show_error<E>(e: E)
where
E: Display,
{
error!("{}", e);
}
pub fn show_error_passthrough<E>(e: E) -> E
where
E: Error + Display,
{
error!("{}", e);
e
}
@@ -1,72 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
use log::{error, info};
use validator_client::nymd::AccountId;
use crate::context::QueryClient;
use crate::utils::{pretty_coin, show_error};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(value_parser)]
#[clap(help = "The account address to get the balance for")]
pub address: Option<AccountId>,
#[clap(long)]
#[clap(help = "Optional currency to show balance for")]
pub denom: Option<String>,
#[clap(long, requires = "denom")]
#[clap(help = "Optionally hide the denom")]
pub hide_denom: bool,
#[clap(long)]
#[clap(help = "Show as a raw value")]
pub raw: bool,
}
pub async fn query_balance(
args: Args,
client: &QueryClient,
address_from_mnemonic: Option<AccountId>,
) {
if args.address.is_none() && address_from_mnemonic.is_none() {
error!("Please specify an account address or a mnemonic to get the balance for");
return;
}
let address = args
.address
.unwrap_or_else(|| address_from_mnemonic.expect("please provide a mnemonic"));
info!("Getting balance for {}...", address);
match client.get_all_balances(&address).await {
Ok(coins) => {
if coins.is_empty() {
println!("No balance");
return;
}
let denom = args.denom.unwrap_or_else(|| "".to_string());
for coin in coins {
if denom.is_empty() || denom.eq_ignore_ascii_case(&coin.denom) {
if args.raw {
if !args.hide_denom {
println!("{}", coin);
} else {
println!("{}", coin.amount);
}
} else {
println!("{}", pretty_coin(&coin));
}
}
}
}
Err(e) => show_error(e),
}
}
@@ -1,28 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod balance;
pub mod create;
pub mod pubkey;
pub mod send;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Account {
#[clap(subcommand)]
pub command: Option<AccountCommands>,
}
#[derive(Debug, Subcommand)]
pub enum AccountCommands {
/// Create a new mnemonic - note, this account does not appear on the chain until the account id is used in a transaction
Create(crate::validator::account::create::Args),
/// Gets the balance of an account
Balance(crate::validator::account::balance::Args),
/// Gets the public key of an account
PubKey(crate::validator::account::pubkey::Args),
/// Sends tokens to another account
Send(crate::validator::account::send::Args),
}
@@ -1,89 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
use log::{error, info};
use validator_client::nymd::wallet::DirectSecp256k1HdWallet;
use validator_client::nymd::AccountId;
use crate::context::QueryClient;
use crate::utils::show_error;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(value_parser)]
#[clap(
help = "Optionally, show the public key for this account address, otherwise generate the account address from the mnemonic"
)]
pub address: Option<AccountId>,
#[clap(long)]
#[clap(help = "If set, get the public key from the mnemonic, rather than querying for it")]
pub from_mnemonic: bool,
}
pub async fn get_pubkey(
args: Args,
client: &QueryClient,
mnemonic: Option<bip39::Mnemonic>,
address_from_mnemonic: Option<AccountId>,
) {
if args.address.is_none() && address_from_mnemonic.is_none() {
error!("Please specify an account address or a mnemonic to get the balance for");
return;
}
let address = args
.address
.unwrap_or_else(|| address_from_mnemonic.expect("please provide a mnemonic"));
if args.from_mnemonic {
let prefix = client
.current_chain_details()
.bech32_account_prefix
.as_str();
get_pubkey_from_mnemonic(address, prefix, mnemonic.expect("mnemonic not set"));
return;
}
get_pubkey_from_chain(address, client).await;
}
pub fn get_pubkey_from_mnemonic(address: AccountId, prefix: &str, mnemonic: bip39::Mnemonic) {
match DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic) {
Ok(wallet) => match wallet.try_derive_accounts() {
Ok(accounts) => match accounts.iter().find(|a| *a.address() == address) {
Some(account) => {
println!("{}", account.public_key().to_string());
}
None => {
error!("Could not derive key that matches {}", address)
}
},
Err(e) => {
error!("Failed to derive accounts. {}", e);
}
},
Err(e) => show_error(e),
}
}
pub async fn get_pubkey_from_chain(address: AccountId, client: &QueryClient) {
info!("Getting public key for address {} from chain...", address);
match client.get_account_details(&address).await {
Ok(Some(account)) => {
if let Ok(base_account) = account.try_get_base_account() {
if let Some(pubkey) = base_account.pubkey {
println!("{}", pubkey.to_string());
} else {
println!("No account associated with address {}", address);
}
}
}
Ok(None) => {
println!("No account associated with address {}", address);
}
Err(e) => show_error(e),
}
}
@@ -1,66 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
use log::info;
use serde_json::json;
use validator_client::nymd::{AccountId, Coin};
use crate::context::SigningClient;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(value_parser, help = "The recipient account address")]
pub recipient: AccountId,
#[clap(
value_parser,
help = "Amount to transfer in micro denomination (e.g. unym or unyx)"
)]
pub amount: u128,
#[clap(long, help = "Override the denomination")]
pub denom: Option<String>,
#[clap(long)]
pub memo: Option<String>,
}
pub async fn send(args: Args, client: &SigningClient) {
let memo = args
.memo
.unwrap_or_else(|| "Sending tokens with nym-cli".to_owned());
let denom = args
.denom
.unwrap_or_else(|| client.current_chain_details().mix_denom.base.clone());
let coin = Coin {
denom,
amount: args.amount,
};
info!(
"Sending {} {} from {} to {}...",
coin.amount,
coin.denom,
client.address(),
args.recipient
);
let res = client
.send(&args.recipient, vec![coin], memo, None)
.await
.expect("failed to send tokens!");
info!("Sending result: {}", json!(res));
println!();
println!(
"Nodesguru: https://nym.explorers.guru/transaction/{}",
&res.hash
);
println!("Mintscan: https://www.mintscan.io/nyx/txs/{}", &res.hash);
println!("Transaction result code: {}", &res.tx_result.code.value());
println!("Transaction hash: {}", &res.hash);
}
@@ -1,23 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
use crate::context::QueryClient;
use crate::utils::show_error;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(value_parser)]
#[clap(help = "The block height")]
pub height: u32,
}
pub async fn query_for_block_time(args: Args, client: &QueryClient) {
match client.get_block_timestamp(Some(args.height)).await {
Ok(res) => {
println!("{}", res.to_rfc3339())
}
Err(e) => show_error(e),
}
}
@@ -1,19 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
use crate::context::QueryClient;
use crate::utils::show_error;
#[derive(Debug, Parser)]
pub struct Args {}
pub async fn query_current_block_height(client: &QueryClient) {
match client.get_current_block_height().await {
Ok(res) => {
println!("Current block height:\n{}", res.value())
}
Err(e) => show_error(e),
}
}
@@ -1,24 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
use crate::context::QueryClient;
use crate::utils::show_error;
use serde_json::json;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(value_parser)]
#[clap(help = "The block height")]
pub height: u32,
}
pub async fn query_for_block(args: Args, client: &QueryClient) {
match client.get_block(Some(args.height)).await {
Ok(res) => {
println!("{}", json!(res))
}
Err(e) => show_error(e),
}
}
@@ -1,25 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod block_time;
pub mod current_height;
pub mod get;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Block {
#[clap(subcommand)]
pub command: Option<BlockCommands>,
}
#[derive(Debug, Subcommand)]
pub enum BlockCommands {
/// Gets a block's details and prints as JSON
Get(crate::validator::block::get::Args),
/// Gets the block time at a height
Time(crate::validator::block::block_time::Args),
/// Gets the current block height
CurrentHeight(crate::validator::block::current_height::Args),
}
@@ -1,60 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use cosmrs::AccountId;
use log::{error, info};
use serde_json::{json, Value};
use validator_client::nymd::Coin;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(value_parser)]
#[clap(help = "The address of contract to execute")]
pub contract_address: AccountId,
#[clap(value_parser)]
#[clap(help = "JSON encoded method arguments")]
pub json_args: String,
#[clap(long)]
pub memo: Option<String>,
#[clap(
value_parser,
requires = "fundsDenom",
help = "Amount to supply as funds in micro denomination (e.g. unym or unyx)"
)]
pub funds: Option<u128>,
#[clap(long, requires = "funds", help = "Set the denomination for the funds")]
pub funds_denom: Option<String>,
}
pub async fn execute(args: Args, client: SigningClient) {
info!("Starting contract method execution!");
let json_args: Value =
serde_json::from_str(&args.json_args).expect("Unable to parse JSON args");
let memo = args
.memo
.unwrap_or_else(|| "nym-cli execute contract method".to_owned());
let funds = match args.funds {
Some(funds) => vec![Coin::new(
funds,
args.funds_denom.expect("denom for funds not set"),
)],
None => vec![],
};
match client
.execute(&args.contract_address, &json_args, None, memo, funds)
.await
{
Ok(res) => info!("SUCCESS ✅\n{}", json!(res)),
Err(e) => error!("FAILURE ❌\n{}", e),
}
}
@@ -1,78 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use cosmrs::{AccountId, Coin as CosmosCoin};
use log::info;
use network_defaults::NymNetworkDetails;
use validator_client::nymd::cosmwasm_client::types::{ContractCodeId, InstantiateOptions};
use validator_client::nymd::Coin;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(value_parser)]
pub code_id: ContractCodeId,
#[clap(long)]
pub memo: Option<String>,
#[clap(long)]
pub label: Option<String>,
#[clap(long)]
pub init_message: String,
#[clap(long)]
pub admin: Option<AccountId>,
#[clap(
long,
requires = "fundsDenom",
help = "Amount to supply as funds in micro denomination (e.g. unym or unyx)"
)]
pub funds: Option<u128>,
#[clap(long, requires = "funds", help = "Set the denomination for the funds")]
pub funds_denom: Option<String>,
}
pub async fn init(args: Args, client: SigningClient, network_details: &NymNetworkDetails) {
info!("Starting contract instantiation!");
let memo = args
.memo
.unwrap_or_else(|| "contract instantiation".to_owned());
let label = args
.label
.unwrap_or_else(|| "Nym mixnet smart contract".to_owned());
let funds: Vec<CosmosCoin> = match args.funds {
Some(funds) => vec![Coin::new(
funds,
args.funds_denom
.unwrap_or_else(|| network_details.chain_details.mix_denom.base.to_string()),
)
.into()],
None => vec![],
};
// by default we make ourselves an admin, let me know if you don't like that behaviour
let opts = Some(InstantiateOptions {
funds,
admin: Some(args.admin.unwrap_or_else(|| client.address().clone())),
});
let msg: serde_json::Value =
serde_json::from_str(&args.init_message).expect("failed to parse init message");
// the EmptyMsg{} argument is equivalent to `--init-message='{}'`
let res = client
.instantiate(args.code_id, &msg, label, memo, opts, None)
.await
.expect("failed to instantiate the contract!");
info!("Init result: {:?}", res);
println!("{}", res.contract_address)
}
@@ -1,28 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod execute_contract;
pub mod init_contract;
pub mod migrate_contract;
pub mod upload_contract;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Cosmwasm {
#[clap(subcommand)]
pub command: Option<CosmwasmCommands>,
}
#[derive(Debug, Subcommand)]
pub enum CosmwasmCommands {
/// Upload a smart contract WASM blob
Upload(crate::validator::cosmwasm::upload_contract::Args),
/// Init a WASM smart contract
Init(crate::validator::cosmwasm::init_contract::Args),
/// Migrate a WASM smart contract
Migrate(crate::validator::cosmwasm::migrate_contract::Args),
/// Execute a WASM smart contract method
Execute(crate::validator::cosmwasm::execute_contract::Args),
}
@@ -1,35 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod rewards;
pub mod delegate_to_mixnode;
pub mod query_for_delegations;
pub mod undelegate_from_mixnode;
pub mod vesting_delegate_to_mixnode;
pub mod vesting_undelegate_from_mixnode;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetDelegators {
#[clap(subcommand)]
pub command: MixnetDelegatorsCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetDelegatorsCommands {
/// Lists current delegations
List(query_for_delegations::Args),
/// Manage rewards from delegations
Rewards(rewards::MixnetDelegatorsReward),
/// Delegate to a mixnode
Delegate(delegate_to_mixnode::Args),
/// Undelegate from a mixnode
Undelegate(undelegate_from_mixnode::Args),
/// Delegate to a mixnode with locked tokens
DelegateVesting(vesting_delegate_to_mixnode::Args),
/// Undelegate from a mixnode (when originally using locked tokens)
UndelegateVesting(vesting_undelegate_from_mixnode::Args),
}
@@ -1,129 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
use log::info;
use crate::context::SigningClientWithValidatorAPI;
use crate::utils::{pretty_cosmwasm_coin, show_error_passthrough};
use comfy_table::Table;
use mixnet_contract_common::mixnode::DelegationEvent;
use mixnet_contract_common::Delegation;
#[derive(Debug, Parser)]
pub struct Args {}
pub async fn execute(_args: Args, client: SigningClientWithValidatorAPI) {
info!(
"Getting delegations for account {}...",
client.nymd.address()
);
let delegations = client
.get_all_delegator_delegations(client.nymd.address())
.await
.map_err(show_error_passthrough);
let mixnet_contract_events = client
.nymd
.get_pending_delegation_events(client.nymd.address().to_string(), None)
.await
.map_err(show_error_passthrough);
let vesting_contract = client.nymd.vesting_contract_address();
let vesting_contract_events = client
.nymd
.get_pending_delegation_events(
client.nymd.address().to_string(),
Some(vesting_contract.to_string()),
)
.await
.map_err(show_error_passthrough);
if let Ok(res) = delegations {
println!();
if res.is_empty() {
println!("This account has not delegated any tokens to mixnodes");
} else {
println!("Delegations:");
print_delegations(res, &client).await;
}
}
if let Ok(res) = mixnet_contract_events {
if !res.is_empty() {
println!();
println!("Pending delegations (liquid tokens):");
print_delegation_events(res, &client).await;
}
}
if let Ok(res) = vesting_contract_events {
if !res.is_empty() {
println!();
println!("Pending delegations (locked tokens):");
print_delegation_events(res, &client).await;
}
}
}
async fn to_iso_timestamp(block_height: u32, client: &SigningClientWithValidatorAPI) -> String {
match client.nymd.get_block_timestamp(Some(block_height)).await {
Ok(res) => res.to_rfc3339(),
Err(_e) => "-".to_string(),
}
}
async fn print_delegations(delegations: Vec<Delegation>, client: &SigningClientWithValidatorAPI) {
let mut table = Table::new();
table.set_header(vec!["Timestamp", "Identity Key", "Delegation", "Proxy"]);
for delegation in delegations {
table.add_row(vec![
to_iso_timestamp(delegation.block_height as u32, client).await,
delegation.node_identity.to_string(),
pretty_cosmwasm_coin(&delegation.amount),
format!("{:?}", delegation.proxy),
]);
}
println!("{table}");
}
async fn print_delegation_events(
events: Vec<DelegationEvent>,
client: &SigningClientWithValidatorAPI,
) {
let mut table = Table::new();
table.set_header(vec![
"Timestamp",
"Identity Key",
"Delegation",
"Event Type",
]);
for event in events {
match event {
DelegationEvent::Delegate(delegation) => {
table.add_row(vec![
to_iso_timestamp(delegation.block_height as u32, client).await,
delegation.node_identity.to_string(),
pretty_cosmwasm_coin(&delegation.amount),
"Delegate".to_string(),
]);
}
DelegationEvent::Undelegate(undelegate) => {
table.add_row(vec![
to_iso_timestamp(undelegate.block_height() as u32, client).await,
undelegate.mix_identity().to_string(),
"-".to_string(),
"Undelegate".to_string(),
]);
}
}
}
println!("{table}");
}
@@ -1,22 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod claim_delegator_reward;
pub mod vesting_claim_delegator_reward;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetDelegatorsReward {
#[clap(subcommand)]
pub command: MixnetDelegatorsRewardCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetDelegatorsRewardCommands {
/// Claim rewards accumulated during the delegation of unlocked tokens
Claim(claim_delegator_reward::Args),
/// Claim rewards accumulated during the delegation of locked tokens
VestingClaim(vesting_claim_delegator_reward::Args),
}
@@ -1,25 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod delegators;
pub mod operators;
pub mod query;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Mixnet {
#[clap(subcommand)]
pub command: MixnetCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetCommands {
/// Query the mixnet directory
Query(query::MixnetQuery),
/// Manage your delegations
Delegators(delegators::MixnetDelegators),
/// Manage a mixnode or gateway you operate
Operators(operators::MixnetOperators),
}
@@ -1,28 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod bond_gateway;
pub mod unbond_gateway;
pub mod vesting_bond_gateway;
pub mod vesting_unbond_gateway;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetOperatorsGateway {
#[clap(subcommand)]
pub command: MixnetOperatorsGatewayCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsGatewayCommands {
/// Bond to a gateway
Bond(bond_gateway::Args),
/// Unbound from a gateway
Unbound(unbond_gateway::Args),
/// Bond to a gateway with locked tokens
VestingBond(vesting_bond_gateway::Args),
/// Unbound from a gateway (when originally using locked tokens)
VestingUnbound(vesting_unbond_gateway::Args),
}
@@ -1,19 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod decode_mixnode_key;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetOperatorsMixnodeKeys {
#[clap(subcommand)]
pub command: MixnetOperatorsMixnodeKeysCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsMixnodeKeysCommands {
/// Decode a mixnode key
DecodeMixnodeKey(decode_mixnode_key::Args),
}
@@ -1,37 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod bond_mixnode;
pub mod keys;
pub mod rewards;
pub mod settings;
pub mod unbond_mixnode;
pub mod vesting_bond_mixnode;
pub mod vesting_unbond_mixnode;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetOperatorsMixnode {
#[clap(subcommand)]
pub command: MixnetOperatorsMixnodeCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsMixnodeCommands {
/// Operations for mixnode keys
Keys(keys::MixnetOperatorsMixnodeKeys),
/// Manage your mixnode operator rewards
Rewards(rewards::MixnetOperatorsMixnodeRewards),
/// Manage your mixnode settings stored in the directory
Settings(settings::MixnetOperatorsMixnodeSettings),
/// Bond to a mixnode
Bond(bond_mixnode::Args),
/// Unbound from a mixnode
Unbound(unbond_mixnode::Args),
/// Bond to a mixnode with locked tokens
BondVesting(vesting_bond_mixnode::Args),
/// Unbound from a mixnode (when originally using locked tokens)
UnboundVesting(vesting_unbond_mixnode::Args),
}
@@ -1,22 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod claim_operator_reward;
pub mod vesting_claim_operator_reward;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetOperatorsMixnodeRewards {
#[clap(subcommand)]
pub command: MixnetOperatorsMixnodeRewardsCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsMixnodeRewardsCommands {
/// Claim rewards
Claim(claim_operator_reward::Args),
/// Claim rewards for a mixnode bonded with locked tokens
VestingClaim(vesting_claim_operator_reward::Args),
}
@@ -1,22 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod update_profit_percent;
pub mod vesting_update_profit_percent;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetOperatorsMixnodeSettings {
#[clap(subcommand)]
pub command: MixnetOperatorsMixnodeSettingsCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsMixnodeSettingsCommands {
/// Update profit percentage
UpdateProfitPercentage(update_profit_percent::Args),
/// Update profit percentage for a mixnode bonded with locked tokens
VestingUpdateProfitPercentage(vesting_update_profit_percent::Args),
}
@@ -1,22 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod gateway;
pub mod mixnode;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetOperators {
#[clap(subcommand)]
pub command: MixnetOperatorsCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsCommands {
/// Manage your mixnode
Mixnode(mixnode::MixnetOperatorsMixnode),
/// Manage your gateway
Gateway(gateway::MixnetOperatorsGateway),
}
@@ -1,22 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod query_all_gateways;
pub mod query_all_mixnodes;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetQuery {
#[clap(subcommand)]
pub command: MixnetQueryCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetQueryCommands {
/// Query mixnodes
Mixnodes(query_all_mixnodes::Args),
/// Query gateways
Gateways(query_all_gateways::Args),
}
@@ -1,52 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
use comfy_table::Table;
use crate::context::QueryClientWithValidatorAPI;
use crate::utils::{pretty_cosmwasm_coin, show_error};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(value_parser)]
#[clap(help = "Optionally, the gateway to display")]
pub identity_key: Option<String>,
}
pub async fn query(args: Args, client: &QueryClientWithValidatorAPI) {
match client.validator_api.get_gateways().await {
Ok(res) => match args.identity_key {
Some(identity_key) => {
let node = res.iter().find(|node| {
node.gateway
.identity_key
.to_string()
.eq_ignore_ascii_case(&identity_key)
});
println!(
"{}",
::serde_json::to_string_pretty(&node).expect("json formatting error")
);
}
None => {
let mut table = Table::new();
table.set_header(vec!["Identity Key", "Owner", "Host", "Bond", "Version"]);
for node in res {
table.add_row(vec![
node.gateway.identity_key.to_string(),
node.owner.to_string(),
node.gateway.host.to_string(),
pretty_cosmwasm_coin(&node.pledge_amount),
node.gateway.version,
]);
}
println!("The gateways in the directory are:");
println!("{table}");
}
},
Err(e) => show_error(e),
}
}
@@ -1,60 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
use comfy_table::Table;
use crate::context::QueryClientWithValidatorAPI;
use crate::utils::{pretty_cosmwasm_coin, show_error};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(value_parser)]
#[clap(help = "Optionally, the mixnode to display")]
pub identity_key: Option<String>,
}
pub async fn query(args: Args, client: &QueryClientWithValidatorAPI) {
match client.validator_api.get_mixnodes().await {
Ok(res) => match args.identity_key {
Some(identity_key) => {
let node = res.iter().find(|node| {
node.mix_node
.identity_key
.to_string()
.eq_ignore_ascii_case(&identity_key)
});
println!(
"{}",
::serde_json::to_string_pretty(&node).expect("json formatting error")
);
}
None => {
let mut table = Table::new();
table.set_header(vec![
"Identity Key",
"Owner",
"Host",
"Bond",
"Total Delegations",
"Version",
]);
for node in res {
table.add_row(vec![
node.mix_node.identity_key.to_string(),
node.owner.to_string(),
node.mix_node.host.to_string(),
pretty_cosmwasm_coin(&node.pledge_amount),
pretty_cosmwasm_coin(&node.total_delegation()),
node.mix_node.version,
]);
}
println!("The mixnodes in the directory are:");
println!("{table}");
}
},
Err(e) => show_error(e),
}
}
-10
View File
@@ -1,10 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod account;
pub mod block;
pub mod cosmwasm;
pub mod mixnet;
pub mod signature;
pub mod transactions;
pub mod vesting;
@@ -1,13 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use thiserror::Error;
#[derive(Error, Debug)]
pub enum Errors {
#[error("signature error - {0}")]
SignatureError(#[from] k256::ecdsa::signature::Error),
#[error("{0}")]
CosmrsError(#[from] cosmrs::ErrorReport),
}
@@ -1,90 +0,0 @@
use std::str::FromStr;
use cosmrs::crypto::secp256k1::{Signature, VerifyingKey};
use cosmrs::crypto::PublicKey;
use k256::ecdsa::signature::Verifier;
use crate::validator::signature::errors::Errors;
pub fn secp256k1_verify_with_public_key(
public_key_as_bytes: &[u8],
signature_as_hex: String,
message: String,
) -> Result<(), k256::ecdsa::signature::Error> {
let verifying_key = VerifyingKey::from_sec1_bytes(public_key_as_bytes)?;
let signature = Signature::from_str(&signature_as_hex)?;
let message_as_bytes = message.into_bytes();
verifying_key.verify(&message_as_bytes, &signature)
}
pub fn secp256k1_verify_with_public_key_json(
public_key_as_json: String,
signature_as_hex: String,
message: String,
) -> Result<(), Errors> {
let public_key = PublicKey::from_json(&public_key_as_json)?;
let verifying_key = VerifyingKey::from_sec1_bytes(&public_key.to_bytes())?;
let signature = Signature::from_str(&signature_as_hex)?;
let message_as_bytes = message.into_bytes();
Ok(verifying_key.verify(&message_as_bytes, &signature)?)
}
#[cfg(test)]
mod test_secp256k1 {
use crate::validator::signature::helpers::{
secp256k1_verify_with_public_key, secp256k1_verify_with_public_key_json,
};
use cosmrs::crypto::PublicKey;
#[test]
fn test_verify_with_json_public_key_with_valid_signature() {
let json_public_key = r#"{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A4FdhUMasPmNhRZjtpKlmjNbq7EEUgPxfdI+E3vSajvc"}"#;
let signature_as_hex = "E3AA5AC0DA1B7DEBB7808000F719D8ACB9A0BE10AFA2756A788516268EB246A1257EC1097C5E364EF916145B01641DEDFE955994CB340BDAFA99A65BCA3F6F28".to_string();
let message = "test 1234".to_string();
let public_key = PublicKey::from_json(json_public_key).unwrap();
let public_key_bytes = public_key.to_bytes();
let result = secp256k1_verify_with_public_key(&public_key_bytes, signature_as_hex, message);
assert!(result.is_ok());
}
#[test]
fn test_verify_with_json_public_key_with_invalid_signature() {
let json_public_key = r#"{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A4FdhUMasPmNhRZjtpKlmjNbq7EEUgPxfdI+E3vSajvc"}"#;
let signature_as_hex = "E3AA5AC0DA1B7DEBB7808000F719D8ACB9A0BE10AFA2756A788516268EB246A1257EC1097C5E364EF916145B01641DEDFE955994CB340BDAFA99A65BCA3F6F28".to_string();
let message = "abcdef".to_string();
let public_key = PublicKey::from_json(json_public_key).unwrap();
let public_key_bytes = public_key.to_bytes();
let result = secp256k1_verify_with_public_key(&public_key_bytes, signature_as_hex, message);
assert!(result.is_err());
}
#[test]
fn test_valid_json_public_key_succeeds() {
let json_public_key = r#"{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A4FdhUMasPmNhRZjtpKlmjNbq7EEUgPxfdI+E3vSajvc"}"#.to_string();
let signature_as_hex = "E3AA5AC0DA1B7DEBB7808000F719D8ACB9A0BE10AFA2756A788516268EB246A1257EC1097C5E364EF916145B01641DEDFE955994CB340BDAFA99A65BCA3F6F28".to_string();
let message = "test 1234".to_string();
let result =
secp256k1_verify_with_public_key_json(json_public_key, signature_as_hex, message);
assert!(result.is_ok());
}
#[test]
fn test_json_public_key_fails_with_error() {
let bad_json_public_key = r#"This is not JSON ☠️"#.to_string();
let signature_as_hex = "E3AA5AC0DA1B7DEBB7808000F719D8ACB9A0BE10AFA2756A788516268EB246A1257EC1097C5E364EF916145B01641DEDFE955994CB340BDAFA99A65BCA3F6F28".to_string();
let message = "abcdef".to_string();
let result =
secp256k1_verify_with_public_key_json(bad_json_public_key, signature_as_hex, message);
assert!(result.is_err());
}
}
@@ -1,24 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod errors;
pub mod helpers;
pub mod sign;
pub mod verify;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Signature {
#[clap(subcommand)]
pub command: Option<SignatureCommands>,
}
#[derive(Debug, Subcommand)]
pub enum SignatureCommands {
/// Sign a message
Sign(crate::validator::signature::sign::Args),
/// Verify a message
Verify(crate::validator::signature::verify::Args),
}
@@ -1,68 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::utils::show_error;
use clap::Parser;
use cosmrs::crypto::PublicKey;
use log::error;
use serde::Serialize;
use serde_json::json;
use validator_client::nymd::wallet::DirectSecp256k1HdWallet;
#[derive(Debug, Serialize)]
pub struct SignatureOutputJson {
pub account_id: String,
pub public_key: PublicKey,
pub signature: String,
}
#[derive(Debug, Parser)]
pub struct Args {
#[clap(value_parser)]
#[clap(help = "The message to sign")]
pub message: String,
}
pub fn sign(args: Args, prefix: &str, mnemonic: Option<bip39::Mnemonic>) {
if args.message.trim().is_empty() {
error!("Message is empty or contains only whitespace");
return;
}
if mnemonic.is_none() {
error!(
"Please provide the mnemonic as an argument or using the MNEMONIC environment variable"
);
return;
}
match DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic.expect("mnemonic not set")) {
Ok(wallet) => match wallet.try_derive_accounts() {
Ok(accounts) => match accounts.first() {
Some(account) => {
let msg = args.message.into_bytes();
match wallet.sign_raw_with_account(account, &msg) {
Ok(signature) => {
let output = SignatureOutputJson {
account_id: account.address().to_string(),
public_key: account.public_key(),
signature: signature.to_string(),
};
println!("{}", json!(output));
}
Err(e) => {
error!("Failed to sign message. {}", e);
}
}
}
None => {
error!("Could not derive an account key from the mnemonic",)
}
},
Err(e) => {
error!("Failed to derive accounts. {}", e);
}
},
Err(e) => show_error(e),
}
}
@@ -1,89 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::str::FromStr;
use clap::Parser;
use cosmrs::crypto::PublicKey;
use log::{error, info};
use serde_json::json;
use validator_client::nymd::AccountId;
use crate::context::QueryClient;
use crate::validator::signature::helpers::secp256k1_verify_with_public_key;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(value_parser)]
#[clap(
help = "The public key of the account, or the account id to query for a public key (NOTE: the account must have signed a message stored on the chain for the public key record to exist)"
)]
pub public_key_or_address: String,
#[clap(value_parser)]
#[clap(help = "The signature to verify as hex")]
pub signature_as_hex: String,
#[clap(value_parser)]
#[clap(help = "The message to verify as a string")]
pub message: String,
}
pub async fn verify(args: Args, client: &QueryClient) {
if args.public_key_or_address.trim().is_empty() {
error!("Please ensure the public key or address is not empty or whitespace");
return;
}
let public_key = match AccountId::from_str(&args.public_key_or_address) {
Ok(address) => {
info!("Found account address instead of public key, so looking up public key for {} from chain", address);
match client.get_account_public_key(&address).await.ok() {
Some(public_key) => {
if let Some(k) = public_key {
info!("Found public key {}", json!(k));
}
public_key
}
None => {
error!(
"Address {} does not have a public key recorded on the chain. This is probably because the account has never signed a transaction.",
address
);
None
}
}
}
Err(_) => match PublicKey::from_json(&args.public_key_or_address) {
Ok(parsed) => Some(parsed),
Err(e) => {
error!("Public key should be JSON. Unable to parse: {}", e);
None
}
},
};
match public_key {
Some(public_key) => {
if public_key.type_url() != PublicKey::SECP256K1_TYPE_URL {
error!("Sorry, we only support secp256k1 public keys at the moment");
return;
}
match secp256k1_verify_with_public_key(
&public_key.to_bytes(),
args.signature_as_hex,
args.message,
) {
Ok(()) => println!("SUCCESS ✅ signature verified"),
Err(e) => {
error!("FAILURE ❌ Signature verification failed: {}", e);
}
}
}
None => {
error!("Unable to verify, as unable to get the public key");
}
}
}
@@ -1,28 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
use std::str::FromStr;
use crate::context::QueryClient;
use crate::utils::show_error;
use cosmrs::tx::Hash;
use serde_json::json;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(value_parser)]
#[clap(help = "The transaction hash")]
pub tx_hash: String,
}
pub async fn get(args: Args, client: &QueryClient) {
let hash = Hash::from_str(&args.tx_hash).expect("could not parse transaction hash");
match client.get_tx(hash).await {
Ok(res) => {
println!("{}", json!(res))
}
Err(e) => show_error(e),
}
}
@@ -1,22 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod get_transaction;
pub mod query_transactions;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Transactions {
#[clap(subcommand)]
pub command: Option<TransactionsCommands>,
}
#[derive(Debug, Subcommand)]
pub enum TransactionsCommands {
/// Get a transaction by hash or block height
Get(crate::validator::transactions::get_transaction::Args),
/// Query for transactions
Query(crate::validator::transactions::query_transactions::Args),
}
@@ -1,30 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::str::FromStr;
use clap::Parser;
use cosmrs::rpc::query::Query;
use serde_json::json;
use crate::context::QueryClient;
use crate::utils::show_error;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(value_parser)]
#[clap(help = "The query to execute")]
pub query: String,
}
pub async fn query(args: Args, client: &QueryClient) {
match Query::from_str(&args.query) {
Ok(query) => match client.search_tx(query).await {
Ok(res) => {
println!("{}", json!(res))
}
Err(e) => show_error(e),
},
Err(e) => show_error(e),
}
}
@@ -1,55 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
use cosmrs::AccountId;
use log::info;
use validator_client::nymd::{Coin, VestingQueryClient};
use crate::context::SigningClient;
use crate::utils::show_error;
use crate::utils::{pretty_coin, pretty_cosmwasm_coin};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(value_parser)]
#[clap(help = "Optionally, the account address to get the balance for")]
pub address: Option<AccountId>,
}
pub async fn balance(args: Args, client: SigningClient) {
let account_id = args.address.unwrap_or_else(|| client.address().clone());
let vesting_address = account_id.to_string();
let denom = client.current_chain_details().mix_denom.base.as_str();
info!(
"Getting vesting schedule information for {}...",
&vesting_address
);
let original_vesting = client.original_vesting(&vesting_address).await;
match original_vesting {
Ok(res) => {
let spendable_coins = client
.spendable_coins(&vesting_address, None)
.await
.unwrap_or_else(|_| Coin::new(0u128, denom));
let liquid_account_balance = client
.get_balance(&account_id, denom.to_string())
.await
.unwrap_or(None)
.unwrap_or_else(|| Coin::new(0u128, denom));
println!(
"Account {} has\n{} vested with\n{} available to be withdrawn to the main account (balance {})",
&account_id,
pretty_cosmwasm_coin(&res.amount),
pretty_coin(&spendable_coins),
pretty_coin(&liquid_account_balance),
);
}
Err(e) => show_error(e),
}
}
@@ -1,28 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod balance;
pub mod create_vesting_schedule;
pub mod query_vesting_schedule;
pub mod withdraw_vested;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct VestingSchedule {
#[clap(subcommand)]
pub command: Option<VestingScheduleCommands>,
}
#[derive(Debug, Subcommand)]
pub enum VestingScheduleCommands {
/// Creates a vesting schedule
Create(crate::validator::vesting::create_vesting_schedule::Args),
/// Query for vesting schedule
Query(crate::validator::vesting::query_vesting_schedule::Args),
/// Get the amount that has vested and is free for withdrawal, delegation or bonding
VestedBalance(crate::validator::vesting::balance::Args),
/// Withdraw vested tokens (note: the available amount excludes anything delegated or bonded before or after vesting)
WithdrawVested(crate::validator::vesting::withdraw_vested::Args),
}
@@ -1,149 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
use cosmrs::AccountId;
use cosmwasm_std::Coin as CosmWasmCoin;
use log::info;
use validator_client::nymd::{Coin, VestingQueryClient};
use crate::context::SigningClient;
use crate::utils::show_error;
use crate::utils::{pretty_coin, pretty_cosmwasm_coin};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(value_parser)]
#[clap(help = "Optionally, the account address to get the balance for")]
pub address: Option<AccountId>,
}
pub async fn query(args: Args, client: SigningClient) {
let account_id = args.address.unwrap_or_else(|| client.address().clone());
let vesting_address = account_id.to_string();
let denom = client.current_chain_details().mix_denom.base.as_str();
info!(
"Getting vesting schedule information for {}...",
&vesting_address
);
let liquid_account_balance = client
.get_balance(&account_id, denom.to_string())
.await
.unwrap_or(None)
.unwrap_or_else(|| Coin::new(0u128, denom));
let original_vesting = client.original_vesting(&vesting_address).await;
let start_time = client.vesting_start_time(&vesting_address).await;
let end_time = client.vesting_end_time(&vesting_address).await;
let vested_coins = client.vested_coins(&vesting_address, None).await;
let spendable_coins = client.spendable_coins(&vesting_address, None).await;
let locked_coins = client.locked_coins(&vesting_address, None).await;
// TODO: get better copy text for what these are
let vesting_coins = client.vesting_coins(&vesting_address, None).await;
let delegated_vesting = client.delegated_vesting(&vesting_address, None).await;
let delegated_free = client.delegated_free(&vesting_address, None).await;
original_vesting.as_ref().map_or_else(show_error, |res| {
println!(
"Amount: {} ({})",
pretty_cosmwasm_coin(&res.amount),
res.amount
);
println!("No of periods: {}", res.number_of_periods);
println!(
"Duration each: {}",
time::Duration::seconds(res.period_duration as i64)
);
});
start_time.as_ref().map_or_else(show_error, |res| {
println!(
"Start date: {}",
time::OffsetDateTime::from_unix_timestamp(res.seconds() as i64)
.expect("unable to parse vesting start timestamp")
.date()
);
});
end_time.map_or_else(show_error, |res| {
println!(
"End date: {}",
time::OffsetDateTime::from_unix_timestamp(res.seconds() as i64)
.expect("unable to parse vesting end timestamp")
.date()
);
});
vested_coins.map_or_else(show_error, |res| {
println!("Vested balance: {} ({})", pretty_coin(&res), res);
});
if let Ok(res) = original_vesting {
if let Ok(start) = start_time {
let amount_in_each_period = res.amount.amount.u128() / res.number_of_periods as u128;
let coin_in_each_period = CosmWasmCoin::new(amount_in_each_period, denom);
println!();
println!("Vesting schedule:");
for period in 1..(res.number_of_periods as u64 + 1) {
let date = time::OffsetDateTime::from_unix_timestamp(
(start.seconds() + period * res.period_duration) as i64,
)
.expect("unable to parse vesting start timestamp")
.date();
let amount_in_vested =
period as u128 * res.amount.amount.u128() / res.number_of_periods as u128;
let coin_in_vested = CosmWasmCoin::new(amount_in_vested, denom);
println!(
"{}. {} {} => {}",
period,
date,
pretty_cosmwasm_coin(&coin_in_each_period),
pretty_cosmwasm_coin(&coin_in_vested),
);
}
}
}
spendable_coins.map_or_else(show_error, |res| {
println!();
println!("This account has the following vested tokens available either to be withdrawn to the main account, or to be delegated:");
println!("Spendable coins: {} ({})", pretty_coin(&res), res);
});
locked_coins.map_or_else(show_error, |res| {
println!();
if res.amount > 0 {
println!("This account has delegated more than the current cap, so the following balance is unavailable for bonding or delegation:");
println!("Locked balance: {} ({})", pretty_coin(&res), res);
} else {
println!("This account is not capped and can use the spendable balance for bonding or delegations:");
println!("Locked balance: {} ({})", pretty_coin(&res), res);
}
});
println!();
println!("The following are shown for information (more help text will follow soon):");
vesting_coins.map_or_else(show_error, |res| {
println!("Vesting coins: {} ({})", pretty_coin(&res), res);
});
delegated_vesting.map_or_else(show_error, |res| {
println!("Delegated vesting: {} ({})", pretty_coin(&res), res);
});
delegated_free.map_or_else(show_error, |res| {
println!("Delegation free: {} ({})", pretty_coin(&res), res);
});
println!();
println!(
"The main account {} also has a regular balance of:",
&account_id
);
println!(
"{} ({})",
pretty_coin(&liquid_account_balance),
&liquid_account_balance
);
}
@@ -1,112 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
use log::info;
use validator_client::nymd::{Coin, VestingQueryClient, VestingSigningClient};
use crate::context::SigningClient;
use crate::utils::show_error;
use crate::utils::{pretty_coin, pretty_cosmwasm_coin};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(value_parser)]
#[clap(help = "Amount to transfer in micro denomination (e.g. unym or unyx)")]
pub amount: u128,
}
pub async fn execute(args: Args, client: SigningClient) {
let account_id = client.address();
let vesting_address = account_id.to_string();
let denom = client.current_chain_details().mix_denom.base.as_str();
info!(
"Getting vesting schedule information for {}...",
&vesting_address
);
let original_vesting = client.original_vesting(&vesting_address).await;
match original_vesting {
Ok(res) => {
let spendable_coins = client
.spendable_coins(&vesting_address, None)
.await
.unwrap_or_else(|_| Coin::new(0u128, denom));
let liquid_account_balance = client
.get_balance(account_id, denom.to_string())
.await
.unwrap_or(None)
.unwrap_or_else(|| Coin::new(0u128, denom));
println!(
"Account {} has\n{} vested with {} available to be withdrawn to the main account (balance {})",
&account_id,
pretty_cosmwasm_coin(&res.amount),
pretty_coin(&spendable_coins),
pretty_coin(&liquid_account_balance),
);
println!();
// execute withdraw
let amount = Coin {
amount: args.amount,
denom: denom.to_string(),
};
info!(
"Withdrawing {} ({}) from {}...",
pretty_coin(&amount),
&amount,
&account_id
);
match client.withdraw_vested_coins(amount, None).await {
Ok(res) => {
println!();
println!("SUCCESS ✅");
println!(
"Nodesguru: https://nym.explorers.guru/transaction/{}",
&res.transaction_hash
);
println!(
"Mintscan: https://www.mintscan.io/nyx/txs/{}",
&res.transaction_hash
);
println!("Transaction hash: {}", &res.transaction_hash);
println!("Gas used: {}", &res.gas_info.gas_used);
println!();
}
Err(e) => show_error(e),
}
// query for balances again
let res = client
.original_vesting(&vesting_address)
.await
.expect("vesting account does not exist");
let spendable_coins = client
.spendable_coins(&vesting_address, None)
.await
.unwrap_or_else(|_| Coin::new(0u128, denom));
let liquid_account_balance = client
.get_balance(account_id, denom.to_string())
.await
.unwrap_or(None)
.unwrap_or_else(|| Coin::new(0u128, denom));
println!(
"After withdrawal, account {} has\n{} vested with {} available to be withdrawn to the main account (balance {})",
&account_id,
pretty_cosmwasm_coin(&res.amount),
pretty_coin(&spendable_coins),
pretty_coin(&liquid_account_balance),
);
}
Err(e) => show_error(e),
}
}
-35
View File
@@ -41,30 +41,6 @@ pub trait NymConfig: Default + Serialize + DeserializeOwned {
Self::default_config_directory(id).join(Self::config_file_name())
}
// We provide a second set of functions that tries to not panic.
fn try_default_root_directory() -> Option<PathBuf>;
fn try_default_config_directory(id: Option<&str>) -> Option<PathBuf> {
if let Some(id) = id {
Self::try_default_root_directory().map(|d| d.join(id).join("config"))
} else {
Self::try_default_root_directory().map(|d| d.join("config"))
}
}
fn try_default_data_directory(id: Option<&str>) -> Option<PathBuf> {
if let Some(id) = id {
Self::try_default_root_directory().map(|d| d.join(id).join("data"))
} else {
Self::try_default_root_directory().map(|d| d.join("data"))
}
}
fn try_default_config_file_path(id: Option<&str>) -> Option<PathBuf> {
Self::try_default_config_directory(id).map(|d| d.join(Self::config_file_name()))
}
fn root_directory(&self) -> PathBuf;
fn config_directory(&self) -> PathBuf;
fn data_directory(&self) -> PathBuf;
@@ -112,14 +88,3 @@ pub trait NymConfig: Default + Serialize + DeserializeOwned {
.map_err(|toml_err| io::Error::new(io::ErrorKind::Other, toml_err))
}
}
pub fn parse_validators(raw: &str) -> Vec<url::Url> {
raw.split(',')
.map(|raw_validator| {
raw_validator
.trim()
.parse()
.expect("one of the provided validator api urls is invalid")
})
.collect()
}
@@ -37,7 +37,7 @@ impl SpendCredentialData {
}
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
pub enum SpendCredentialStatus {
InProgress,
Spent,
@@ -166,7 +166,6 @@ pub mod fixed_U128_as_string {
use super::U128;
use serde::de::Error;
use serde::Deserialize;
#[allow(unused_imports)]
use std::str::FromStr;
pub fn serialize<S>(val: &U128, serializer: S) -> Result<S::Ok, S::Error>
@@ -2,9 +2,8 @@
// SPDX-License-Identifier: Apache-2.0
use crate::reward_params::NodeRewardParams;
use crate::{ContractStateParams, Layer, SphinxKey};
use crate::ContractStateParams;
use crate::{Gateway, IdentityKey, MixNode};
use cosmwasm_std::{Addr, Coin};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
@@ -123,10 +122,6 @@ pub enum ExecuteMsg {
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
GetAllDelegationValuesPaged {
start_after: Option<(IdentityKey, Vec<u8>, u64)>,
limit: Option<u32>,
},
GetBlacklistedNodes {},
GetCurrentOperatorCost {},
GetRewardingValidatorAddress {},
@@ -218,150 +213,20 @@ pub enum QueryMsg {
},
}
// all of those `serde rename` are here to reduce the rpc response size to bare minimum
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
#[serde(rename = "op")]
pub enum V2MigrationOperation {
#[serde(rename = "m1")]
MigrateOperator {
#[serde(rename = "a1")]
node_identity: String,
},
pub struct MigrateMsg {
pub mixnet_denom: String,
nodes_to_remove: Option<Vec<NodeToRemove>>,
}
#[serde(rename = "m2")]
MigrateDelegator {
#[serde(rename = "a1")]
address: Addr,
#[serde(rename = "a2")]
node_identity: String,
#[serde(rename = "a3")]
proxy: Option<Addr>,
#[serde(rename = "a4")]
new_mix_id: Option<u32>,
},
#[serde(rename = "m3")]
RemoveOperator {
#[serde(rename = "a1")]
node_identity: String,
},
#[serde(rename = "m4")]
RemoveDelegator {
#[serde(rename = "a1")]
address: Addr,
#[serde(rename = "a2")]
node_identity: String,
#[serde(rename = "a3")]
proxy: Option<Addr>,
},
#[serde(rename = "m5")]
MigrateGateway {
#[serde(rename = "a1")]
node_identity: String,
},
#[serde(rename = "m6")]
RemoveGateway {
#[serde(rename = "a1")]
node_identity: String,
},
impl MigrateMsg {
pub fn nodes_to_remove(&self) -> Vec<NodeToRemove> {
self.nodes_to_remove.clone().unwrap_or_default()
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum SpecialV2ExecuteMsg {
#[serde(rename = "m1")]
SaveOperator {
#[serde(rename = "a1")]
host: String,
#[serde(rename = "a2")]
mix_port: u16,
#[serde(rename = "a3")]
verloc_port: u16,
#[serde(rename = "a4")]
http_api_port: u16,
#[serde(rename = "a5")]
sphinx_key: SphinxKey,
#[serde(rename = "a6")]
identity_key: IdentityKey,
#[serde(rename = "a7")]
version: String,
#[serde(rename = "a8")]
pledge_amount: Coin,
#[serde(rename = "a9")]
owner: Addr,
#[serde(rename = "a10")]
block_height: u64,
#[serde(rename = "a11")]
profit_margin_percent: u8,
#[serde(rename = "a12")]
proxy: Option<Addr>,
},
#[serde(rename = "m2")]
SaveDelegation {
#[serde(rename = "a1")]
owner: Addr,
#[serde(rename = "a2")]
mix_id: u32,
#[serde(rename = "a3")]
amount: Coin,
#[serde(rename = "a4")]
block_height: u64,
#[serde(rename = "a5")]
proxy: Option<Addr>,
},
#[serde(rename = "m3")]
SaveGateway {
#[serde(rename = "a1")]
pledge_amount: Coin,
#[serde(rename = "a2")]
owner: Addr,
#[serde(rename = "a3")]
block_height: u64,
#[serde(rename = "a4")]
gateway: Gateway,
#[serde(rename = "a5")]
proxy: Option<Addr>,
},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct MigrateMsg {
pub v2_contract_address: String,
pub vesting_contract_address: String,
pub operations: Vec<V2MigrationOperation>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct NodeToRemove {
owner: String,
proxy: Option<String>,
@@ -1,11 +1,10 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::{Addr, Coin, Timestamp, Uint128};
use cosmwasm_std::{Coin, Timestamp};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
pub use messages::{ExecuteMsg, InitMsg, MigrateMsg, QueryMsg};
use mixnet_contract_common::IdentityKey;
pub mod events;
pub mod messages;
@@ -74,35 +73,3 @@ impl OriginalVestingResponse {
}
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, JsonSchema)]
pub struct VestingDelegation {
pub account_id: u32,
pub mix_identity: IdentityKey,
pub block_timestamp: u64,
pub amount: Uint128,
}
impl VestingDelegation {
pub fn storage_key(&self) -> (u32, IdentityKey, u64) {
(
self.account_id,
self.mix_identity.clone(),
self.block_timestamp,
)
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, JsonSchema)]
pub struct DelegationTimesResponse {
pub owner: Addr,
pub account_id: u32,
pub mix_identity: IdentityKey,
pub delegation_timestamps: Vec<u64>,
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, JsonSchema)]
pub struct AllDelegationsResponse {
pub delegations: Vec<VestingDelegation>,
pub start_next_after: Option<(u32, IdentityKey, u64)>,
}
@@ -12,7 +12,9 @@ pub struct InitMsg {
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct MigrateMsg {}
pub struct MigrateMsg {
pub mix_denom: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, Default)]
pub struct VestingSpecification {
@@ -117,12 +119,6 @@ pub enum ExecuteMsg {
UpdateLockedPledgeCap {
amount: Uint128,
},
AuthorisedUpdateToV2 {
owner: String,
node_identity: IdentityKey,
mix_id: u32,
},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
@@ -174,12 +170,4 @@ pub enum QueryMsg {
address: String,
},
GetLockedPledgeCap {},
GetDelegationTimes {
address: String,
mix_identity: IdentityKey,
},
GetAllDelegations {
start_after: Option<(u32, IdentityKey, u64)>,
limit: Option<u32>,
},
}
-11
View File
@@ -1,11 +0,0 @@
[package]
name = "inclusion-probability"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
log = "0.4.17"
rand = "0.8.5"
thiserror = "1.0.32"
-11
View File
@@ -1,11 +0,0 @@
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("The list of cumulative stake was unexpectedly empty")]
EmptyListCumulStake,
#[error("Sample point was unexpectedly out of bounds")]
SamplePointOutOfBounds,
#[error("Norm computation failed on different size arrays")]
NormDifferenceSizeArrays,
#[error("Computed probabilities are fewer than input number of nodes")]
ResultsShorterThanInput,
}
-426
View File
@@ -1,426 +0,0 @@
//! Active set inclusion probability simulator
use std::time::{Duration, Instant};
use error::Error;
use rand::Rng;
mod error;
const TOLERANCE_L2_NORM: f64 = 1e-4;
const TOLERANCE_MAX_NORM: f64 = 1e-4;
pub struct SelectionProbability {
pub active_set_probability: Vec<f64>,
pub reserve_set_probability: Vec<f64>,
pub samples: u64,
pub time: Duration,
pub delta_l2: f64,
pub delta_max: f64,
}
pub fn simulate_selection_probability_mixnodes<R>(
list_stake_for_mixnodes: &[u128],
active_set_size: usize,
reserve_set_size: usize,
max_samples: u64,
max_time: Duration,
rng: &mut R,
) -> Result<SelectionProbability, Error>
where
R: Rng + ?Sized,
{
log::trace!("Simulating mixnode active set selection probability");
// In case the active set size is larger than the number of bonded mixnodes, they all have 100%
// chance we don't have to go through with the simulation
if list_stake_for_mixnodes.len() <= active_set_size {
return Ok(SelectionProbability {
active_set_probability: vec![1.0; list_stake_for_mixnodes.len()],
reserve_set_probability: vec![0.0; list_stake_for_mixnodes.len()],
samples: 0,
time: Duration::ZERO,
delta_l2: 0.0,
delta_max: 0.0,
});
}
// Total number of existing (registered) nodes
let num_mixnodes = list_stake_for_mixnodes.len();
// Cumulative stake ordered by node index
let list_cumul = cumul_sum(list_stake_for_mixnodes);
// The computed probabilities
let mut active_set_probability = vec![0.0; num_mixnodes];
let mut reserve_set_probability = vec![0.0; num_mixnodes];
// Number sufficiently large to have a good approximation of selection probability
let mut samples = 0;
let mut delta_l2;
let mut delta_max;
// Make sure we bound the time we allow it to run
let start_time = Instant::now();
loop {
samples += 1;
let mut sample_active_mixnodes = Vec::new();
let mut sample_reserve_mixnodes = Vec::new();
let mut list_cumul_temp = list_cumul.clone();
let active_set_probability_previous = active_set_probability.clone();
// Select the active nodes for the epoch (hour)
while sample_active_mixnodes.len() < active_set_size
&& sample_active_mixnodes.len() < list_cumul_temp.len()
{
let candidate = sample_candidate(&list_cumul_temp, rng)?;
if !sample_active_mixnodes.contains(&candidate) {
sample_active_mixnodes.push(candidate);
remove_mixnode_from_cumul_stake(candidate, &mut list_cumul_temp);
}
}
// Select the reserve nodes for the epoch (hour)
while sample_reserve_mixnodes.len() < reserve_set_size
&& sample_reserve_mixnodes.len() + sample_active_mixnodes.len() < list_cumul_temp.len()
{
let candidate = sample_candidate(&list_cumul_temp, rng)?;
if !sample_reserve_mixnodes.contains(&candidate)
&& !sample_active_mixnodes.contains(&candidate)
{
sample_reserve_mixnodes.push(candidate);
remove_mixnode_from_cumul_stake(candidate, &mut list_cumul_temp);
}
}
// Sum up nodes being in active or reserve set
for active_mixnodes in sample_active_mixnodes {
active_set_probability[active_mixnodes] += 1.0;
}
for reserve_mixnodes in sample_reserve_mixnodes {
reserve_set_probability[reserve_mixnodes] += 1.0;
}
// Convergence critera only on active set.
// We devide by samples to get the average, that is not really part of the delta
// computation.
delta_l2 =
l2_diff(&active_set_probability, &active_set_probability_previous)? / (samples as f64);
delta_max =
max_diff(&active_set_probability, &active_set_probability_previous)? / (samples as f64);
if samples > 10 && delta_l2 < TOLERANCE_L2_NORM && delta_max < TOLERANCE_MAX_NORM
|| samples >= max_samples
{
break;
}
// Stop if we run out of time
if start_time.elapsed() > max_time {
log::debug!("Simulation ran out of time, stopping");
break;
}
}
// Divide occurrences with the number of samples once we're done to get the probabilities.
active_set_probability
.iter_mut()
.for_each(|x| *x /= samples as f64);
reserve_set_probability
.iter_mut()
.for_each(|x| *x /= samples as f64);
// Some sanity checks of the output
if active_set_probability.len() != num_mixnodes || reserve_set_probability.len() != num_mixnodes
{
return Err(Error::ResultsShorterThanInput);
}
Ok(SelectionProbability {
active_set_probability,
reserve_set_probability,
samples,
time: start_time.elapsed(),
delta_l2,
delta_max,
})
}
// Compute the cumulative sum
fn cumul_sum<'a>(list: impl IntoIterator<Item = &'a u128>) -> Vec<u128> {
let mut list_cumul = Vec::new();
let mut cumul = 0;
for entry in list {
cumul += entry;
list_cumul.push(cumul);
}
list_cumul
}
fn sample_candidate<R>(list_cumul: &[u128], rng: &mut R) -> Result<usize, Error>
where
R: Rng + ?Sized,
{
use rand::distributions::{Distribution, Uniform};
let uniform = Uniform::from(0..*list_cumul.last().ok_or(Error::EmptyListCumulStake)?);
let r = uniform.sample(rng);
let candidate = list_cumul
.iter()
.enumerate()
.find(|(_, x)| *x >= &r)
.ok_or(Error::SamplePointOutOfBounds)?
.0;
Ok(candidate)
}
// Update list of cumulative stake to reflect eliminating the picked node
fn remove_mixnode_from_cumul_stake(candidate: usize, list_cumul_stake: &mut [u128]) {
let prob_candidate = if candidate == 0 {
list_cumul_stake[0]
} else {
list_cumul_stake[candidate] - list_cumul_stake[candidate - 1]
};
for cumul in list_cumul_stake.iter_mut().skip(candidate) {
*cumul -= prob_candidate;
}
}
// Compute the difference in l2-norm
fn l2_diff(v1: &[f64], v2: &[f64]) -> Result<f64, Error> {
if v1.len() != v2.len() {
return Err(Error::NormDifferenceSizeArrays);
}
Ok(v1
.iter()
.zip(v2)
.map(|(&i1, &i2)| (i1 - i2).powi(2))
.sum::<f64>()
.sqrt())
}
// Compute the difference in max-norm
fn max_diff(v1: &[f64], v2: &[f64]) -> Result<f64, Error> {
if v1.len() != v2.len() {
return Err(Error::NormDifferenceSizeArrays);
}
Ok(v1
.iter()
.zip(v2)
.map(|(x, y)| (x - y).abs())
.fold(f64::NEG_INFINITY, f64::max))
}
#[cfg(test)]
mod tests {
use rand::{rngs::StdRng, SeedableRng};
use super::*;
fn test_rng() -> StdRng {
StdRng::seed_from_u64(42)
}
#[test]
fn compute_cumul_sum() {
let v = cumul_sum(&vec![1, 2, 3]);
assert_eq!(v, &[1, 3, 6]);
}
#[test]
fn remove_mixnode_from_cumul() {
let mut cumul_stake = vec![1, 2, 3, 4, 5, 6];
remove_mixnode_from_cumul_stake(3, &mut cumul_stake);
assert_eq!(cumul_stake, &[1, 2, 3, 3, 4, 5]);
}
#[test]
fn max_norm() {
let v1 = vec![1.0, 2.0, 3.0];
let v2 = vec![2.0, 4.0, -6.0];
assert!((max_diff(&v1, &v2).unwrap() - 9.0).abs() < f64::EPSILON);
}
#[test]
fn ls_norm() {
let v1 = vec![1.0, 2.0, 3.0];
let v2 = vec![2.0, 3.0, -2.0];
assert!((l2_diff(&v1, &v2).unwrap() - 5.196_152_422_706_632).abs() < 1e2 * f64::EPSILON);
}
// Replicate the results from the Python simulation code in https://github.com/nymtech/team-core/issues/114
#[test]
fn replicate_python_simulation() {
let active_set_size = 4;
let standby_set_size = 1;
// this has to contain the total stake per node
let list_mix = vec![
100, 100, 3000, 500_000, 100, 10, 10, 10, 10, 10, 30000, 500, 200, 52345,
];
let max_samples = 100_000;
let max_time = Duration::from_secs(10);
let mut rng = test_rng();
let SelectionProbability {
active_set_probability,
reserve_set_probability,
samples,
time,
delta_l2,
delta_max,
} = simulate_selection_probability_mixnodes(
&list_mix,
active_set_size,
standby_set_size,
max_samples,
max_time,
&mut rng,
)
.unwrap();
// Check that any possible test failure wasn't because we ran it on 1970s hardware, and the
// sampling aborted prematurely due to hitting `max_time`.
assert!(time < max_time);
// These values comes from running the python simulator for a very long time
let expected_active_set_probability = vec![
0.025_070_8,
0.025_073_2,
0.744_117,
0.999_999,
0.025_000_2,
0.002_524_4,
0.002_527_8,
0.002_528_6,
0.002_569_6,
0.002_513_6,
0.994,
0.125_482_8,
0.050_279_8,
0.998_313_2,
];
// The same check is used in the convergence criterion, and hence should be reflected in
// `delta_max` too.
assert!(
max_diff(&active_set_probability, &expected_active_set_probability).unwrap() < 1e-2
);
let expected_reserve_set_probability = vec![
0.076_392_4,
0.076_499,
0.204_893_6,
1e-06,
0.076_278_8,
0.007_720_6,
0.007_673,
0.007_700_2,
0.007_669_4,
0.007_731_2,
0.005_789_4,
0.368_465_6,
0.151_537_2,
0.001_648_6,
];
assert!(
max_diff(&reserve_set_probability, &expected_reserve_set_probability).unwrap() < 1e-2
);
// We converge around 20_000, add another 500 for some slack due to random values
assert_eq!(samples, 20_001);
assert!(delta_l2 < TOLERANCE_L2_NORM);
assert!(delta_max < TOLERANCE_MAX_NORM);
}
#[test]
fn fewer_nodes_than_active_set_size() {
let active_set_size = 10;
let standby_set_size = 3;
let list_mix = vec![100, 100, 3000];
let max_samples = 100_000;
let max_time = Duration::from_secs(10);
let mut rng = test_rng();
let SelectionProbability {
active_set_probability,
reserve_set_probability,
samples,
time: _,
delta_l2,
delta_max,
} = simulate_selection_probability_mixnodes(
&list_mix,
active_set_size,
standby_set_size,
max_samples,
max_time,
&mut rng,
)
.unwrap();
// These values comes from running the python simulator for a very long time
let expected_active_set_probability = vec![1.0, 1.0, 1.0];
let expected_reserve_set_probability = vec![0.0, 0.0, 0.0];
assert!(
max_diff(&active_set_probability, &expected_active_set_probability).unwrap()
< 1e1 * f64::EPSILON
);
assert!(
max_diff(&reserve_set_probability, &expected_reserve_set_probability).unwrap()
< 1e1 * f64::EPSILON
);
// We converge around 20_000, add another 500 for some slack due to random values
assert_eq!(samples, 0);
assert!(delta_l2 < f64::EPSILON);
assert!(delta_max < f64::EPSILON);
}
#[test]
fn fewer_nodes_than_reward_set_size() {
let active_set_size = 4;
let standby_set_size = 3;
let list_mix = vec![100, 100, 3000, 342, 3_498_234];
let max_samples = 100_000_000;
let max_time = Duration::from_secs(10);
let mut rng = test_rng();
let SelectionProbability {
active_set_probability,
reserve_set_probability,
samples,
time: _,
delta_l2,
delta_max,
} = simulate_selection_probability_mixnodes(
&list_mix,
active_set_size,
standby_set_size,
max_samples,
max_time,
&mut rng,
)
.unwrap();
// These values comes from running the python simulator for a very long time
let expected_active_set_probability = vec![0.546, 0.538, 0.999, 0.915, 1.0];
let expected_reserve_set_probability = vec![0.453, 0.461, 0.0005, 0.084, 0.0];
assert!(
max_diff(&active_set_probability, &expected_active_set_probability).unwrap() < 1e-2,
);
assert!(
max_diff(&reserve_set_probability, &expected_reserve_set_probability).unwrap() < 1e-2,
);
// We converge around 20_000, add another 500 for some slack due to random values
assert_eq!(samples, 20_001);
assert!(delta_l2 < TOLERANCE_L2_NORM);
assert!(delta_max < TOLERANCE_MAX_NORM);
}
}
+1 -1
View File
@@ -24,7 +24,7 @@ pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
hex_literal::hex!("0000000000000000000000000000000000000000");
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy";
pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "https://mainnet-stats.nymte.ch:8090/";
pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "http://127.0.0.1:8090";
pub const NYMD_VALIDATOR: &str = "https://rpc.nyx.nodes.guru/";
pub const API_VALIDATOR: &str = "https://validator.nymtech.net/api/";
pub(crate) fn validators() -> Vec<ValidatorDetails> {
+1 -1
View File
@@ -42,7 +42,7 @@ pub enum CoconutError {
)]
DeserializationMinLength { min: usize, actual: usize },
#[error("Tried to deserialize {object} with bytes of invalid length. Expected {actual} < {object} or {modulus_target} % {modulus} == 0")]
#[error("Tried to deserialize {object} with bytes of invalid length. Expected {actual} < {} or {modulus_target} % {modulus} == 0")]
DeserializationInvalidLength {
actual: usize,
target: usize,
+6 -4
View File
@@ -213,7 +213,7 @@ where
/// - compute vk_b = g^x || v_b
/// - compute sphinx_plaintext = SURB_ACK || g^x || v_b
/// - compute sphinx_packet = Sphinx(recipient, sphinx_plaintext)
pub fn prepare_chunk_for_sending(
pub async fn prepare_chunk_for_sending(
&mut self,
fragment: Fragment,
topology: &NymTopology,
@@ -222,7 +222,8 @@ where
) -> Result<PreparedFragment, NymTopologyError> {
// create an ack
let (ack_delay, surb_ack_bytes) = self
.generate_surb_ack(fragment.fragment_identifier(), topology, ack_key)?
.generate_surb_ack(fragment.fragment_identifier(), topology, ack_key)
.await?
.prepare_for_sending();
// TODO:
@@ -293,7 +294,7 @@ where
}
/// Construct an acknowledgement SURB for the given [`FragmentIdentifier`]
fn generate_surb_ack(
async fn generate_surb_ack(
&mut self,
fragment_id: FragmentIdentifier,
topology: &NymTopology,
@@ -356,7 +357,8 @@ where
// gateways could not distinguish reply packets from normal messages due to lack of said acks
// note: the ack delay is irrelevant since we do not know the delay of actual surb
let (_, surb_ack_bytes) = self
.generate_surb_ack(reply_id, topology, ack_key)?
.generate_surb_ack(reply_id, topology, ack_key)
.await?
.prepare_for_sending();
let zero_pad_len = self.packet_size.plaintext_size()
-1
View File
@@ -9,4 +9,3 @@ edition = "2021"
[dependencies]
nymsphinx-addressing = { path = "../../../common/nymsphinx/addressing" }
ordered-buffer = {path = "../ordered-buffer"}
thiserror = "1"
-5
View File
@@ -1,12 +1,7 @@
// Copyright 2020-2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod msg;
pub mod network_requester_response;
pub mod request;
pub mod response;
pub use msg::*;
pub use network_requester_response::*;
pub use request::*;
pub use response::*;
+13 -26
View File
@@ -1,40 +1,36 @@
// Copyright 2020-2022 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use thiserror::Error;
use crate::network_requester_response::{Error as NrError, NetworkRequesterResponse};
use crate::request::{Request, RequestError};
use crate::response::{Response, ResponseError};
#[derive(Debug, Error)]
#[derive(Debug)]
pub enum MessageError {
#[error("{0}")]
Request(RequestError),
#[error("{0:?}")]
Response(ResponseError),
#[error("{0}")]
NetworkRequesterResponseError(NrError),
#[error("no data")]
NoData,
#[error("unknown message type received")]
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),
NetworkRequesterResponse(NetworkRequesterResponse),
}
impl Message {
const REQUEST_FLAG: u8 = 0;
const RESPONSE_FLAG: u8 = 1;
const NR_RESPONSE_FLAG: u8 = 2;
pub fn conn_id(&self) -> u64 {
match self {
@@ -43,7 +39,6 @@ impl Message {
Request::Send(conn_id, _, _) => *conn_id,
},
Message::Response(resp) => resp.connection_id,
Message::NetworkRequesterResponse(resp) => resp.connection_id,
}
}
@@ -54,7 +49,6 @@ impl Message {
Request::Send(_, data, _) => data.len(),
},
Message::Response(resp) => resp.data.len(),
Message::NetworkRequesterResponse(_) => 0,
}
}
@@ -71,10 +65,6 @@ impl Message {
Response::try_from_bytes(&b[1..])
.map(Message::Response)
.map_err(MessageError::Response)
} else if b[0] == Self::NR_RESPONSE_FLAG {
NetworkRequesterResponse::try_from_bytes(&b[1..])
.map(Message::NetworkRequesterResponse)
.map_err(MessageError::NetworkRequesterResponseError)
} else {
Err(MessageError::UnknownMessageType)
}
@@ -88,9 +78,6 @@ impl Message {
Self::Response(r) => std::iter::once(Self::RESPONSE_FLAG)
.chain(r.into_bytes().iter().cloned())
.collect(),
Self::NetworkRequesterResponse(r) => std::iter::once(Self::NR_RESPONSE_FLAG)
.chain(r.into_bytes().iter().cloned())
.collect(),
}
}
}
@@ -1,112 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::ConnectionId;
#[derive(Debug)]
pub struct NetworkRequesterResponse {
pub connection_id: ConnectionId,
pub network_requester_error: String,
}
#[derive(Debug, thiserror::Error, PartialEq, Eq)]
pub enum Error {
#[error("no data provided")]
NoData,
#[error("not enough bytes to recover the connection id")]
ConnectionIdTooShort,
#[error("message is not utf8 encoded")]
MalformedErrorMessage(#[from] std::string::FromUtf8Error),
}
impl NetworkRequesterResponse {
pub fn new(connection_id: ConnectionId, network_requester_error: String) -> Self {
NetworkRequesterResponse {
connection_id,
network_requester_error,
}
}
pub fn try_from_bytes(b: &[u8]) -> Result<NetworkRequesterResponse, Error> {
if b.is_empty() {
return Err(Error::NoData);
}
if b.len() < 8 {
return Err(Error::ConnectionIdTooShort);
}
let mut connection_id_bytes = b.to_vec();
let network_requester_error_bytes = connection_id_bytes.split_off(8);
let connection_id = u64::from_be_bytes([
connection_id_bytes[0],
connection_id_bytes[1],
connection_id_bytes[2],
connection_id_bytes[3],
connection_id_bytes[4],
connection_id_bytes[5],
connection_id_bytes[6],
connection_id_bytes[7],
]);
let network_requester_error = String::from_utf8(network_requester_error_bytes)?;
Ok(NetworkRequesterResponse {
connection_id,
network_requester_error,
})
}
pub fn into_bytes(self) -> Vec<u8> {
self.connection_id
.to_be_bytes()
.iter()
.cloned()
.chain(self.network_requester_error.into_bytes().into_iter())
.collect()
}
}
#[cfg(test)]
mod network_requester_response_serde_tests {
use super::*;
#[test]
fn simple_serde() {
let conn_id = 42;
let network_requester_error = String::from("This is a test msg");
let response = NetworkRequesterResponse::new(conn_id, network_requester_error.clone());
let bytes = response.into_bytes();
let deserialized_response = NetworkRequesterResponse::try_from_bytes(&bytes).unwrap();
assert_eq!(conn_id, deserialized_response.connection_id);
assert_eq!(
network_requester_error,
deserialized_response.network_requester_error
);
}
#[test]
fn deserialization_errors() {
let err = NetworkRequesterResponse::try_from_bytes(&[]).err().unwrap();
assert_eq!(err, Error::NoData);
let bytes: [u8; 5] = [1, 2, 3, 4, 5];
let err = NetworkRequesterResponse::try_from_bytes(&bytes)
.err()
.unwrap();
assert_eq!(err, Error::ConnectionIdTooShort);
let bytes: Vec<u8> = 42u64
.to_be_bytes()
.into_iter()
.chain([0, 159, 146, 150].into_iter())
.collect();
let err = NetworkRequesterResponse::try_from_bytes(&bytes)
.err()
.unwrap();
assert!(matches!(err, Error::MalformedErrorMessage(_)));
}
}
+24 -18
View File
@@ -1,9 +1,6 @@
// Copyright 2020-2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nymsphinx_addressing::clients::{Recipient, RecipientFormattingError};
use std::convert::TryFrom;
use thiserror::Error;
use std::fmt::{self};
pub type ConnectionId = u64;
pub type RemoteAddress = String;
@@ -15,30 +12,39 @@ pub enum RequestFlag {
Send = 1,
}
#[derive(Debug, Error)]
#[derive(Debug)]
pub enum RequestError {
#[error("not enough bytes to recover the length of the address")]
AddressLengthTooShort,
#[error("not enough bytes to recover the address")]
AddressTooShort,
#[error("not enough bytes to recover the connection id")]
ConnectionIdTooShort,
#[error("no data provided")]
NoData,
#[error("request of unknown type")]
UnknownRequestFlag,
#[error("too short return address")]
ReturnAddressTooShort,
#[error("malformed return address - {0}")]
MalformedReturnAddress(RecipientFormattingError),
}
impl fmt::Display for RequestError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
match self {
RequestError::AddressLengthTooShort => {
write!(f, "not enough bytes to recover the length of the address")
}
RequestError::AddressTooShort => write!(f, "not enough bytes to recover the address"),
RequestError::ConnectionIdTooShort => {
write!(f, "not enough bytes to recover the connection id")
}
RequestError::NoData => write!(f, "no data provided"),
RequestError::UnknownRequestFlag => write!(f, "request of unknown type"),
RequestError::ReturnAddressTooShort => write!(f, "too short return address"),
RequestError::MalformedReturnAddress(recipient_err) => {
write!(f, "malformed return address - {}", recipient_err)
}
}
}
}
impl std::error::Error for RequestError {}
impl RequestError {
pub fn is_malformed_return(&self) -> bool {
matches!(self, RequestError::MalformedReturnAddress(_))
+1 -8
View File
@@ -1,15 +1,8 @@
// Copyright 2020-2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use thiserror::Error;
use crate::ConnectionId;
#[derive(Debug, Error, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq)]
pub enum ResponseError {
#[error("not enough bytes to recover the connection id")]
ConnectionIdTooShort,
#[error("no data provided")]
NoData,
}
/// A remote network response retrieved by the Socks5 service provider. This
+2 -11
View File
@@ -5,14 +5,13 @@ use std::time::Duration;
use tokio::sync::watch::{self, error::SendError};
const DEFAULT_SHUTDOWN_TIMER_SECS: u64 = 5;
const SHUTDOWN_TIMER_SECS: u64 = 5;
/// Used to notify other tasks to gracefully shutdown
#[derive(Debug)]
pub struct ShutdownNotifier {
notify_tx: watch::Sender<()>,
notify_rx: Option<watch::Receiver<()>>,
shutdown_timer_secs: u64,
}
impl Default for ShutdownNotifier {
@@ -21,19 +20,11 @@ impl Default for ShutdownNotifier {
Self {
notify_tx,
notify_rx: Some(notify_rx),
shutdown_timer_secs: DEFAULT_SHUTDOWN_TIMER_SECS,
}
}
}
impl ShutdownNotifier {
pub fn new(shutdown_timer_secs: u64) -> Self {
Self {
shutdown_timer_secs,
..Default::default()
}
}
pub fn subscribe(&self) -> ShutdownListener {
ShutdownListener::new(
self.notify_rx
@@ -59,7 +50,7 @@ impl ShutdownNotifier {
_ = tokio::signal::ctrl_c() => {
log::info!("Forcing shutdown");
}
_ = tokio::time::sleep(Duration::from_secs(self.shutdown_timer_secs)) => {
_ = tokio::time::sleep(Duration::from_secs(SHUTDOWN_TIMER_SECS)) => {
log::info!("Timout reached, forcing shutdown");
},
}
+1 -1
View File
@@ -507,7 +507,7 @@ mod test {
for (expected, raw_display) in values {
let coin = DecCoin {
denom: Network::MAINNET.mix_denom().display,
denom: Network::MAINNET.mix_denom().display.into(),
amount: raw_display.parse().unwrap(),
};
let base = reg.attempt_convert_to_base_coin(coin).unwrap();
-51
View File
@@ -1,51 +0,0 @@
## Unreleased
### Added
- vesting-contract: added queries for delegation timestamps and paged query for all vesting delegations in the contract ([#1569])
### Changed
- mixnet-contract: compounding delegator rewards now happens instantaneously as opposed to having to wait for the current epoch to finish ([#1571])
### Fixed
- vesting-contract: the contract now correctly stores delegations with their timestamp as opposed to using block height ([#1544])
- mixnet-contract: compounding delegator rewards is now possible even if the associated mixnode had already unbonded ([#1571])
[#1544]: https://github.com/nymtech/nym/pull/1544
[#1569]: https://github.com/nymtech/nym/pull/1569
[#1569]: https://github.com/nymtech/nym/pull/1571
## [nym-contracts-v1.0.1](https://github.com/nymtech/nym/tree/nym-contracts-v1.0.1) (2022-06-22)
### Added
- mixnet-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
- mixnet-contract: Replace all naked `-` with `saturating_sub`.
- mixnet-contract: Added staking_supply field to ContractStateParams.
- mixnet-contract: Added a query to get MixnodeBond by identity key ([#1369]).
- mixnet-contract: Added a query to get GatewayBond by identity key ([#1369]).
- vesting-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
- vesting-contract: Added limit to the amount of tokens one can pledge ([#1331])
### Fixed
- mixnet-contract: `estimated_delegator_reward` calculation ([#1284])
- mixnet-contract: delegator and operator rewards use lambda and sigma instead of lambda_ticked and sigma_ticked ([#1284])
- mixnet-contract: removed `expect` in `query_delegator_reward` and queries containing invalid proxy address should now return a more human-readable error ([#1257])
- mixnet-contract: replaced integer division with fixed for performance calculations ([#1284])
- mixnet-contract: Under certain circumstances nodes could not be unbonded ([#1255](https://github.com/nymtech/nym/issues/1255)) ([#1258])
- mixnet-contract: Using correct staking supply when distributing rewards. ([#1373])
- vesting-contract: replaced `checked_sub` with `saturating_sub` to fix the underflow in `get_vesting_tokens` ([#1275])
[#1255]: https://github.com/nymtech/nym/pull/1255
[#1257]: https://github.com/nymtech/nym/pull/1257
[#1258]: https://github.com/nymtech/nym/pull/1258
[#1275]: https://github.com/nymtech/nym/pull/1275
[#1284]: https://github.com/nymtech/nym/pull/1284
[#1292]: https://github.com/nymtech/nym/pull/1292
[#1331]: https://github.com/nymtech/nym/pull/1331
[#1369]: https://github.com/nymtech/nym/pull/1369
[#1373]: https://github.com/nymtech/nym/pull/1373
+220 -218
View File
@@ -7,7 +7,6 @@ use crate::delegations::queries::query_mixnode_delegation;
use crate::delegations::queries::{
query_mixnode_delegations_paged, query_pending_delegation_events,
};
use crate::delegations::storage::delegations;
use crate::error::ContractError;
use crate::gateways::queries::query_owns_gateway;
use crate::gateways::queries::{query_gateway_bond, query_gateways_paged};
@@ -25,19 +24,18 @@ 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_mixnode_bond,
query_mixnodes_paged,
query_checkpoints_for_mixnode, query_mixnode_at_height, query_mixnodes_paged,
};
use crate::mixnodes::layer_queries::query_layer_distribution;
use crate::mixnodes::transactions::_try_remove_mixnode;
use crate::queued_migrations::v2_migration;
use crate::queued_migrations::migrate_config_from_env;
use crate::rewards::queries::{
query_circulating_supply, query_reward_pool, query_rewarding_status, query_staking_supply,
};
use crate::rewards::storage as rewards_storage;
use cosmwasm_std::{
entry_point, to_binary, Addr, Api, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response,
Storage, SubMsg, Uint128,
Storage, Uint128,
};
use mixnet_contract_common::{
ContractStateParams, ExecuteMsg, InstantiateMsg, MigrateMsg, NodeToRemove, QueryMsg,
@@ -116,7 +114,6 @@ pub fn execute(
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
match msg {
// we must be able to perform universal compound alongside reconcile
ExecuteMsg::CompoundReward {
operator,
delegator,
@@ -130,217 +127,215 @@ pub fn execute(
mix_identity,
proxy,
),
ExecuteMsg::UpdateRewardingValidatorAddress { address } => {
try_update_rewarding_validator_address(deps, info, address)
}
ExecuteMsg::InitEpoch {} => try_init_epoch(info, deps.storage, env),
ExecuteMsg::BondMixnode {
mix_node,
owner_signature,
} => crate::mixnodes::transactions::try_add_mixnode(
deps,
env,
info,
mix_node,
owner_signature,
),
ExecuteMsg::UnbondMixnode {} => {
crate::mixnodes::transactions::try_remove_mixnode(&env, deps.storage, deps.api, info)
}
ExecuteMsg::UpdateMixnodeConfig {
profit_margin_percent,
} => crate::mixnodes::transactions::try_update_mixnode_config(
deps,
env,
info,
profit_margin_percent,
),
ExecuteMsg::UpdateMixnodeConfigOnBehalf {
profit_margin_percent,
owner,
} => crate::mixnodes::transactions::try_update_mixnode_config_on_behalf(
deps,
env,
info,
profit_margin_percent,
owner,
),
ExecuteMsg::BondGateway {
gateway,
owner_signature,
} => crate::gateways::transactions::try_add_gateway(
deps,
env,
info,
gateway,
owner_signature,
),
ExecuteMsg::UnbondGateway {} => {
crate::gateways::transactions::try_remove_gateway(deps, info)
}
ExecuteMsg::UpdateContractStateParams(params) => {
crate::mixnet_contract_settings::transactions::try_update_contract_settings(
deps, info, params,
)
}
ExecuteMsg::RewardMixnode { identity, params } => {
crate::rewards::transactions::try_reward_mixnode(deps, env, info, identity, params)
}
ExecuteMsg::DelegateToMixnode { mix_identity } => {
crate::delegations::transactions::try_delegate_to_mixnode(deps, env, info, mix_identity)
}
ExecuteMsg::UndelegateFromMixnode { mix_identity } => {
crate::delegations::transactions::try_remove_delegation_from_mixnode(
deps,
env,
info,
mix_identity,
)
}
// ExecuteMsg::RewardNextMixDelegators {
// mix_identity,
// interval_id,
// } => crate::rewards::transactions::try_reward_next_mixnode_delegators(
// deps,
// info,
// mix_identity,
// interval_id,
// ),
ExecuteMsg::DelegateToMixnodeOnBehalf {
mix_identity,
delegate,
} => crate::delegations::transactions::try_delegate_to_mixnode_on_behalf(
deps,
env,
info,
mix_identity,
delegate,
),
ExecuteMsg::UndelegateFromMixnodeOnBehalf {
mix_identity,
delegate,
} => crate::delegations::transactions::try_remove_delegation_from_mixnode_on_behalf(
deps,
env,
info,
mix_identity,
delegate,
),
ExecuteMsg::BondMixnodeOnBehalf {
mix_node,
owner,
owner_signature,
} => crate::mixnodes::transactions::try_add_mixnode_on_behalf(
deps,
env,
info,
mix_node,
owner,
owner_signature,
),
ExecuteMsg::UnbondMixnodeOnBehalf { owner } => {
crate::mixnodes::transactions::try_remove_mixnode_on_behalf(
&env,
deps.storage,
deps.api,
info,
owner,
)
}
ExecuteMsg::BondGatewayOnBehalf {
gateway,
owner,
owner_signature,
} => crate::gateways::transactions::try_add_gateway_on_behalf(
deps,
env,
info,
gateway,
owner,
owner_signature,
),
ExecuteMsg::UnbondGatewayOnBehalf { owner } => {
crate::gateways::transactions::try_remove_gateway_on_behalf(deps, info, owner)
}
ExecuteMsg::WriteRewardedSet {
rewarded_set,
expected_active_set_size,
} => crate::interval::transactions::try_write_rewarded_set(
deps,
env,
info,
rewarded_set,
expected_active_set_size,
),
ExecuteMsg::AdvanceCurrentEpoch {} => crate::interval::transactions::try_advance_epoch(
env,
deps.storage,
info.sender.to_string(),
),
ExecuteMsg::CompoundDelegatorReward { mix_identity } => {
crate::rewards::transactions::try_compound_delegator_reward(
deps,
env,
info,
mix_identity,
)
}
ExecuteMsg::CompoundOperatorReward {} => {
crate::rewards::transactions::try_compound_operator_reward(deps, env, info)
}
ExecuteMsg::CompoundDelegatorRewardOnBehalf {
owner,
mix_identity,
} => crate::rewards::transactions::try_compound_delegator_reward_on_behalf(
deps,
env,
info,
owner,
mix_identity,
),
ExecuteMsg::CompoundOperatorRewardOnBehalf { owner } => {
crate::rewards::transactions::try_compound_operator_reward_on_behalf(
deps, env, info, owner,
)
}
ExecuteMsg::ReconcileDelegations {} => {
crate::delegations::transactions::try_reconcile_all_delegation_events(deps)
}
_ => Err(ContractError::MaintenanceMode),
// ExecuteMsg::UpdateRewardingValidatorAddress { address } => {
// try_update_rewarding_validator_address(deps, info, address)
// }
// ExecuteMsg::InitEpoch {} => try_init_epoch(info, deps.storage, env),
// ExecuteMsg::BondMixnode {
// mix_node,
// owner_signature,
// } => crate::mixnodes::transactions::try_add_mixnode(
// deps,
// env,
// info,
// mix_node,
// owner_signature,
// ),
// ExecuteMsg::UnbondMixnode {} => {
// crate::mixnodes::transactions::try_remove_mixnode(&env, deps.storage, deps.api, info)
// }
// ExecuteMsg::UpdateMixnodeConfig {
// profit_margin_percent,
// } => crate::mixnodes::transactions::try_update_mixnode_config(
// deps,
// env,
// info,
// profit_margin_percent,
// ),
// ExecuteMsg::UpdateMixnodeConfigOnBehalf {
// profit_margin_percent,
// owner,
// } => crate::mixnodes::transactions::try_update_mixnode_config_on_behalf(
// deps,
// env,
// info,
// profit_margin_percent,
// owner,
// ),
// ExecuteMsg::BondGateway {
// gateway,
// owner_signature,
// } => crate::gateways::transactions::try_add_gateway(
// deps,
// env,
// info,
// gateway,
// owner_signature,
// ),
// ExecuteMsg::UnbondGateway {} => {
// crate::gateways::transactions::try_remove_gateway(deps, info)
// }
// ExecuteMsg::UpdateContractStateParams(params) => {
// crate::mixnet_contract_settings::transactions::try_update_contract_settings(
// deps, info, params,
// )
// }
// ExecuteMsg::RewardMixnode { identity, params } => {
// crate::rewards::transactions::try_reward_mixnode(deps, env, info, identity, params)
// }
// ExecuteMsg::DelegateToMixnode { mix_identity } => {
// crate::delegations::transactions::try_delegate_to_mixnode(deps, env, info, mix_identity)
// }
// ExecuteMsg::UndelegateFromMixnode { mix_identity } => {
// crate::delegations::transactions::try_remove_delegation_from_mixnode(
// deps,
// env,
// info,
// mix_identity,
// )
// }
// // ExecuteMsg::RewardNextMixDelegators {
// // mix_identity,
// // interval_id,
// // } => crate::rewards::transactions::try_reward_next_mixnode_delegators(
// // deps,
// // info,
// // mix_identity,
// // interval_id,
// // ),
// ExecuteMsg::DelegateToMixnodeOnBehalf {
// mix_identity,
// delegate,
// } => crate::delegations::transactions::try_delegate_to_mixnode_on_behalf(
// deps,
// env,
// info,
// mix_identity,
// delegate,
// ),
// ExecuteMsg::UndelegateFromMixnodeOnBehalf {
// mix_identity,
// delegate,
// } => crate::delegations::transactions::try_remove_delegation_from_mixnode_on_behalf(
// deps,
// env,
// info,
// mix_identity,
// delegate,
// ),
// ExecuteMsg::BondMixnodeOnBehalf {
// mix_node,
// owner,
// owner_signature,
// } => crate::mixnodes::transactions::try_add_mixnode_on_behalf(
// deps,
// env,
// info,
// mix_node,
// owner,
// owner_signature,
// ),
// ExecuteMsg::UnbondMixnodeOnBehalf { owner } => {
// crate::mixnodes::transactions::try_remove_mixnode_on_behalf(
// &env,
// deps.storage,
// deps.api,
// info,
// owner,
// )
// }
// ExecuteMsg::BondGatewayOnBehalf {
// gateway,
// owner,
// owner_signature,
// } => crate::gateways::transactions::try_add_gateway_on_behalf(
// deps,
// env,
// info,
// gateway,
// owner,
// owner_signature,
// ),
// ExecuteMsg::UnbondGatewayOnBehalf { owner } => {
// crate::gateways::transactions::try_remove_gateway_on_behalf(deps, info, owner)
// }
// ExecuteMsg::WriteRewardedSet {
// rewarded_set,
// expected_active_set_size,
// } => crate::interval::transactions::try_write_rewarded_set(
// deps,
// env,
// info,
// rewarded_set,
// expected_active_set_size,
// ),
// ExecuteMsg::AdvanceCurrentEpoch {} => crate::interval::transactions::try_advance_epoch(
// env,
// deps.storage,
// info.sender.to_string(),
// ),
// ExecuteMsg::CompoundDelegatorReward { mix_identity } => {
// crate::rewards::transactions::try_compound_delegator_reward(
// deps,
// env,
// info,
// mix_identity,
// )
// }
// ExecuteMsg::CompoundOperatorReward {} => {
// crate::rewards::transactions::try_compound_operator_reward(deps, env, info)
// }
// ExecuteMsg::CompoundDelegatorRewardOnBehalf {
// owner,
// mix_identity,
// } => crate::rewards::transactions::try_compound_delegator_reward_on_behalf(
// deps,
// env,
// info,
// owner,
// mix_identity,
// ),
// ExecuteMsg::CompoundOperatorRewardOnBehalf { owner } => {
// crate::rewards::transactions::try_compound_operator_reward_on_behalf(
// deps, env, info, owner,
// )
// }
//
// ExecuteMsg::CheckpointMixnodes {} => {
// crate::mixnodes::transactions::try_checkpoint_mixnodes(
// deps.storage,
// env.block.height,
// info,
// )
// }
// ExecuteMsg::ClaimOperatorReward {} => {
// crate::rewards::transactions::try_claim_operator_reward(deps, &env, &info)
// }
// ExecuteMsg::ClaimOperatorRewardOnBehalf { owner } => {
// crate::rewards::transactions::try_claim_operator_reward_on_behalf(
// deps, &env, &info, owner,
// )
// }
// ExecuteMsg::ClaimDelegatorReward { mix_identity } => {
// crate::rewards::transactions::try_claim_delegator_reward(
// deps,
// &env,
// &info,
// &mix_identity,
// )
// }
// ExecuteMsg::ClaimDelegatorRewardOnBehalf {
// mix_identity,
// owner,
// } => crate::rewards::transactions::try_claim_delegator_reward_on_behalf(
// deps,
// &env,
// &info,
// owner,
// &mix_identity,
// ),
ExecuteMsg::CheckpointMixnodes {} => {
crate::mixnodes::transactions::try_checkpoint_mixnodes(
deps.storage,
env.block.height,
info,
)
}
ExecuteMsg::ClaimOperatorReward {} => {
crate::rewards::transactions::try_claim_operator_reward(deps, &env, &info)
}
ExecuteMsg::ClaimOperatorRewardOnBehalf { owner } => {
crate::rewards::transactions::try_claim_operator_reward_on_behalf(
deps, &env, &info, owner,
)
}
ExecuteMsg::ClaimDelegatorReward { mix_identity } => {
crate::rewards::transactions::try_claim_delegator_reward(
deps,
&env,
&info,
&mix_identity,
)
}
ExecuteMsg::ClaimDelegatorRewardOnBehalf {
mix_identity,
owner,
} => crate::rewards::transactions::try_claim_delegator_reward_on_behalf(
deps,
&env,
&info,
owner,
&mix_identity,
),
}
}
@@ -472,9 +467,6 @@ pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result<QueryResponse, C
mix_identity,
height,
} => to_binary(&query_mixnode_at_height(deps, mix_identity, height)?),
QueryMsg::GetAllDelegationValuesPaged { start_after, limit } => to_binary(
&crate::delegations::queries::query_all_delegations_paged(deps, start_after, limit)?,
),
};
Ok(query_res?)
@@ -517,7 +509,17 @@ fn remove_malicious_node(
#[entry_point]
pub fn migrate(deps: DepsMut<'_>, env: Env, msg: MigrateMsg) -> Result<Response, ContractError> {
v2_migration(deps, env, msg)
migrate_config_from_env(deps.storage, &msg)?;
let mut response = Response::new();
for node in msg.nodes_to_remove().iter() {
let mut sub_response = remove_malicious_node(deps.storage, deps.api, &env, node)
.unwrap_or_else(|_| panic!("Could not remove node: {:?}", node));
response.messages.append(&mut sub_response.messages);
response.attributes.append(&mut sub_response.attributes);
response.events.append(&mut sub_response.events);
}
Ok(response)
}
#[cfg(test)]

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