Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a94272ffd6 | |||
| 773f9e5ead | |||
| 79f695f138 | |||
| 3aabbcf876 | |||
| d96b7408db | |||
| 728b0f4549 | |||
| 0a37c81709 | |||
| 957cbb45b0 | |||
| 8ec074cb1f | |||
| ab5740087f | |||
| 6af59c303e | |||
| 27b384e034 | |||
| 7f5ce3ffeb | |||
| 89b6667c75 | |||
| a94a9aeaf5 | |||
| 6bc8b88a20 | |||
| 21f3991714 | |||
| cd8eba988a | |||
| d2b3841bbd | |||
| de877fb337 | |||
| d4c2b9060f | |||
| 41ac866729 | |||
| a7afd2a1c7 | |||
| c7fdcf0a79 | |||
| 8edc762df9 | |||
| 7b15f350cd | |||
| 2b4917b8b1 | |||
| 921e558660 | |||
| d62638b8e2 | |||
| 02da10e222 | |||
| 2637924e9c | |||
| bbaa06417d | |||
| edcaf72714 | |||
| 80ad7c1798 |
@@ -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_NYMBOT_TEAM }}"
|
||||
KEYBASE_NYM_CHANNEL: "ci-nightly"
|
||||
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMTECH_TEAM }}"
|
||||
KEYBASE_NYM_CHANNEL: "test"
|
||||
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
|
||||
@@ -45,3 +45,4 @@ jobs:
|
||||
target/release/nym-socks5-client
|
||||
target/release/nym-validator-api
|
||||
target/release/nym-network-requester
|
||||
target/release/nym-network-statistics
|
||||
@@ -51,12 +51,12 @@ jobs:
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install
|
||||
working-directory: nym-wallet/webdriver
|
||||
working-directory: nym-wallet/wallet-ui-tests
|
||||
|
||||
- name: Remove existing user datafile
|
||||
uses: JesseTG/rm@v1.0.2
|
||||
with:
|
||||
path: nym-wallet/webdriver/common/data/user-data.json
|
||||
path: nym-wallet/wallet-ui-tests/common/user-data.json
|
||||
|
||||
- name: Create user data json file
|
||||
id: create-json
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
with:
|
||||
name: "user-data.json"
|
||||
json: ${{ secrets.WALLET_USERDATA }}
|
||||
dir: "nym-wallet/webdriver/common/data/"
|
||||
dir: "nym-wallet/wallet-ui-tests/common/"
|
||||
|
||||
- name: Install tauri-driver
|
||||
uses: actions-rs/cargo@v1
|
||||
@@ -73,5 +73,5 @@ jobs:
|
||||
args: tauri-driver
|
||||
|
||||
- name: Launch tests
|
||||
run: xvfb-run yarn test:runall
|
||||
working-directory: nym-wallet/webdriver
|
||||
run: xvfb-run yarn test
|
||||
working-directory: nym-wallet/wallet-ui-tests
|
||||
|
||||
+12
-254
@@ -2,8 +2,16 @@
|
||||
|
||||
Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
## [Unreleased]
|
||||
### Changed
|
||||
|
||||
- validator-client: made `fee` argument optional for `execute` and `execute_multiple` ([#1541])
|
||||
|
||||
[#1541]: https://github.com/nymtech/nym/pull/1541
|
||||
|
||||
|
||||
## [nym-binaries-1.0.2](https://github.com/nymtech/nym/tree/nym-binaries-1.0.2)
|
||||
|
||||
### Added
|
||||
|
||||
@@ -25,6 +33,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
- 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
|
||||
|
||||
@@ -53,6 +62,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
- 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])
|
||||
|
||||
|
||||
[#1249]: https://github.com/nymtech/nym/pull/1249
|
||||
@@ -81,90 +91,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
[#1487]: https://github.com/nymtech/nym/pull/1487
|
||||
[#1496]: https://github.com/nymtech/nym/pull/1496
|
||||
[#1503]: https://github.com/nymtech/nym/pull/1503
|
||||
|
||||
## [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])
|
||||
[#1520]: https://github.com/nymtech/nym/pull/1520
|
||||
|
||||
## [v1.0.1](https://github.com/nymtech/nym/tree/v1.0.1) (2022-05-04)
|
||||
|
||||
@@ -197,77 +124,10 @@ 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)
|
||||
@@ -346,108 +206,6 @@ 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
+531
-477
File diff suppressed because it is too large
Load Diff
+9
-7
@@ -22,22 +22,23 @@ 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/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",
|
||||
@@ -53,9 +54,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",
|
||||
@@ -76,6 +77,7 @@ default-members = [
|
||||
"clients/socks5",
|
||||
"gateway",
|
||||
"service-providers/network-requester",
|
||||
"service-providers/network-statistics",
|
||||
"mixnode",
|
||||
"validator-api",
|
||||
"explorer-api",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
|
||||
@@ -82,7 +82,7 @@ fn version_check(cfg: &Config) -> bool {
|
||||
if binary_version == config_version {
|
||||
true
|
||||
} else {
|
||||
warn!("The mixnode binary has different version than what is specified in config file! {} and {}", binary_version, config_version);
|
||||
warn!("The native-client 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,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
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"
|
||||
|
||||
@@ -893,7 +893,7 @@ impl<C> NymdClient<C> {
|
||||
&self,
|
||||
contract_address: &AccountId,
|
||||
msg: &M,
|
||||
fee: Fee,
|
||||
fee: Option<Fee>,
|
||||
memo: impl Into<String> + Send + 'static,
|
||||
funds: Vec<Coin>,
|
||||
) -> Result<ExecuteResult, NymdError>
|
||||
@@ -901,6 +901,7 @@ 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
|
||||
@@ -910,7 +911,7 @@ impl<C> NymdClient<C> {
|
||||
&self,
|
||||
contract_address: &AccountId,
|
||||
msgs: I,
|
||||
fee: Fee,
|
||||
fee: Option<Fee>,
|
||||
memo: impl Into<String> + Send + 'static,
|
||||
) -> Result<ExecuteResult, NymdError>
|
||||
where
|
||||
@@ -918,6 +919,7 @@ 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
|
||||
|
||||
@@ -37,7 +37,7 @@ impl SpendCredentialData {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub enum SpendCredentialStatus {
|
||||
InProgress,
|
||||
Spent,
|
||||
|
||||
@@ -213,7 +213,7 @@ pub enum QueryMsg {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct MigrateMsg {
|
||||
pub mixnet_denom: String,
|
||||
@@ -226,7 +226,7 @@ impl MigrateMsg {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
pub struct NodeToRemove {
|
||||
owner: String,
|
||||
proxy: Option<String>,
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
[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]
|
||||
rand = "0.8.5"
|
||||
thiserror = "1.0.32"
|
||||
@@ -0,0 +1,9 @@
|
||||
#[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 arrarys")]
|
||||
NormDifferenceSizeArrays,
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
//! Active set inclusion probability simulator
|
||||
|
||||
use error::Error;
|
||||
|
||||
mod error;
|
||||
|
||||
const TOLERANCE_L2_NORM: f64 = 1e-4;
|
||||
const TOLERANCE_MAX_NORM: f64 = 1e-3;
|
||||
|
||||
pub struct SelectionProbability {
|
||||
pub active_set_probability: Vec<f64>,
|
||||
pub reserve_set_probability: Vec<f64>,
|
||||
pub samples: u32,
|
||||
pub delta_l2: f64,
|
||||
pub delta_max: f64,
|
||||
}
|
||||
|
||||
pub fn simulate_selection_probability_mixnodes(
|
||||
list_stake_for_mixnodes: &[u64],
|
||||
active_set_size: usize,
|
||||
reserve_set_size: usize,
|
||||
max_samples: u32,
|
||||
) -> Result<SelectionProbability, Error> {
|
||||
// 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;
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
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 {
|
||||
let candidate = sample_candidate(&list_cumul_temp, &mut 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 {
|
||||
let candidate = sample_candidate(&list_cumul_temp, &mut 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)?
|
||||
/ f64::from(samples);
|
||||
delta_max = max_diff(&active_set_probability, &active_set_probability_previous)?
|
||||
/ f64::from(samples);
|
||||
if samples > 10 && delta_l2 < TOLERANCE_L2_NORM && delta_max < TOLERANCE_MAX_NORM
|
||||
|| samples >= max_samples
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
active_set_probability
|
||||
.iter_mut()
|
||||
.for_each(|x| *x /= f64::from(samples));
|
||||
reserve_set_probability
|
||||
.iter_mut()
|
||||
.for_each(|x| *x /= f64::from(samples));
|
||||
|
||||
Ok(SelectionProbability {
|
||||
active_set_probability,
|
||||
reserve_set_probability,
|
||||
samples,
|
||||
delta_l2,
|
||||
delta_max,
|
||||
})
|
||||
}
|
||||
|
||||
// Compute the cumulative sum
|
||||
fn cumul_sum<'a>(list: impl IntoIterator<Item = &'a u64>) -> Vec<u64> {
|
||||
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(list_cumul: &[u64], rng: &mut rand::rngs::ThreadRng) -> Result<usize, Error> {
|
||||
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 [u64]) {
|
||||
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 super::*;
|
||||
|
||||
#[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 SelectionProbability {
|
||||
active_set_probability,
|
||||
reserve_set_probability,
|
||||
samples,
|
||||
delta_l2,
|
||||
delta_max,
|
||||
} = simulate_selection_probability_mixnodes(
|
||||
&list_mix,
|
||||
active_set_size,
|
||||
standby_set_size,
|
||||
max_samples,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// 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!(samples < 20_500);
|
||||
assert!(delta_l2 < TOLERANCE_L2_NORM);
|
||||
assert!(delta_max < TOLERANCE_MAX_NORM);
|
||||
}
|
||||
}
|
||||
@@ -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 = "http://127.0.0.1:8090";
|
||||
pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "https://mainnet-stats.nymte.ch: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> {
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
## [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
|
||||
@@ -18,7 +18,6 @@ pub fn migrate_config_from_env(
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
pub struct OldContractState {
|
||||
pub owner: Addr,
|
||||
pub mix_denom: String,
|
||||
pub rewarding_validator_address: Addr,
|
||||
pub params: ContractStateParams,
|
||||
}
|
||||
|
||||
@@ -101,10 +101,9 @@ impl Account {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the index of the next vesting period. Unless the current time is somehow in the past or vesting has not started yet.
|
||||
/// In case vesting is over it will always return NUM_VESTING_PERIODS.
|
||||
pub fn get_current_vesting_period(&self, block_time: Timestamp) -> Period {
|
||||
// Returns the index of the next vesting period. Unless the current time is somehow in the past or vesting has not started yet.
|
||||
// In case vesting is over it will always return NUM_VESTING_PERIODS.
|
||||
|
||||
if block_time.seconds() < self.periods.first().unwrap().start_time {
|
||||
Period::Before
|
||||
} else if self.periods.last().unwrap().end_time() < block_time {
|
||||
|
||||
+1
-1
@@ -15,6 +15,6 @@ BANDWIDTH_CLAIM_CONTRACT_ADDRESS=n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0
|
||||
COCONUT_BANDWIDTH_CONTRACT_ADDRESS=n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0
|
||||
MULTISIG_CONTRACT_ADDRESS=n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0
|
||||
REWARDING_VALIDATOR_ADDRESS=n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy
|
||||
STATISTICS_SERVICE_DOMAIN_ADDRESS="http://127.0.0.1:8090"
|
||||
STATISTICS_SERVICE_DOMAIN_ADDRESS="https://mainnet-stats.nymte.ch:8090"
|
||||
NYMD_VALIDATOR="https://rpc.nyx.nodes.guru/"
|
||||
API_VALIDATOR="https://validator.nymtech.net/api/"
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "nym-gateway"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Mixnet Gateway"
|
||||
edition = "2021"
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "nym-mixnode"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
authors = [
|
||||
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
||||
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
## [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
|
||||
Generated
+1
-1
@@ -3436,7 +3436,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"client-core",
|
||||
|
||||
@@ -1 +1 @@
|
||||
ADMIN_ADDRESS={"MAINNET":[],"SANDBOX":[],"QA":["n1c8te4wlc25re97qw5nh8urtpek494zqx30lza2","n177krl498arsfupd2p9097kwfmuf07lkj6crmj9"]}
|
||||
ADMIN_ADDRESS={\"MAINNET\":[],\"SANDBOX\":[],\"QA\":[\"n1c8te4wlc25re97qw5nh8urtpek494zqx30lza2\",\"n177krl498arsfupd2p9097kwfmuf07lkj6crmj9\"]}
|
||||
@@ -0,0 +1,213 @@
|
||||
## [nym-wallet-v1.0.8](https://github.com/nymtech/nym/releases/tag/nym-wallet-v1.0.8) (2022-08-11)
|
||||
|
||||
- wallet: new bonding flow and screen for bonded node
|
||||
- wallet: compound and redeem functionalities for operator rewards
|
||||
- wallet: a few minor touch ups and bug fixes
|
||||
|
||||
|
||||
## [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-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])
|
||||
|
||||
## [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-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-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))
|
||||
Generated
+1
-1
@@ -3055,7 +3055,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym_wallet"
|
||||
version = "1.0.7"
|
||||
version = "1.0.8"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"argon2 0.3.4",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym_wallet"
|
||||
version = "1.0.7"
|
||||
version = "1.0.8"
|
||||
description = "Nym Native Wallet"
|
||||
authors = ["Nym Technologies SA"]
|
||||
license = ""
|
||||
|
||||
@@ -254,7 +254,7 @@ pub async fn get_mix_node_description(
|
||||
host: &str,
|
||||
port: u16,
|
||||
) -> Result<NodeDescription, BackendError> {
|
||||
return fetch_mix_node_description(host, port)
|
||||
fetch_mix_node_description(host, port)
|
||||
.await
|
||||
.map_err(|e| BackendError::ReqwestError { source: e });
|
||||
.map_err(|e| BackendError::ReqwestError { source: e })
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"accounts": [
|
||||
{
|
||||
"id": "default",
|
||||
"account": {
|
||||
"ciphertext": "cq5w4W5ex5eFFRcqLG+824XyUAUoYmrRY3NGw/rue6/mLoQKQE/07+BxzRuKjyYFasC1HBPg41KJwp2IY+/7+80rB9aXPpaKVLUcG9U40qgCw66WhgxTrXOnrt5toefpSTBL7f9N/PVwpuumfAgD9CS0ioB7/9Qoea7nYKkextGX15ex26B/ndQddvUkQ4gx+Vq7OLymv4l+nkdZ2nKMja349zd/BjnzPBB68/iIjyYlivVjtQ7FRbvpNRj6Mjg4905wGlO7bTpkw+RGiaGK4pK8fTWz8gAKr8GYoXPD",
|
||||
"salt": "SPVGdbVyoEayD4ZzM4I+Jg==",
|
||||
"iv": "tjpn/tRjD1gty+fQ"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"accounts": [
|
||||
{
|
||||
"id": "default",
|
||||
"account": {
|
||||
"ciphertext": "3MDgoU2i5QMc9r80yPeq2AMk5wpkke0tXum5NsOE5NcFciF+aHLQW0dvXbGszap1y3nN4+YZD3cgGrmtKh/cChqRGJDkniaxdf3XPHh9RkiWXw2KSHHeyGrFY0INJeiky1ZtUFhWhopcHJWSnfCmVC15YFpnM5xOKpITjHAFhGt98MaYR+mS+3zoUFrjYbaZRh2TR2lFWsbR8YU1uaTYqJZ1HX1PBCub6aS3vjQm0Fwa+hAtR/gMymXJc5qtruTO4NbqYtMj3Z9eIgoVB+56SLAXlIF1Uo1pjvV0mx1hWNNiIc10ujF/wl/nnKF6icOcmrfm9XhOtsvUYBsE/wAIJZw3LKXgSX+hJbOl+zLAwJZK1xiL8n/nM1IJZDn+Wu6z0OzRaj9S7T16+brMw1oaqjk56saM8n5z725fizJj+ur6gnPBWnoyHPaCHgHdB2PKQNY0ZlwRM6dVncRaEWQDLAboyMq3FXxK9UbusNcDFpYw6bdnuJlNVf6y9yxwyvkUrt5YtgfkLyoW42z1PVtVWsV9P8eE/A/tnYjXf34xvba3K8Y1/3DTi7uuydNrSR/XhA+pevz68VWCbY+j746Yi8Lz7altePphkjfJAezodobKvMplXzqInopIWNovyemw/+1E7WZbkQIOAXg1WC1+Y/df+dffRGuGRdDerfRLmA5XLej1M/wE3WQ7b9KwlAo6XJ4hnQKwyDCqYP/ButBXW1AOnnZpCq59gGbiccZJsTMZB4OP95yFPgz8//IeDgma2PDixVmDEp0SGHhN7dlSoNa5eoglblqzJu/TcTA6jmQFA3ef0GiA3QzBjmyB4bz0bFybh8XA1brVIVlsjRwXb3/UYaVqsP6Hy1QDUpZofXIJs5lK0hUd0ECdaNFXXgHd25ifPocp09WLFyK92H6i3ABDZ7pu3b4lTUt6kHt6LTVsKkyylmYf2iMHnCcmfy4uxGTXxRjPjMgKL8pd++OZ3q62jLBuoTjgdj6pccwDvD+NYQ2FFeHmBzxyTLqUyKltYiyFlJHWLKOcXyeDHzRhHic+e/wn3VhM3NdrvtqYWA9m72Ye1L1I7VX7KatGurG6CeiFiY5xHxxpLT7dF0fJ7uxRye4JnRyYQuU7iK72qCKjgYjwjCIha4qPi5Q/x6S+uVe7yX5Eb73L3eB+IlkyW9wPHmSOcE4GpbMU96tK8xoxT0T9eQlj050GDnJ/oI2XHfZTs1bIxsjfZqW03g==",
|
||||
"salt": "wXR3RnPmsoA3ncrixIvaUw==",
|
||||
"iv": "/Zjn1OXsLJhA43n/"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"accounts": [
|
||||
{
|
||||
"id": "first",
|
||||
"account": {
|
||||
"ciphertext": "icnpxLmr/H7FIIOaEf7DYNLuM6uhh7poEppXpYCllQD33TjY+8eLtVvhEQmjX60IQeFOd+1JCcrHa2B12vlBAYlfM4gBxA6d2ZJ8+Dw/vNvBNyChiyUx2euV3vPGOs22r/XDBsmEeF40XZcXftQZa2kzYaPnkbP+eiMOIWkcY4FYOEHwx5SxT4VBPZIrVTC3iDalJLWybVbbw/Bc2zbzEXI1ckg4Ccydj95SMil9BiyDpALfZqwlai7I97S+BjmcVxSCsYqFjTkRUHVMjrEr7fWHKU4DIOM=",
|
||||
"salt": "CtnbfkxTybqz0U4cPHW2jQ==",
|
||||
"iv": "77ZROU6dAMttEWwS"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "second",
|
||||
"account": {
|
||||
"ciphertext": "nsqZHdQFlskglc5izKgnr8sBwdMmd82h2Rnjdos9EUca3cqkUdFYEjZDsK8OGR3GZ9alLTNt/1U97Rvvr2HPAWbzl23FW2YXaLTA6yj6ZwQK5w0MYE061NYbcxNHuzT9f5aQWkGULAk4RWb5t8eUX7y/NdJr3tA5xuGOLhooTfBB98/4RpupDsYGZp1DPC/GMFppOA3GmKs9bacZm805Bhfq5mwhXab1SjJQpFHMHisCMhxo/oLqulKML1tQMetBdqDTjJmPpdUnd1mi",
|
||||
"salt": "J2TMLjKv4dkZ/kXso9FGhg==",
|
||||
"iv": "CTqqoMa4LetvBKCP"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"package": {
|
||||
"productName": "nym-wallet",
|
||||
"version": "1.0.7"
|
||||
"version": "1.0.8"
|
||||
},
|
||||
"build": {
|
||||
"distDir": "../dist",
|
||||
|
||||
@@ -75,7 +75,7 @@ export const BondedMixnode = ({
|
||||
id: 'pm-cell',
|
||||
},
|
||||
{
|
||||
cell: `${operatorRewards.amount} ${operatorRewards.denom}`,
|
||||
cell: operatorRewards ? `${operatorRewards.amount} ${operatorRewards.denom}` : '-',
|
||||
id: 'operator-rewards-cell',
|
||||
},
|
||||
{
|
||||
@@ -86,7 +86,7 @@ export const BondedMixnode = ({
|
||||
cell: (
|
||||
<BondedMixnodeActions
|
||||
onActionSelect={onActionSelect}
|
||||
disabledRedeemAndCompound={Number(mixnode.operatorRewards.amount) === 0}
|
||||
disabledRedeemAndCompound={(operatorRewards && Number(operatorRewards.amount) === 0) || false}
|
||||
/>
|
||||
),
|
||||
id: 'actions-cell',
|
||||
|
||||
@@ -43,7 +43,9 @@ export const CompoundRewardsModal = ({
|
||||
>
|
||||
<ModalListItem
|
||||
label="Rewards to redeem"
|
||||
value={`${node.operatorRewards.amount} ${node.operatorRewards.denom.toUpperCase()}`}
|
||||
value={
|
||||
node.operatorRewards ? `${node.operatorRewards.amount} ${node.operatorRewards.denom.toUpperCase()}` : '-'
|
||||
}
|
||||
divider
|
||||
/>
|
||||
<ModalFee fee={fee} isLoading={isFeeLoading} divider />
|
||||
|
||||
@@ -43,7 +43,9 @@ export const RedeemRewardsModal = ({
|
||||
>
|
||||
<ModalListItem
|
||||
label="Rewards to redeem"
|
||||
value={`${node.operatorRewards.amount} ${node.operatorRewards.denom.toUpperCase()}`}
|
||||
value={
|
||||
node.operatorRewards ? `${node.operatorRewards.amount} ${node.operatorRewards.denom.toUpperCase()}` : '-'
|
||||
}
|
||||
divider
|
||||
/>
|
||||
<ModalFee fee={fee} isLoading={isFeeLoading} divider />
|
||||
|
||||
@@ -61,7 +61,9 @@ export const UnbondModal = ({ node, onConfirm, onClose, onError }: Props) => {
|
||||
{isMixnode(node) && (
|
||||
<ModalListItem
|
||||
label="Operator rewards"
|
||||
value={`${node.operatorRewards.amount} ${node.operatorRewards.denom.toUpperCase()}`}
|
||||
value={
|
||||
node.operatorRewards ? `${node.operatorRewards.amount} ${node.operatorRewards.denom.toUpperCase()}` : '-'
|
||||
}
|
||||
divider
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -28,7 +28,7 @@ type ClientAddressProps = {
|
||||
showEntireAddress?: boolean;
|
||||
};
|
||||
|
||||
export const ClientAddressDisplay: FC<ClientAddressProps & { address?: string }> = ({
|
||||
export const ClientAddressDisplay: FC<ClientAddressProps & { address?: string } > = ({
|
||||
withLabel,
|
||||
withCopy,
|
||||
showEntireAddress,
|
||||
@@ -44,7 +44,7 @@ export const ClientAddressDisplay: FC<ClientAddressProps & { address?: string }>
|
||||
)}
|
||||
|
||||
<AddressTooltip address={address} visible={!showEntireAddress}>
|
||||
<Typography variant="body2" component="span" sx={{ mr: 1, color: 'text.primary', fontWeight: 400 }}>
|
||||
<Typography data-testid="accountNumber" variant="body2" component="span" sx={{ mr: 1, color: 'text.primary', fontWeight: 400 }}>
|
||||
{showEntireAddress ? address || '' : splice(6, address)}
|
||||
</Typography>
|
||||
</AddressTooltip>
|
||||
|
||||
@@ -37,6 +37,8 @@ export const CopyToClipboard = ({ text = '', iconButton }: { text?: string; icon
|
||||
}}
|
||||
>
|
||||
{!copied ? <ContentCopy sx={{ fontSize: 14 }} /> : <Check color="success" sx={{ fontSize: 14 }} />}
|
||||
{!copied ? <ContentCopy data-testid="copyIcon"
|
||||
fontSize="small" /> : <Check color="success" />}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
@@ -98,7 +98,7 @@ export const DelegationsActionsMenu: React.FC<{
|
||||
<ActionsMenuItem title="Undelegate" Icon={<Undelegate />} onClick={() => handleActionSelect('undelegate')} />
|
||||
<ActionsMenuItem
|
||||
title="Redeem"
|
||||
description="Trasfer your rewards to your balance"
|
||||
description="Transfer your rewards to your balance"
|
||||
Icon={<Typography sx={{ pl: 1 }}>R</Typography>}
|
||||
onClick={() => handleActionSelect('redeem')}
|
||||
disabled={disableRedeemingRewards}
|
||||
|
||||
@@ -16,12 +16,13 @@ import {
|
||||
import LockOutlinedIcon from '@mui/icons-material/LockOutlined';
|
||||
import { visuallyHidden } from '@mui/utils';
|
||||
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
|
||||
import { DelegationWithEverything } from '@nymproject/types';
|
||||
import { DelegationEvent, DelegationWithEverything } from '@nymproject/types';
|
||||
import { Link } from '@nymproject/react/link/Link';
|
||||
import { format, formatDistanceToNow, parseISO } from 'date-fns';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import { tableCellClasses } from '@mui/material/TableCell';
|
||||
import { DelegationListItemActions, DelegationsActionsMenu } from './DelegationActions';
|
||||
import { DelegationWithEvent, isPendingDelegation, TDelegations } from '../../context/delegations';
|
||||
|
||||
const StyledTooltipTableCell = styled(TableCell)(({ theme }) => ({
|
||||
[`&.${tableCellClasses.head}`]: {
|
||||
@@ -71,13 +72,30 @@ function descendingComparator<T>(a: T, b: T, orderBy: keyof T) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function sortPendingDelegation(a: DelegationWithEvent, b: DelegationWithEvent) {
|
||||
if (isPendingDelegation(a) && isPendingDelegation(b)) return 0;
|
||||
if (isPendingDelegation(b)) return -1;
|
||||
if (isPendingDelegation(a)) return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
function getComparator<Key extends keyof DelegationWithEverything>(
|
||||
order: Order,
|
||||
orderBy: Key,
|
||||
): (a: DelegationWithEverything, b: DelegationWithEverything) => number {
|
||||
): (a: DelegationWithEvent, b: DelegationWithEvent) => number {
|
||||
return order === 'desc'
|
||||
? (a, b) => descendingComparator(a, b, orderBy)
|
||||
: (a, b) => -descendingComparator(a, b, orderBy);
|
||||
? (a, b) => {
|
||||
const pendingSort = sortPendingDelegation(a, b);
|
||||
if (pendingSort === 2)
|
||||
return descendingComparator(a as DelegationWithEverything, b as DelegationWithEverything, orderBy);
|
||||
return pendingSort;
|
||||
}
|
||||
: (a, b) => {
|
||||
const pendingSort = -sortPendingDelegation(a, b);
|
||||
if (pendingSort === 2)
|
||||
return -descendingComparator(a as DelegationWithEverything, b as DelegationWithEverything, orderBy);
|
||||
return pendingSort;
|
||||
};
|
||||
}
|
||||
|
||||
const EnhancedTableHead: React.FC<EnhancedTableProps> = ({ order, orderBy, onRequestSort }) => {
|
||||
@@ -119,7 +137,7 @@ const EnhancedTableHead: React.FC<EnhancedTableProps> = ({ order, orderBy, onReq
|
||||
|
||||
export const DelegationList: React.FC<{
|
||||
isLoading?: boolean;
|
||||
items?: DelegationWithEverything[];
|
||||
items?: TDelegations;
|
||||
onItemActionClick?: (item: DelegationWithEverything, action: DelegationListItemActions) => void;
|
||||
explorerUrl: string;
|
||||
}> = ({ isLoading, items, onItemActionClick, explorerUrl }) => {
|
||||
@@ -132,6 +150,15 @@ export const DelegationList: React.FC<{
|
||||
setOrderBy(property);
|
||||
};
|
||||
|
||||
const getRewardValue = (item: DelegationWithEvent) => {
|
||||
if (isPendingDelegation(item)) {
|
||||
return '';
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
const { accumulated_rewards } = item;
|
||||
return !accumulated_rewards ? '-' : `${accumulated_rewards.amount} ${accumulated_rewards.denom}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<TableContainer>
|
||||
<Table sx={{ width: '100%' }}>
|
||||
@@ -149,12 +176,19 @@ export const DelegationList: React.FC<{
|
||||
noIcon
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>{!item.avg_uptime_percent ? '-' : `${item.avg_uptime_percent}%`}</TableCell>
|
||||
<TableCell>{!item.profit_margin_percent ? '-' : `${item.profit_margin_percent}%`}</TableCell>
|
||||
<TableCell>
|
||||
{!item.stake_saturation ? '-' : `${Math.round(item.stake_saturation * 100000) / 1000}%`}
|
||||
{!isPendingDelegation(item) && (!item.avg_uptime_percent ? '-' : `${item.avg_uptime_percent}%`)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{!isPendingDelegation(item) && (!item.profit_margin_percent ? '-' : `${item.profit_margin_percent}%`)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{!isPendingDelegation(item) &&
|
||||
(!item.stake_saturation ? '-' : `${Math.round(item.stake_saturation * 100000) / 1000}%`)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{!isPendingDelegation(item) && format(new Date(item.delegated_on_iso_datetime), 'dd/MM/yyyy')}
|
||||
</TableCell>
|
||||
<TableCell>{format(new Date(item.delegated_on_iso_datetime), 'dd/MM/yyyy')}</TableCell>
|
||||
<TableCell>
|
||||
<Tooltip
|
||||
placement="right"
|
||||
@@ -169,55 +203,65 @@ export const DelegationList: React.FC<{
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{item.history.map((historyItem) => (
|
||||
<TableRow key={`${historyItem.block_height}`}>
|
||||
<StyledTooltipTableCell>
|
||||
{formatDistanceToNow(parseISO(historyItem.delegated_on_iso_datetime), {
|
||||
addSuffix: true,
|
||||
})}
|
||||
</StyledTooltipTableCell>
|
||||
<StyledTooltipTableCell>
|
||||
<Typography fontSize="inherit" noWrap>
|
||||
{`${historyItem.amount.amount} ${historyItem.amount.denom}`}
|
||||
{historyItem.uses_vesting_contract_tokens && (
|
||||
<LockOutlinedIcon fontSize="inherit" sx={{ ml: 0.5 }} />
|
||||
)}
|
||||
</Typography>
|
||||
</StyledTooltipTableCell>
|
||||
<StyledTooltipTableCell>{historyItem.block_height}</StyledTooltipTableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
{!isPendingDelegation(item) &&
|
||||
item.history.map((historyItem) => (
|
||||
<TableRow key={`${historyItem.block_height}`}>
|
||||
<StyledTooltipTableCell>
|
||||
{formatDistanceToNow(parseISO(historyItem.delegated_on_iso_datetime), {
|
||||
addSuffix: true,
|
||||
})}
|
||||
</StyledTooltipTableCell>
|
||||
<StyledTooltipTableCell>
|
||||
<Typography fontSize="inherit" noWrap>
|
||||
{`${historyItem.amount.amount} ${historyItem.amount.denom}`}
|
||||
{historyItem.uses_vesting_contract_tokens && (
|
||||
<LockOutlinedIcon fontSize="inherit" sx={{ ml: 0.5 }} />
|
||||
)}
|
||||
</Typography>
|
||||
</StyledTooltipTableCell>
|
||||
<StyledTooltipTableCell>{historyItem.block_height}</StyledTooltipTableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
}
|
||||
arrow
|
||||
>
|
||||
<span
|
||||
style={{ cursor: 'pointer', textTransform: 'uppercase' }}
|
||||
>{`${item.amount.amount} ${item.amount.denom}`}</span>
|
||||
<span style={{ cursor: 'pointer', textTransform: 'uppercase' }}>
|
||||
{!isPendingDelegation(item) && `${item.amount.amount} ${item.amount.denom}`}
|
||||
</span>
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
<TableCell sx={{ textTransform: 'uppercase' }}>
|
||||
{!item.accumulated_rewards
|
||||
? '-'
|
||||
: `${item.accumulated_rewards.amount} ${item.accumulated_rewards.denom}`}
|
||||
</TableCell>
|
||||
<TableCell sx={{ textTransform: 'uppercase' }}>{getRewardValue(item)}</TableCell>
|
||||
|
||||
<TableCell align="right">
|
||||
{!item.pending_events.length ? (
|
||||
{!isPendingDelegation(item) && !item.pending_events.length && (
|
||||
<DelegationsActionsMenu
|
||||
isPending={undefined}
|
||||
onActionClick={(action) => (onItemActionClick ? onItemActionClick(item, action) : undefined)}
|
||||
disableRedeemingRewards={!item.accumulated_rewards || item.accumulated_rewards.amount === '0'}
|
||||
disableCompoundRewards={!item.accumulated_rewards || item.accumulated_rewards.amount === '0'}
|
||||
/>
|
||||
) : (
|
||||
)}
|
||||
{!isPendingDelegation(item) && item.pending_events.length > 0 && (
|
||||
<Tooltip
|
||||
title="There will be a new epoch roughly every hour when your changes will take effect"
|
||||
title="Your changes will take effect when
|
||||
the new epoch starts. There is a new
|
||||
epoch every hour."
|
||||
arrow
|
||||
>
|
||||
<Chip label="Pending events" />
|
||||
<Chip label="Pending Events" />
|
||||
</Tooltip>
|
||||
)}
|
||||
{isPendingDelegation(item) && (
|
||||
<Tooltip
|
||||
title={`Your delegation of ${item.amount?.amount} ${item.amount?.denom} will take effect
|
||||
when the new epoch starts. There is a new
|
||||
epoch every hour.`}
|
||||
arrow
|
||||
>
|
||||
<Chip label="Pending Events" />
|
||||
</Tooltip>
|
||||
)}
|
||||
</TableCell>
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
import React, { FC } from 'react';
|
||||
import LockOutlinedIcon from '@mui/icons-material/LockOutlined';
|
||||
import {
|
||||
Box,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TableSortLabel,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from '@mui/material';
|
||||
import { CopyToClipboard } from '@nymproject/react/clipboard/CopyToClipboard';
|
||||
import { DelegationEvent } from '@nymproject/types';
|
||||
import { ArrowDropDown } from '@mui/icons-material';
|
||||
import { visuallyHidden } from '@mui/utils';
|
||||
import { Link } from '@nymproject/react/link/Link';
|
||||
|
||||
type Order = 'asc' | 'desc';
|
||||
|
||||
interface HeadCell {
|
||||
id: keyof DelegationEvent;
|
||||
label: string;
|
||||
sortable: boolean;
|
||||
disablePadding?: boolean;
|
||||
}
|
||||
|
||||
interface EnhancedTableProps {
|
||||
onRequestSort: (event: React.MouseEvent<unknown>, property: keyof DelegationEvent) => void;
|
||||
order: Order;
|
||||
orderBy: string;
|
||||
}
|
||||
|
||||
const headCells: HeadCell[] = [
|
||||
{ id: 'node_identity', label: 'Node ID', sortable: true },
|
||||
{ id: 'amount', label: 'Delegation', sortable: true },
|
||||
{ id: 'kind', label: 'Type', sortable: true },
|
||||
];
|
||||
|
||||
function descendingComparator<T>(a: T, b: T, orderBy: keyof T) {
|
||||
if (b[orderBy] < a[orderBy]) {
|
||||
return -1;
|
||||
}
|
||||
if (b[orderBy] > a[orderBy]) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getComparator<Key extends keyof DelegationEvent>(
|
||||
order: Order,
|
||||
orderBy: Key,
|
||||
): (a: DelegationEvent, b: DelegationEvent) => number {
|
||||
return order === 'desc'
|
||||
? (a, b) => descendingComparator(a, b, orderBy)
|
||||
: (a, b) => -descendingComparator(a, b, orderBy);
|
||||
}
|
||||
|
||||
const EnhancedTableHead: React.FC<EnhancedTableProps> = ({ order, orderBy, onRequestSort }) => {
|
||||
const createSortHandler = (property: keyof DelegationEvent) => (event: React.MouseEvent<unknown>) => {
|
||||
onRequestSort(event, property);
|
||||
};
|
||||
|
||||
return (
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
{headCells.map((headCell) => (
|
||||
<TableCell
|
||||
key={headCell.id}
|
||||
align="left"
|
||||
padding={headCell.disablePadding ? 'none' : 'normal'}
|
||||
sortDirection={orderBy === headCell.id ? order : false}
|
||||
color="secondary"
|
||||
>
|
||||
<TableSortLabel
|
||||
active={orderBy === headCell.id}
|
||||
direction={orderBy === headCell.id ? order : 'asc'}
|
||||
onClick={createSortHandler(headCell.id)}
|
||||
IconComponent={ArrowDropDown}
|
||||
>
|
||||
{headCell.label}
|
||||
{orderBy === headCell.id ? (
|
||||
<Box component="span" sx={visuallyHidden}>
|
||||
{order === 'desc' ? 'sorted descending' : 'sorted ascending'}
|
||||
</Box>
|
||||
) : null}
|
||||
</TableSortLabel>
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
);
|
||||
};
|
||||
|
||||
export const PendingEvents: FC<{ pendingEvents: DelegationEvent[]; explorerUrl: string }> = ({
|
||||
pendingEvents,
|
||||
explorerUrl,
|
||||
}) => {
|
||||
const [order, setOrder] = React.useState<Order>('asc');
|
||||
const [orderBy, setOrderBy] = React.useState<keyof DelegationEvent>('node_identity');
|
||||
|
||||
const handleRequestSort = (event: React.MouseEvent<unknown>, property: keyof DelegationEvent) => {
|
||||
const isAsc = orderBy === property && order === 'asc';
|
||||
setOrder(isAsc ? 'desc' : 'asc');
|
||||
setOrderBy(property);
|
||||
};
|
||||
|
||||
if (pendingEvents.length === 0) return <Typography>No pending events</Typography>;
|
||||
|
||||
return (
|
||||
<TableContainer>
|
||||
<Table sx={{ width: '100%' }}>
|
||||
<EnhancedTableHead order={order} orderBy={orderBy} onRequestSort={handleRequestSort} />
|
||||
<TableBody>
|
||||
{pendingEvents.sort(getComparator(order, orderBy)).map((item) => (
|
||||
<TableRow key={`${item.node_identity}-${item.block_height}`}>
|
||||
<TableCell>
|
||||
<CopyToClipboard
|
||||
sx={{ fontSize: 16, mr: 1 }}
|
||||
value={item.node_identity}
|
||||
tooltip={
|
||||
<>
|
||||
Copy identity key <strong>{item.node_identity}</strong> to clipboard
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<Tooltip
|
||||
title={
|
||||
<>
|
||||
Click to view <strong>{item.node_identity}</strong> in the Network Explorer
|
||||
</>
|
||||
}
|
||||
placement="right"
|
||||
arrow
|
||||
>
|
||||
<Link
|
||||
target="_blank"
|
||||
href={`${explorerUrl}/network-components/mixnode/${item.node_identity}`}
|
||||
text={`${item.node_identity.slice(0, 6)}...${item.node_identity.slice(-6)}`}
|
||||
/>
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
<TableCell>{!item.amount ? '-' : `${item.amount?.amount} ${item.amount?.denom.toUpperCase()}`}</TableCell>
|
||||
<TableCell>
|
||||
{item.kind === 'Delegate' ? 'Delegation' : 'Undelegation'}
|
||||
{item.proxy && (
|
||||
<Tooltip title="Uses tokens for your vesting account" arrow>
|
||||
<LockOutlinedIcon fontSize="inherit" sx={{ ml: 0.5 }} />
|
||||
</Tooltip>
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
);
|
||||
};
|
||||
@@ -18,10 +18,11 @@ export const Mnemonic = ({
|
||||
Below is your 24 word mnemonic, make sure to store it in a safe place for accessing your wallet in the future
|
||||
</Typography>
|
||||
</Warning>
|
||||
<TextField multiline rows={3} value={mnemonic} fullWidth />
|
||||
<TextField multiline rows={3} value={mnemonic} fullWidth data-testid="mnemonicPhrase"/>
|
||||
|
||||
<Button
|
||||
color="inherit"
|
||||
data-testid="copyMnemonic"
|
||||
disableElevation
|
||||
size="large"
|
||||
onClick={() => {
|
||||
|
||||
@@ -56,7 +56,7 @@ export const ConfirmationModal = ({
|
||||
const ConfirmButton =
|
||||
typeof confirmButton === 'string' ? (
|
||||
<Button onClick={onConfirm} variant="contained" fullWidth disabled={disabled} sx={{ py: 1.6 }}>
|
||||
<Typography variant="button" fontSize="large">
|
||||
<Typography variant="button" fontSize="large" data-testid={confirmButton}>
|
||||
{confirmButton}
|
||||
</Typography>
|
||||
</Button>
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Box, Stack, Typography, TypographyProps } from '@mui/material';
|
||||
import { ModalDivider } from './ModalDivider';
|
||||
import { fontWeight } from '@mui/system';
|
||||
|
||||
type TFontWeight = 'strong' | 'light';
|
||||
|
||||
export const ModalListItem: React.FC<{
|
||||
label: string;
|
||||
|
||||
@@ -16,7 +16,7 @@ const NetworkItem: React.FC<{ title: string; isSelected: boolean; onSelect: () =
|
||||
isSelected,
|
||||
onSelect,
|
||||
}) => (
|
||||
<ListItem button onClick={onSelect}>
|
||||
<ListItem button onClick={onSelect} data-testid={title}>
|
||||
<ListItemIcon>{isSelected && <CheckSharp color="success" />}</ListItemIcon>
|
||||
<ListItemText>{title}</ListItemText>
|
||||
</ListItem>
|
||||
@@ -38,6 +38,7 @@ export const NetworkSelector = () => {
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
data-testid="networkEnv"
|
||||
variant="text"
|
||||
color="inherit"
|
||||
sx={{ color: 'text.primary' }}
|
||||
|
||||
@@ -31,7 +31,7 @@ export const NymCard: React.FC<{
|
||||
{noPadding ? (
|
||||
<CardContentNoPadding>{children}</CardContentNoPadding>
|
||||
) : (
|
||||
<CardContent sx={{ p: 3 }}>{children}</CardContent>
|
||||
<CardContent sx={{ p: 3 }} >{children}</CardContent>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
|
||||
@@ -62,6 +62,9 @@ export const SendInputModal = ({
|
||||
fullWidth
|
||||
onChange={(e) => onAddressChange(e.target.value)}
|
||||
value={toAddress}
|
||||
inputProps={{
|
||||
"data-testid": "recipientAddress",
|
||||
}}
|
||||
/>
|
||||
<CurrencyFormField
|
||||
placeholder="Amount"
|
||||
@@ -73,7 +76,7 @@ export const SendInputModal = ({
|
||||
initialValue={amount?.amount}
|
||||
denom={denom}
|
||||
/>
|
||||
<Typography fontSize="smaller" sx={{ color: 'error.main' }}>
|
||||
<Typography fontSize="smaller" sx={{ color: 'error.main' }} >
|
||||
{error}
|
||||
</Typography>
|
||||
</Stack>
|
||||
|
||||
@@ -31,7 +31,7 @@ export const SendSuccessModal = ({
|
||||
{txDetails && (
|
||||
<>
|
||||
<Typography variant="h5">{txDetails.amount}</Typography>
|
||||
<Link href={txDetails.txUrl} target="_blank" sx={{ ml: 1 }} text="View on blockchain" />
|
||||
<Link href={txDetails.txUrl} target="_blank" sx={{ ml: 1 }} text="View on blockchain" data-testid="viewOnBlockchain"/>
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
@@ -13,6 +13,9 @@ export const MnemonicInput: React.FC<{
|
||||
<Stack spacing={2}>
|
||||
<TextField
|
||||
label="Mnemonic"
|
||||
inputProps={{
|
||||
"data-testid": "mnemonicInput",
|
||||
}}
|
||||
type={showPassword ? 'input' : 'password'}
|
||||
value={mnemonic}
|
||||
onChange={(e) => onUpdateMnemonic(e.target.value)}
|
||||
@@ -63,6 +66,9 @@ export const PasswordInput: React.FC<{
|
||||
</IconButton>
|
||||
),
|
||||
}}
|
||||
inputProps={{
|
||||
"data-testid": label,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
{error && <Error message={error} />}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { FeeDetails, DecCoin, MixnodeStatus, TransactionExecuteResult } from '@nymproject/types';
|
||||
import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
||||
import { isGateway, isMixnode, Network, TBondGatewayArgs, TBondMixNodeArgs } from 'src/types';
|
||||
import { isGateway, isMixnode, TBondGatewayArgs, TBondMixNodeArgs } from 'src/types';
|
||||
import { Console } from 'src/utils/console';
|
||||
import {
|
||||
bondGateway as bondGatewayRequest,
|
||||
@@ -28,19 +28,6 @@ import {
|
||||
import { useCheckOwnership } from '../hooks/useCheckOwnership';
|
||||
import { AppContext } from './main';
|
||||
|
||||
const bonded: TBondedMixnode = {
|
||||
name: 'Monster node',
|
||||
identityKey: 'B2Xx4haarLWMajX8w259oHjtRZsC7nHwagbWrJNiA3QC',
|
||||
bond: { denom: 'nym', amount: '1234' },
|
||||
delegators: 123,
|
||||
operatorRewards: { denom: 'nym', amount: '12' },
|
||||
profitMargin: 10,
|
||||
stake: { denom: 'nym', amount: '99' },
|
||||
stakeSaturation: 99,
|
||||
status: 'active',
|
||||
};
|
||||
|
||||
// TODO add relevant data
|
||||
export type TBondedMixnode = {
|
||||
name?: string;
|
||||
identityKey: string;
|
||||
@@ -48,13 +35,12 @@ export type TBondedMixnode = {
|
||||
bond: DecCoin;
|
||||
stakeSaturation: number;
|
||||
profitMargin: number;
|
||||
operatorRewards: DecCoin;
|
||||
operatorRewards?: DecCoin;
|
||||
delegators: number;
|
||||
status: MixnodeStatus;
|
||||
proxy?: string;
|
||||
};
|
||||
|
||||
// TODO add relevant data
|
||||
export interface TBondedGateway {
|
||||
name: string;
|
||||
identityKey: string;
|
||||
@@ -173,7 +159,12 @@ export const BondingContextProvider = ({ children }: { children?: React.ReactNod
|
||||
if (ownership.hasOwnership && ownership.nodeType === 'mixnode' && clientDetails) {
|
||||
try {
|
||||
const data = await getMixnodeBondDetails();
|
||||
const operatorRewards = await getOperatorRewards(clientDetails?.client_address);
|
||||
let operatorRewards;
|
||||
try {
|
||||
operatorRewards = await getOperatorRewards(clientDetails?.client_address);
|
||||
} catch (e) {
|
||||
console.warn(`get_operator_rewards request failed: ${e}`);
|
||||
}
|
||||
if (data) {
|
||||
const { status, stakeSaturation, numberOfDelegators } = await getAdditionalMixnodeDetails(
|
||||
data.mix_node.identity_key,
|
||||
@@ -195,6 +186,7 @@ export const BondingContextProvider = ({ children }: { children?: React.ReactNod
|
||||
} as TBondedMixnode);
|
||||
}
|
||||
} catch (e: any) {
|
||||
console.warn(e);
|
||||
setError(`While fetching current bond state, an error occurred: ${e}`);
|
||||
}
|
||||
}
|
||||
@@ -211,7 +203,6 @@ export const BondingContextProvider = ({ children }: { children?: React.ReactNod
|
||||
ip: data.gateway.host,
|
||||
location: data.gateway.location,
|
||||
bond: data.pledge_amount,
|
||||
delegators: bonded.delegators,
|
||||
proxy: data.proxy,
|
||||
} as TBondedGateway);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import { TPoolOption } from 'src/components';
|
||||
export type TDelegationContext = {
|
||||
isLoading: boolean;
|
||||
error?: string;
|
||||
delegations?: DelegationWithEverything[];
|
||||
delegations?: TDelegations;
|
||||
pendingDelegations?: DelegationEvent[];
|
||||
totalDelegations?: string;
|
||||
totalRewards?: string;
|
||||
@@ -35,6 +35,12 @@ export type TDelegationTransaction = {
|
||||
transactionUrl: string;
|
||||
};
|
||||
|
||||
export type DelegationWithEvent = DelegationWithEverything | DelegationEvent;
|
||||
export type TDelegations = DelegationWithEvent[];
|
||||
|
||||
export const isPendingDelegation = (delegation: DelegationWithEvent): delegation is DelegationEvent =>
|
||||
'kind' in delegation;
|
||||
|
||||
export const DelegationContext = createContext<TDelegationContext>({
|
||||
isLoading: true,
|
||||
refresh: async () => undefined,
|
||||
@@ -51,7 +57,7 @@ export const DelegationContextProvider: FC<{
|
||||
}> = ({ network, children }) => {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState<string>();
|
||||
const [delegations, setDelegations] = useState<undefined | DelegationWithEverything[]>();
|
||||
const [delegations, setDelegations] = useState<undefined | TDelegations>();
|
||||
const [totalDelegations, setTotalDelegations] = useState<undefined | string>();
|
||||
const [totalRewards, setTotalRewards] = useState<undefined | string>();
|
||||
const [pendingDelegations, setPendingDelegations] = useState<DelegationEvent[]>();
|
||||
@@ -87,8 +93,13 @@ export const DelegationContextProvider: FC<{
|
||||
const data = await getDelegationSummary();
|
||||
const pending = await getAllPendingDelegations();
|
||||
|
||||
const pendingOnNewNodes = pending.filter((event) => {
|
||||
const some = data.delegations.some(({ node_identity }) => node_identity === event.node_identity);
|
||||
return !some;
|
||||
});
|
||||
|
||||
setPendingDelegations(pending);
|
||||
setDelegations(data.delegations);
|
||||
setDelegations([...data.delegations, ...pendingOnNewNodes]);
|
||||
setTotalDelegations(`${data.total_delegations.amount} ${data.total_delegations.denom}`);
|
||||
setTotalRewards(`${data.total_rewards.amount} ${data.total_rewards.denom}`);
|
||||
} catch (e) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { TransactionExecuteResult } from '@nymproject/types';
|
||||
import { DelegationWithEverything, TransactionExecuteResult } from '@nymproject/types';
|
||||
import { RewardsContext, TRewardsTransaction } from '../rewards';
|
||||
import { useDelegationContext } from '../delegations';
|
||||
import { mockSleep } from './utils';
|
||||
@@ -9,7 +9,7 @@ export const MockRewardsContextProvider: FC = ({ children }) => {
|
||||
const [error, setError] = useState<string>();
|
||||
const [totalRewards, setTotalRewards] = useState<undefined | string>();
|
||||
const { delegations } = useDelegationContext();
|
||||
const delegationsHash = delegations?.map((d) => d.accumulated_rewards).join(',');
|
||||
const delegationsHash = delegations?.map((d) => (d as DelegationWithEverything).accumulated_rewards).join(',');
|
||||
|
||||
const resetState = () => {
|
||||
setIsLoading(true);
|
||||
@@ -19,7 +19,7 @@ export const MockRewardsContextProvider: FC = ({ children }) => {
|
||||
|
||||
const recalculate = () => {
|
||||
const sum: number | undefined = delegations
|
||||
?.map((d) => (d.accumulated_rewards ? Number(10) : Number(0)))
|
||||
?.map((d) => ((d as DelegationWithEverything).accumulated_rewards ? Number(10) : Number(0)))
|
||||
.reduce((acc, cur) => acc + cur, Number(0));
|
||||
|
||||
setTotalRewards(sum ? `${sum} NYM` : undefined);
|
||||
|
||||
@@ -6,7 +6,7 @@ export const Title = ({ title }: { title: string }) => (
|
||||
);
|
||||
|
||||
export const Subtitle = ({ subtitle }: { subtitle: string }) => (
|
||||
<Typography sx={{ color: 'common.white', textAlign: 'center', maxWidth: 450 }}>{subtitle}</Typography>
|
||||
<Typography data-testid={subtitle} sx={{ color: 'common.white', textAlign: 'center', maxWidth: 450 }}>{subtitle}</Typography>
|
||||
);
|
||||
|
||||
export const SubtitleSlick = ({ subtitle }: { subtitle: string }) => (
|
||||
|
||||
@@ -53,7 +53,8 @@ export const WordTiles = ({
|
||||
return (
|
||||
<Grid container spacing={3} justifyContent="center">
|
||||
{mnemonicWords.map(({ name, index, disabled }) => (
|
||||
<Grid item xs={2} key={index} onClick={() => onClick?.({ name, index })}>
|
||||
<Grid
|
||||
item xs={2} key={index} onClick={() => onClick?.({ name, index })} data-testid="mnemonicWordTile">
|
||||
<WordTile
|
||||
mnemonicWord={name}
|
||||
index={showIndex ? index : undefined}
|
||||
@@ -79,7 +80,7 @@ const HiddenWord = ({ mnemonicWord }: { mnemonicWord: THiddenMnemonicWord }) =>
|
||||
</Box>
|
||||
</Fade>
|
||||
</Box>
|
||||
<Typography>{mnemonicWord.index}.</Typography>
|
||||
<Typography data-testid="wordIndex">{mnemonicWord.index}.</Typography>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ export const ConfirmMnemonic = () => {
|
||||
<Subtitle subtitle="Enter the mnemonic you wish to create a password for" />
|
||||
<MnemonicInput mnemonic={localMnemonic} onUpdateMnemonic={(mnc) => setLocalMnemonic(mnc)} error={error} />
|
||||
<Button
|
||||
data-testid="nextToPasswordCreation"
|
||||
size="large"
|
||||
variant="contained"
|
||||
fullWidth
|
||||
@@ -37,6 +38,7 @@ export const ConfirmMnemonic = () => {
|
||||
Next
|
||||
</Button>
|
||||
<Button
|
||||
data-testid="backToMnemonicSignIn"
|
||||
size="large"
|
||||
color="inherit"
|
||||
fullWidth
|
||||
|
||||
@@ -57,6 +57,7 @@ export const ConnectPassword = () => {
|
||||
label="Confirm password"
|
||||
/>
|
||||
<Button
|
||||
data-testid="createPasswordButton"
|
||||
size="large"
|
||||
variant="contained"
|
||||
disabled={password !== confirmedPassword || password.length === 0 || !isStrongPassword || isLoading}
|
||||
@@ -65,6 +66,7 @@ export const ConnectPassword = () => {
|
||||
{isLoading ? <CircularProgress size={25} /> : 'Create password'}
|
||||
</Button>
|
||||
<Button
|
||||
data-testid="backToStep1PasswordCreation"
|
||||
size="large"
|
||||
color="inherit"
|
||||
onClick={() => {
|
||||
|
||||
@@ -23,6 +23,7 @@ export const CreateMnemonic = () => {
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
data-testid="iSavedMnemonic"
|
||||
color="primary"
|
||||
disableElevation
|
||||
size="large"
|
||||
@@ -33,6 +34,7 @@ export const CreateMnemonic = () => {
|
||||
I saved my mnemonic
|
||||
</Button>
|
||||
<Button
|
||||
data-testid="backToWelcome"
|
||||
onClick={() => {
|
||||
resetState();
|
||||
navigate(-1);
|
||||
|
||||
@@ -57,13 +57,14 @@ export const CreatePassword = () => {
|
||||
/>
|
||||
<Button
|
||||
size="large"
|
||||
data-testid="nextStorePassword"
|
||||
variant="contained"
|
||||
disabled={password !== confirmedPassword || password.length === 0 || !isStrongPassword || isLoading}
|
||||
onClick={storePassword}
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
<Button size="large" color="info" onClick={handleSkip}>
|
||||
<Button size="large" color="info" onClick={handleSkip} data-testid="skipPasswordAndSignInWithMnemonic">
|
||||
Skip and sign in with mnemonic
|
||||
</Button>
|
||||
</Stack>
|
||||
|
||||
@@ -11,18 +11,18 @@ export const ExistingAccount = () => {
|
||||
<Title title="Welcome to Nym" />
|
||||
<SubtitleSlick subtitle="NEXT GENERATION OF PRIVACY" />
|
||||
<Stack spacing={2} sx={{ width: 300 }}>
|
||||
<Button variant="contained" size="large" onClick={() => navigate('/sign-in-mnemonic')} fullWidth>
|
||||
<Button variant="contained" size="large" onClick={() => navigate('/sign-in-mnemonic')} fullWidth data-testid="signInWithMnemonic">
|
||||
Sign in with mnemonic
|
||||
</Button>
|
||||
<Typography sx={{ textAlign: 'center', fontWeight: 600 }}>or</Typography>
|
||||
<Button variant="contained" size="large" fullWidth onClick={() => navigate('/sign-in-password')}>
|
||||
<Button variant="contained" size="large" fullWidth onClick={() => navigate('/sign-in-password')} data-testid="signInWithPassword">
|
||||
Sign in with password
|
||||
</Button>
|
||||
<Box display="flex" justifyContent="space-between">
|
||||
<Button color="inherit" onClick={() => navigate('/')}>
|
||||
<Button color="inherit" onClick={() => navigate('/')} data-testid="backToWelcomePage">
|
||||
Back
|
||||
</Button>
|
||||
<Button color="info" onClick={() => navigate('/forgot-password')}>
|
||||
<Button color="info" onClick={() => navigate('/forgot-password')} data-testid="forgotPassword">
|
||||
Forgot password?
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
@@ -39,15 +39,15 @@ export const SignInMnemonic = () => {
|
||||
>
|
||||
<Stack spacing={2}>
|
||||
<MnemonicInput mnemonic={mnemonic} onUpdateMnemonic={(mnc) => setMnemonic(mnc)} error={error} />
|
||||
<Button variant="contained" size="large" fullWidth type="submit">
|
||||
<Button variant="contained" size="large" fullWidth type="submit" data-testid="signInSubmitButton">
|
||||
Sign in with mnemonic
|
||||
</Button>
|
||||
<Box display="flex" justifyContent={passwordExists ? 'center' : 'space-between'}>
|
||||
<Button color="inherit" onClick={() => handlePageChange(-1)}>
|
||||
<Button color="inherit" onClick={() => handlePageChange(-1)} data-testid="backToSignInOptions">
|
||||
Back
|
||||
</Button>
|
||||
{!passwordExists && (
|
||||
<Button color="info" onClick={() => handlePageChange('/confirm-mnemonic')}>
|
||||
<Button color="info" onClick={() => handlePageChange('/confirm-mnemonic')} data-testid="goToCreatePassword">
|
||||
Create a password
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@@ -29,6 +29,7 @@ export const SignInPassword = () => {
|
||||
autoFocus
|
||||
/>
|
||||
<Button
|
||||
data-testid="signInPasswordButton"
|
||||
variant="contained"
|
||||
size="large"
|
||||
fullWidth
|
||||
@@ -38,6 +39,7 @@ export const SignInPassword = () => {
|
||||
</Button>
|
||||
<Box display="flex" justifyContent="space-between">
|
||||
<Button
|
||||
data-testid="backToSignInOptionsFromPassword"
|
||||
color="inherit"
|
||||
disableElevation
|
||||
onClick={() => {
|
||||
@@ -49,6 +51,7 @@ export const SignInPassword = () => {
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
data-testid="forgotPasswordButton"
|
||||
color="info"
|
||||
onClick={() => {
|
||||
setError(undefined);
|
||||
|
||||
@@ -52,6 +52,7 @@ export const VerifyMnemonic = () => {
|
||||
<Stack spacing={3} sx={{ width: 300 }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
data-testid="nextToStep3"
|
||||
fullWidth
|
||||
size="large"
|
||||
disabled={currentSelection !== numberOfRandomWords}
|
||||
@@ -59,7 +60,7 @@ export const VerifyMnemonic = () => {
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
<Button color="inherit" fullWidth size="large" onClick={() => navigate(-1)}>
|
||||
<Button color="inherit" fullWidth size="large" onClick={() => navigate(-1)} data-testid="backToStep1">
|
||||
Back
|
||||
</Button>
|
||||
</Stack>
|
||||
|
||||
@@ -19,6 +19,7 @@ export const WelcomeContent: React.FC<{}> = () => {
|
||||
variant="contained"
|
||||
size="large"
|
||||
onClick={() => navigate('/existing-account')}
|
||||
data-testid="signIn"
|
||||
>
|
||||
Sign in
|
||||
</Button>
|
||||
@@ -29,6 +30,7 @@ export const WelcomeContent: React.FC<{}> = () => {
|
||||
disableElevation
|
||||
size="large"
|
||||
onClick={() => navigate('/create-mnemonic')}
|
||||
data-testid="createAccount"
|
||||
>
|
||||
Create account
|
||||
</Button>
|
||||
|
||||
@@ -14,9 +14,8 @@ export const BalanceCard = () => {
|
||||
return (
|
||||
<NymCard
|
||||
title="Balance"
|
||||
data-testid="check-balance"
|
||||
borderless
|
||||
Action={<ClientAddress withCopy showEntireAddress />}
|
||||
Action={<ClientAddress withCopy showEntireAddress/>}
|
||||
>
|
||||
<Grid container direction="column" spacing={2}>
|
||||
<Grid item>
|
||||
@@ -27,7 +26,7 @@ export const BalanceCard = () => {
|
||||
)}
|
||||
{!userBalance.error && (
|
||||
<Typography
|
||||
data-testid="refresh-success"
|
||||
data-testid="nym-balance"
|
||||
sx={{
|
||||
color: 'text.primary',
|
||||
textTransform: 'uppercase',
|
||||
|
||||
@@ -30,7 +30,7 @@ export const Bond = () => {
|
||||
<NymCard title="Bond" subheader="Bond a mixnode or gateway" noPadding>
|
||||
{status === EnumRequestStatus.initial && (
|
||||
<Box sx={{ px: 3, mb: 1 }}>
|
||||
<Alert severity="warning">Always ensure you leave yourself enough funds to UNBOND</Alert>
|
||||
<Alert severity="warning" data-testid="fundsAlert">Always ensure you leave yourself enough funds to UNBOND</Alert>
|
||||
</Box>
|
||||
)}
|
||||
{ownership?.hasOwnership && (
|
||||
|
||||
@@ -5,7 +5,6 @@ import { DelegationWithEverything, FeeDetails, DecCoin } from '@nymproject/types
|
||||
import { Link } from '@nymproject/react/link/Link';
|
||||
import { AppContext, urls } from 'src/context/main';
|
||||
import { DelegationList } from 'src/components/Delegation/DelegationList';
|
||||
import { PendingEvents } from 'src/components/Delegation/PendingEvents';
|
||||
import { TPoolOption } from 'src/components';
|
||||
import { Console } from 'src/utils/console';
|
||||
import { CompoundModal } from 'src/components/Rewards/CompoundModal';
|
||||
@@ -49,7 +48,6 @@ export const Delegation: FC<{ isStorybook?: boolean }> = ({ isStorybook }) => {
|
||||
|
||||
const {
|
||||
delegations,
|
||||
pendingDelegations,
|
||||
totalDelegations,
|
||||
totalRewards,
|
||||
isLoading,
|
||||
@@ -322,15 +320,6 @@ export const Delegation: FC<{ isStorybook?: boolean }> = ({ isStorybook }) => {
|
||||
</Stack>
|
||||
</Paper>
|
||||
|
||||
{pendingDelegations && (
|
||||
<Paper elevation={0} sx={{ p: 3, mt: 2 }}>
|
||||
<Stack spacing={5}>
|
||||
<Typography variant="h6">Pending Delegation Events</Typography>
|
||||
<PendingEvents pendingEvents={pendingDelegations} explorerUrl={urls(network).networkExplorer} />
|
||||
</Stack>
|
||||
</Paper>
|
||||
)}
|
||||
|
||||
{showNewDelegationModal && (
|
||||
<DelegateModal
|
||||
open={showNewDelegationModal}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { Card, Divider, Grid, Typography } from '@mui/material';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { AppContext } from '../../context/main';
|
||||
|
||||
const SendReviewField = ({ title, subtitle, info }: { title: string; subtitle?: string; info?: boolean }) => (
|
||||
<>
|
||||
<Typography sx={{ color: info ? 'nym.fee' : '' }} data-testid={title}>
|
||||
{title}
|
||||
</Typography>
|
||||
<Typography sx={{ color: info ? 'nym.fee' : '', wordBreak: 'break-all' }} data-testid={subtitle}>
|
||||
{subtitle}
|
||||
</Typography>
|
||||
</>
|
||||
);
|
||||
|
||||
export const SendReview = ({ transferFee }: { transferFee?: string }) => {
|
||||
const { getValues } = useFormContext();
|
||||
const { clientDetails } = useContext(AppContext);
|
||||
|
||||
const values = getValues();
|
||||
|
||||
return (
|
||||
<Card
|
||||
variant="outlined"
|
||||
sx={{
|
||||
width: '100%',
|
||||
py: 3,
|
||||
px: 2,
|
||||
my: 3,
|
||||
mx: 0,
|
||||
}}
|
||||
>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<SendReviewField title="From" subtitle={clientDetails?.client_address} />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Divider light />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<SendReviewField title="To" subtitle={values.to} />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Divider light />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<SendReviewField title="Amount" subtitle={`${values.amount.amount} ${clientDetails?.denom}`} />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Divider light />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<SendReviewField title="Transfer fee" subtitle={`${transferFee} ${clientDetails?.denom}`} info />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -99,7 +99,7 @@ const TerminalInner: React.FC = () => {
|
||||
<Box width="100%" display="flex" justifyContent="space-between">
|
||||
<Box display="flex" alignItems="center">
|
||||
<TerminalIcon sx={{ mr: 1 }} />
|
||||
<Typography mr={4}>Terminal</Typography>
|
||||
<Typography mr={4} data-testid='terminal-header'>Terminal</Typography>
|
||||
{!isBusy && <RefreshIcon onClick={refresh} cursor="pointer" />}
|
||||
</Box>
|
||||
<CloseIcon onClick={handleShowTerminal} cursor="pointer" />
|
||||
|
||||
@@ -19,5 +19,5 @@
|
||||
"@assets/*": ["../assets/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "dist", "jest.config.js", "webpack.config.js", "webpack.prod.js", "webpack.common.js", "target"]
|
||||
"exclude": ["node_modules", "dist", "jest.config.js", "webpack.config.js", "webpack.prod.js", "webpack.common.js", "target", "wallet-ui-tests"]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
import Balance from '../tests/pageobjects/balanceScreen'
|
||||
import Auth from '../tests/pageobjects/authScreens'
|
||||
const userData = require("../common/user-data.json");
|
||||
const deleteScript = require("../scripts/deletesavedwallet")
|
||||
const savedWalletScript = require("../scripts/savedwalletexists")
|
||||
|
||||
|
||||
class Helpers {
|
||||
|
||||
// clear wallet data, login, and navigate to QA network
|
||||
freshMnemonicLoginQaNetwork = async () => {
|
||||
await deleteScript
|
||||
await savedWalletScript
|
||||
await Auth.loginWithMnemonic(userData.mnemonic)
|
||||
await Balance.selectQa()
|
||||
}
|
||||
|
||||
loginMnemonic = async () => {
|
||||
await Auth.loginWithMnemonic(userData.mnemonic)
|
||||
}
|
||||
|
||||
//helper to decode mnemonic so plain 24 character passphrase isn't in sight albeit it is presented when ruunning the scripts
|
||||
// TO-DO figure out what's going on with the decoding bit
|
||||
decodeBase = async (input) => {
|
||||
var m = Buffer.from(input, "base64").toString();
|
||||
return m;
|
||||
}
|
||||
|
||||
navigateAndClick = async (element) => {
|
||||
await element.waitForClickable({ timeout: 6000 })
|
||||
await element.click();
|
||||
}
|
||||
|
||||
elementVisible = async (element) => {
|
||||
await element.waitForDisplayed({ timeout: 6000 })
|
||||
}
|
||||
|
||||
elementClickable = async (element) => {
|
||||
await element.toBeClickable({ timeout: 8000 })
|
||||
}
|
||||
|
||||
addValueToTextField = async (element, value) => {
|
||||
await element.addValue(value)
|
||||
}
|
||||
|
||||
verifyStrictText = async (element, expectedText) => {
|
||||
let error = await element.getText()
|
||||
expect(error).toStrictEqual(expectedText)
|
||||
|
||||
}
|
||||
|
||||
verifyPartialText = async (element, expectedText) => {
|
||||
let error = await element.getText()
|
||||
expect(error).toContain(expectedText)
|
||||
}
|
||||
|
||||
currentBalance = async (value) => {
|
||||
return parseFloat(value.split(/\s+/)[0].toString()).toFixed(5)
|
||||
}
|
||||
|
||||
|
||||
calculateFees = async (beforeBalance, transactionFee, amount, isSend) => {
|
||||
let fee
|
||||
|
||||
if (isSend) {
|
||||
//send transaction
|
||||
fee = transactionFee.split(/\s+/)[0]
|
||||
} else {
|
||||
//delegate transaction
|
||||
fee = transactionFee.split(/\s+/)[3]
|
||||
}
|
||||
|
||||
const currentBalance = beforeBalance.split(/\s+/)[0]
|
||||
console.log("currenttttt 2 ............. = " + currentBalance)
|
||||
const castCurrentBalance = parseFloat(currentBalance).toFixed(5)
|
||||
console.log("castttt ............. " + castCurrentBalance)
|
||||
const transCost = +parseFloat(amount) + +parseFloat(fee).toFixed(5)
|
||||
console.log("trans ............." + transCost)
|
||||
|
||||
let sum = +castCurrentBalance - transCost
|
||||
return sum.toFixed(5)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = new Helpers();
|
||||
@@ -0,0 +1,42 @@
|
||||
module.exports = {
|
||||
|
||||
//welcome, sign in, create account
|
||||
homePageErrorMnemonic: "Error parsing bip39 mnemonic",
|
||||
signInWithoutMnemonic: "A mnemonic must be provided",
|
||||
signInRandomString: "mnemonic has a word count that is not a multiple of 6:",
|
||||
signInIncorrectMnemonic: "mnemonic contains an unknown word",
|
||||
incorrectMnemonicPasswordCreation: "The mnemonic provided is not valid. Please check the mnemonic",
|
||||
invalidPasswordOnSignIn: "failed to decrypt the given data with the provided password",
|
||||
signInWithoutPassword: "A password must be provided",
|
||||
failedToFindWalletFile: "The wallet file is not found",
|
||||
|
||||
//headers
|
||||
mnemonicSignIn: "Enter a mnemonic to sign in",
|
||||
passwordSignIn: "Enter a password to sign in",
|
||||
|
||||
//homePage
|
||||
qaNetwork: "QA",
|
||||
sandboxNetwork: "Testnet Sandbox",
|
||||
mainnetNetwork: "Nym Mainnet",
|
||||
noNym: "0 NYM",
|
||||
|
||||
//send
|
||||
invalidRecipientAddress: "123",
|
||||
recipientAddress: "n17tj0a0w6v7r2dc54rnkzfza6s8hxs87rj273a5",
|
||||
amountToSend: "1",
|
||||
negativeAmount: "-1",
|
||||
inferiorAmount: "0.0000001",
|
||||
confirmedAmount: "1 NYM",
|
||||
sendDetails: "Send details",
|
||||
|
||||
|
||||
// bond
|
||||
host: "1.1.1.1",
|
||||
version: "1.2.1",
|
||||
|
||||
// user incorrect data
|
||||
incorrectMnemonic: "giraffe note order sun cradle bottom crime humble able antique rural donkey guess parent potato tongue truly way disagree exile zebra someone else heat",
|
||||
randomString:"thisrandomstring",
|
||||
password:"iAmThePassword1!",
|
||||
incorrectPassword:"123notvalid",
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"mnemonic": "giraffe note order sun cradle bottom crime humble able antique rural donkey guess parent potato tongue truly way disagree exile zebra someone else typical",
|
||||
"qa_address": "n1qqct7gs79yrjncpkumljxeqjsnwvn42j2g3fw4",
|
||||
"receiver_address": "n167rupnmpput2alw62sz43eelks03zek4fwvjk0",
|
||||
"amount_to_send": "1",
|
||||
"identity_key_to_delegate_mix_node": "HqW2HStFHtAZ3PxRaiSCh7xJK6B7swoR1gSmJzH2iV9g",
|
||||
"identity_key_to_delegate_gateway": "",
|
||||
"delegate_amount": "10"
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "wallet-ui-tests",
|
||||
"version": "1.0.0",
|
||||
"description": "ui tests for the nym wallet",
|
||||
"scripts": {
|
||||
"test": "wdio run wdio.conf.ts",
|
||||
"test:signup": "wdio run wdio.conf.ts --suite signup",
|
||||
"test:login": "wdio run wdio.conf.ts --suite login",
|
||||
"test:balance": "wdio run wdio.conf.ts --suite balance",
|
||||
"test:nav": "wdio run wdio.conf.ts --suite nav",
|
||||
"test:send": "wdio run wdio.conf.ts --suite send",
|
||||
"test:delegation": "wdio run wdio.conf.ts --suite delegation"
|
||||
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"-": "^0.0.1",
|
||||
"@wdio/cli": "^7.16.16",
|
||||
"save-dev": "^0.0.1-security",
|
||||
"@zxing/browser": "^0.0.9",
|
||||
"ts-node": "^10.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@wdio/local-runner": "^7.16.16",
|
||||
"@wdio/mocha-framework": "^7.16.15",
|
||||
"@wdio/spec-reporter": "^7.16.14",
|
||||
"prettier": "2.5.1",
|
||||
"typescript": "^4.6.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
const { exec } = require("child_process")
|
||||
|
||||
const deleteSavedFile = exec("rm '/home/benedetta/.local/share/nym-wallet/saved-wallet.json'", (err, stdout, stderr) => {
|
||||
if (err) {
|
||||
console.error(`${err.message}`)
|
||||
return
|
||||
} else
|
||||
console.log("File deleted")
|
||||
})
|
||||
@@ -0,0 +1,14 @@
|
||||
const { exec } = require("child_process")
|
||||
|
||||
// const doesFileExist = exec("test -f /home/benedetta/.local/share/nym-wallet/saved-wallet.json" && "echo '$FILE exists.'" || "echo 'file doesn't exist'")
|
||||
// scriptExist ? expect(getErrorWarning).toStrictEqual(textConstants.invalidPasswordOnSignIn) : expect(getErrorWarning).toStrictEqual(textConstants.failedToFindWalletFile)
|
||||
|
||||
|
||||
const doesFileExist = exec("test -f /home/benedetta/.local/share/nym-wallet/saved-wallet.json", (err, stdout, stderr) => {
|
||||
if (err) {
|
||||
console.error(`${err.message}`)
|
||||
return
|
||||
} else
|
||||
console.log("File: " + stdout)
|
||||
})
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
class Nav {
|
||||
|
||||
get lightMode() { return $("[data-testid='LightModeOutlinedIcon']") }
|
||||
get darkMode() { return $("[data-testid='ModeNightOutlinedIcon']") }
|
||||
get terminalTitle() { return $("[data-testid='terminal-header']") }
|
||||
get terminalIcon() { return $("[data-testid='TerminalIcon']") }
|
||||
|
||||
|
||||
get balance() { return $("[data-testid='Balance']") }
|
||||
get send() { return $("[data-testid='Send']") }
|
||||
get receive() { return $("[data-testid='Receive']") }
|
||||
get bond() { return $("[data-testid='Bond']") }
|
||||
get unbond() { return $("[data-testid='Unbond']") }
|
||||
get delegation() { return $("[data-testid='Delegation']") }
|
||||
|
||||
|
||||
|
||||
get closeIcon() { return $("[data-testid='CloseIcon']") }
|
||||
|
||||
}
|
||||
export default new Nav()
|
||||
@@ -0,0 +1,74 @@
|
||||
import Balance from '../pageobjects/balanceScreen'
|
||||
|
||||
class Auth {
|
||||
//Welcome landing page
|
||||
get signInButton() { return $("[data-testid='signIn']") }
|
||||
get createAccount() { return $("[data-testid='createAccount']") }
|
||||
|
||||
// Existing account sign in option page
|
||||
get signInMnemonic() { return $("[data-testid='signInWithMnemonic']") }
|
||||
get signInPassword() { return $("[data-testid='signInWithPassword']") }
|
||||
get backToWelcomePage() { return $("[data-testid='backToWelcomePage']") }
|
||||
get forgotPassword() { return $("[data-testid='forgotPassword']") }
|
||||
|
||||
// Sign in with mnemonic page
|
||||
get mnemonicLoginScreenHeader() { return $("[data-testid='Enter a mnemonic to sign in']") }
|
||||
get mnemonicInput() { return $("[data-testid='mnemonicInput']") }
|
||||
get signIn() { return $("[data-testid='signInSubmitButton']") }
|
||||
get backToSignInOptions() { return $("[data-testid='backToSignInOptions']") }
|
||||
get createPassword() { return $("[data-testid='goToCreatePassword']") }
|
||||
|
||||
// Create password step 1/2
|
||||
get backToMnemonicSignIn() { return $("[data-testid='backToMnemonicSignIn']") }
|
||||
get nextToPasswordCreation() { return $("[data-testid='nextToPasswordCreation']") }
|
||||
|
||||
// Create password step 2/2
|
||||
get password() { return $("[data-testid='Password']") }
|
||||
get confirmPassword() { return $("[data-testid='Confirm password']") }
|
||||
get createPasswordButton() { return $("[data-testid='createPasswordButton']") }
|
||||
get backToStep1PasswordCreation() { return $("[data-testid='backToStep1PasswordCreation']") }
|
||||
|
||||
// Create account step 1/3
|
||||
get copyMnemonic() { return $("[data-testid='copyMnemonic']") }
|
||||
get iSavedMnemonic() { return $("[data-testid='iSavedMnemonic']") }
|
||||
get mnemonicPhrase() { return $("[data-testid='mnemonicPhrase']") }
|
||||
get backToWelcomePageFromCreate() { return $("[data-testid='backToWelcome']") }
|
||||
|
||||
// Create account step 2/3
|
||||
get wordIndex() { return $$("[data-testid='wordIndex']") }
|
||||
get mnemonicWordTile() { return $$("[data-testid='mnemonicWordTile']") }
|
||||
get nextToStep3() { return $("[data-testid='nextToStep3']") }
|
||||
get backToStep1() { return $("[data-testid='backToStep1']") }
|
||||
|
||||
// Create account step 3/3
|
||||
get nextStorePassword() { return $("[data-testid='nextStorePassword']") }
|
||||
get skipPasswordAndSignInWithMnemonic() { return $("[data-testid='skipPasswordAndSignInWithMnemonic']") }
|
||||
|
||||
// Enter password to sign in
|
||||
get passwordLoginScreenHeader() { return $("[data-testid='Enter a password to sign in']") }
|
||||
get enterPassword() { return $("[data-testid='Enter password']") }
|
||||
get signInPasswordButton() { return $("[data-testid='signInPasswordButton']") }
|
||||
get backToSignInOptionsFromPassword() { return $("[data-testid='backToSignInOptionsFromPassword']") }
|
||||
get forgotPasswordButton() { return $("[data-testid='forgotPasswordButton']") }
|
||||
|
||||
// Errors
|
||||
get error() { return $("[data-testid='error']") }
|
||||
//TO-DO get this bit below working
|
||||
getErrorMessage = async () => {
|
||||
await (await this.error).waitForDisplayed({ timeout: 1500 })
|
||||
await this.error.getText()
|
||||
}
|
||||
|
||||
//login to the application
|
||||
loginWithMnemonic = async (mnemonic) => {
|
||||
await this.signInButton.click()
|
||||
await this.signInMnemonic.click()
|
||||
await this.mnemonicInput.waitForDisplayed()
|
||||
await this.mnemonicInput.addValue(mnemonic);
|
||||
await this.signIn.click();
|
||||
await Balance.nymBalance.isExisting({ timeout: 4000 });
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
export default new Auth()
|
||||
@@ -0,0 +1,23 @@
|
||||
class Balance {
|
||||
|
||||
get balance() { return $("[data-testid='Balance']") }
|
||||
get checkBalance() { return $("[data-testid='check-balance']") }
|
||||
get nymBalance() { return $("[data-testid='nym-balance']") }
|
||||
|
||||
get copyAccountId() { return $("[data-testid='copyIcon']") }
|
||||
|
||||
get accountNumber() { return $("[data-testid='accountNumber']") }
|
||||
|
||||
get networkDropdown() { return $("[data-testid='ArrowDropDownIcon']") }
|
||||
get networkEnv() { return $("[data-testid='networkEnv']") }
|
||||
get networkSelectQa() { return $("[data-testid='QA']") }
|
||||
|
||||
selectQa = async () => {
|
||||
await this.networkDropdown.waitForDisplayed({ timeout: 4000 })
|
||||
await this.networkDropdown.click()
|
||||
await this.networkSelectQa.waitForClickable({ timeout: 4000 })
|
||||
await this.networkSelectQa.click()
|
||||
await this.networkEnv.waitForClickable({ timeout: 2000 })
|
||||
}
|
||||
}
|
||||
export default new Balance()
|
||||
@@ -0,0 +1,10 @@
|
||||
class Bond {
|
||||
|
||||
get bondTitle() { return $("[data-testid='Bond']") }
|
||||
get mixnodeRadio() { return $("[data-testid='mix-node']") }
|
||||
get gatewayRadio() { return $("[data-testid='gate-way']") }
|
||||
get fundsAlert() { return $("[data-testid='fundsAlert']") }
|
||||
|
||||
|
||||
}
|
||||
export default new Bond()
|
||||
@@ -0,0 +1,9 @@
|
||||
class Delegation {
|
||||
|
||||
get delegationTitle() { return $("[data-testid='Delegation']") }
|
||||
get delegateStakeButton() { return $("[data-testid='Delegate stake']") }
|
||||
get delegateModalHeader() { return $("[data-testid='Delegate']") }
|
||||
|
||||
}
|
||||
|
||||
export default new Delegation()
|
||||
@@ -0,0 +1,7 @@
|
||||
class Receive {
|
||||
|
||||
get receiveNymTitle() { return $("[data-testid='Receive NYM']") }
|
||||
|
||||
}
|
||||
|
||||
export default new Receive()
|
||||
@@ -0,0 +1,28 @@
|
||||
class Send {
|
||||
|
||||
// send nym form
|
||||
get sendHeader() { return $("[data-testid='Send']") }
|
||||
get recipientAddress() { return $("[data-testid='recipientAddress']") }
|
||||
// get sendAmount() { return $("[data-testid='Amount']") }
|
||||
get sendAmount() { return $("#mui-5") } // TO-DO fix this selector, using #mui-5 isn't a good solution
|
||||
get next() { return $("[data-testid='Next']") }
|
||||
|
||||
// confirm transaction modal
|
||||
get sendDetailsHeader() { return $("[data-testid='Send details']") }
|
||||
get from() { return $("/html/body/div[2]/div[3]/div[2]/div[1]/div[1]") }
|
||||
get to() { return $("/html/body/div[2]/div[3]/div[2]/div[2]") }
|
||||
get amount() { return $("/html/body/div[2]/div[3]/div[2]/div[3]") }
|
||||
get fee() { return $("/html/body/div[2]/div[3]/div[2]/div[4]") }
|
||||
|
||||
get confirm() { return $("[data-testid='Confirm']") }
|
||||
|
||||
|
||||
// transaction sent
|
||||
get viewOnBlockchain() { return $("[data-testid='viewOnBlockchain']") }
|
||||
get done() { return $("[data-testid='Done']") }
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
export default new Send()
|
||||
@@ -0,0 +1,7 @@
|
||||
class Unbond {
|
||||
|
||||
get unbondTitle() { return $("[data-testid='Unbond']") }
|
||||
|
||||
}
|
||||
|
||||
export default new Unbond()
|
||||
@@ -0,0 +1,32 @@
|
||||
import Balance from '../../pageobjects/balanceScreen'
|
||||
import Auth from '../../pageobjects/authScreens'
|
||||
const textConstants = require("../../../common/text-constants");
|
||||
const userData = require("../../../common/user-data.json");
|
||||
const Helper = require('../../../common/helper');
|
||||
|
||||
|
||||
describe('Balance screen displays correctly', () => {
|
||||
|
||||
it('selecting qa network', async () => {
|
||||
|
||||
//log in
|
||||
await Helper.loginMnemonic()
|
||||
// select QA network
|
||||
await Helper.navigateAndClick(Balance.networkDropdown)
|
||||
await Helper.navigateAndClick(Balance.networkSelectQa)
|
||||
// verifty QA network has been selected properly
|
||||
await Helper.verifyStrictText(Balance.networkEnv, textConstants.qaNetwork)
|
||||
|
||||
})
|
||||
|
||||
it('copy the account id', async () => {
|
||||
|
||||
// ensure the account number contains *something*
|
||||
await Helper.elementVisible(Balance.accountNumber)
|
||||
await Helper.verifyPartialText(Balance.accountNumber[1],'1')
|
||||
await Helper.navigateAndClick(Balance.copyAccountId)
|
||||
// TO-DO is there a way to verify that the copy worked, aka pasting it somewhere maybe?
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
@@ -0,0 +1,21 @@
|
||||
import Balance from '../../pageobjects/balanceScreen'
|
||||
import Auth from '../../pageobjects/authScreens'
|
||||
import Nav from '../../pageobjects/appNavConstants'
|
||||
import Delegation from '../../pageobjects/delegationScreen'
|
||||
import Send from '../../pageobjects/sendScreen'
|
||||
const Helper = require('../../../common/helper');
|
||||
const textConstants = require("../../../common/text-constants");
|
||||
const userData = require("../../../common/user-data.json");
|
||||
|
||||
describe('Delegate to a mixnode', () => {
|
||||
|
||||
it('entering an invalid node identity key', async () => {
|
||||
|
||||
//login and navigate to the screen
|
||||
await Helper.freshMnemonicLoginQaNetwork()
|
||||
await Helper.navigateAndClick(Nav.delegation)
|
||||
await Helper.elementVisible(Delegation.delegationTitle)
|
||||
// TO-DO enter an invalid node
|
||||
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,99 @@
|
||||
import Auth from '../../pageobjects/authScreens'
|
||||
import Balance from '../../pageobjects/balanceScreen'
|
||||
import ValidatorClient from '@nymproject/nym-validator-client';
|
||||
const deleteScript = require("../../../scripts/deletesavedwallet")
|
||||
const textConstants = require("../../../common/text-constants");
|
||||
const userData = require("../../../common/user-data.json");
|
||||
const Helper = require('../../../common/helper');
|
||||
|
||||
|
||||
describe('Create password for existing account and use it to sign in', () => {
|
||||
|
||||
it('enter incorrect mnemonic', async () => {
|
||||
|
||||
//click through sign in
|
||||
await Helper.navigateAndClick(Auth.signInButton)
|
||||
await Helper.navigateAndClick(Auth.signInMnemonic)
|
||||
//instead of entering mnemonic, click on create a password
|
||||
await Helper.navigateAndClick(Auth.createPassword)
|
||||
//enter incorrect mnemonic
|
||||
await Helper.addValueToTextField(Auth.mnemonicInput, textConstants.incorrectMnemonic)
|
||||
await Helper.navigateAndClick(Auth.nextToPasswordCreation)
|
||||
|
||||
// assert error message is correct
|
||||
await Helper.verifyStrictText(Auth.error, textConstants.incorrectMnemonicPasswordCreation)
|
||||
})
|
||||
|
||||
it('enter random string', async () => {
|
||||
|
||||
// enter random string as mnemonic
|
||||
await Helper.addValueToTextField(Auth.mnemonicInput, textConstants.randomString)
|
||||
await Helper.navigateAndClick(Auth.nextToPasswordCreation)
|
||||
// assert error is correct
|
||||
await Helper.verifyStrictText(Auth.error, textConstants.incorrectMnemonicPasswordCreation)
|
||||
|
||||
})
|
||||
|
||||
|
||||
it('enter correct mnemonic', async () => {
|
||||
|
||||
// generate random mnemonic in the backend
|
||||
const randomMnemonic = ValidatorClient.randomMnemonic();
|
||||
deleteScript
|
||||
// use it to continue with password creation flow
|
||||
await Helper.navigateAndClick(Auth.backToMnemonicSignIn)
|
||||
await Helper.navigateAndClick(Auth.createPassword)
|
||||
await Helper.addValueToTextField(Auth.mnemonicInput, randomMnemonic)
|
||||
await Helper.navigateAndClick(Auth.nextToPasswordCreation)
|
||||
await Helper.elementVisible(Auth.password)
|
||||
})
|
||||
|
||||
it('create an invalid password', async () => {
|
||||
|
||||
// type an invalid password in both fields
|
||||
await Helper.addValueToTextField(Auth.password, textConstants.incorrectPassword)
|
||||
await Helper.navigateAndClick(Auth.confirmPassword)
|
||||
await Helper.addValueToTextField(Auth.confirmPassword, textConstants.incorrectPassword)
|
||||
// ensure the button to proceed is still disabled
|
||||
const nextButton = await Auth.createPasswordButton
|
||||
const isNextDisabled = await nextButton.getAttribute('disabled')
|
||||
expect(isNextDisabled).toBe("true")
|
||||
|
||||
})
|
||||
|
||||
it('create a valid password', async () => {
|
||||
|
||||
// type a valid password in both fields
|
||||
await Helper.navigateAndClick(Auth.password)
|
||||
await Helper.addValueToTextField(Auth.password, textConstants.password)
|
||||
await Helper.navigateAndClick(Auth.confirmPassword)
|
||||
await Helper.addValueToTextField(Auth.confirmPassword, textConstants.password)
|
||||
// verify the password is created and the next screen is visible
|
||||
await Helper.navigateAndClick(Auth.createPasswordButton)
|
||||
await Helper.verifyStrictText(Auth.passwordLoginScreenHeader, textConstants.passwordSignIn)
|
||||
|
||||
})
|
||||
|
||||
it('sign in with no password throws error', async () => {
|
||||
|
||||
//click sign without entering a password
|
||||
await Helper.navigateAndClick(Auth.signInPasswordButton)
|
||||
// wait for error
|
||||
await Helper.elementVisible(Auth.error)
|
||||
// verify error has the correct message
|
||||
await Helper.verifyStrictText(Auth.error, textConstants.signInWithoutPassword)
|
||||
|
||||
})
|
||||
|
||||
it('sign in with invalid password throws error', async () => {
|
||||
|
||||
// enter invalid password
|
||||
await Helper.addValueToTextField(Auth.enterPassword, textConstants.incorrectPassword)
|
||||
await Helper.navigateAndClick(Auth.signInPasswordButton)
|
||||
// wait for error
|
||||
await Helper.elementVisible(Auth.error)
|
||||
await Helper.verifyStrictText(Auth.error, textConstants.invalidPasswordOnSignIn)
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
@@ -0,0 +1,67 @@
|
||||
import Auth from '../../pageobjects/authScreens'
|
||||
import Balance from '../../pageobjects/balanceScreen'
|
||||
import ValidatorClient from '@nymproject/nym-validator-client';
|
||||
import { text } from 'stream/consumers';
|
||||
const textConstants = require("../../../common/text-constants");
|
||||
const userData = require("../../../common/user-data.json");
|
||||
const Helper = require('../../../common/helper');
|
||||
|
||||
|
||||
|
||||
describe('Wallet sign in functionality with mnemonic', () => {
|
||||
|
||||
it('get to the sign in with mnemonic screen', async () => {
|
||||
|
||||
// click through to reach the mnemonic sign in
|
||||
await Helper.navigateAndClick(Auth.signInButton)
|
||||
await Helper.navigateAndClick(Auth.signInMnemonic)
|
||||
// verify you are on the right screen by confirming the header
|
||||
await Helper.verifyStrictText(Auth.mnemonicLoginScreenHeader, textConstants.mnemonicSignIn)
|
||||
|
||||
})
|
||||
|
||||
it('sign in with no mnemonic throws error', async () => {
|
||||
|
||||
await Helper.navigateAndClick(Auth.signIn)
|
||||
// wait for error
|
||||
await Helper.elementVisible(Auth.error)
|
||||
// verify error has the correct message
|
||||
await Helper.verifyStrictText(Auth.error, textConstants.signInWithoutMnemonic)
|
||||
|
||||
})
|
||||
|
||||
it('sign in with incorrect mnemonic throws error', async () => {
|
||||
|
||||
// enter an incorrect mnemonic string
|
||||
await Helper.addValueToTextField(Auth.mnemonicInput, textConstants.incorrectMnemonic)
|
||||
await Helper.navigateAndClick(Auth.signIn)
|
||||
// verifty error message is correct
|
||||
await Helper.verifyPartialText(Auth.error, textConstants.signInIncorrectMnemonic)
|
||||
|
||||
})
|
||||
|
||||
it('sign in with random string throws error', async () => {
|
||||
|
||||
// enter a random string not in mnemonic "format"
|
||||
await Helper.addValueToTextField(Auth.mnemonicInput, textConstants.randomString)
|
||||
await Helper.navigateAndClick(Auth.signIn)
|
||||
// verifty error message is correct
|
||||
await Helper.verifyPartialText(Auth.error, textConstants.signInRandomString)
|
||||
|
||||
})
|
||||
|
||||
it('should sign in with valid credentials', async () => {
|
||||
|
||||
// create new mnemonic
|
||||
const randomMnemonic = ValidatorClient.randomMnemonic();
|
||||
// enter mnemonic
|
||||
await Helper.addValueToTextField(Auth.mnemonicInput, randomMnemonic)
|
||||
await Helper.navigateAndClick(Auth.signIn)
|
||||
// verify successful login, balance is visible
|
||||
await Helper.elementVisible(Balance.balance)
|
||||
//new accounts will always default to mainnet, so 0 balance
|
||||
// TO-DO this value sometimes returns " " instead of "0"
|
||||
await Helper.verifyStrictText(Balance.nymBalance, textConstants.noNym)
|
||||
|
||||
})
|
||||
})
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
import Auth from '../../pageobjects/authScreens'
|
||||
import Balance from '../../pageobjects/balanceScreen'
|
||||
const textConstants = require("../../../common/text-constants");
|
||||
const userData = require("../../../common/user-data.json");
|
||||
const deleteWallet = require("../../../scripts/deletesavedwallet");
|
||||
const walletExists = require("../../../scripts/savedwalletexists")
|
||||
const Helper = require('../../../common/helper');
|
||||
|
||||
|
||||
describe('Wallet sign in functionality without creating password', () => {
|
||||
|
||||
it('sign in with invalid password and no saved wallet.json file throws error', async () => {
|
||||
|
||||
// delete existing saved wallet file
|
||||
deleteWallet
|
||||
//click through sign without entering a password
|
||||
await Helper.navigateAndClick(Auth.signInButton)
|
||||
await Helper.navigateAndClick(Auth.signInPassword)
|
||||
// enter invalid password
|
||||
await Helper.addValueToTextField(Auth.enterPassword,textConstants.incorrectPassword)
|
||||
await Helper.navigateAndClick(Auth.signInPasswordButton)
|
||||
// wait for error
|
||||
await Helper.elementVisible(Auth.error)
|
||||
// verify error has the correct message
|
||||
await Helper.verifyStrictText(Auth.error, textConstants.failedToFindWalletFile)
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
@@ -0,0 +1,73 @@
|
||||
import Auth from '../../pageobjects/authScreens'
|
||||
import Nav from '../../pageobjects/appNavConstants'
|
||||
import Balance from '../../pageobjects/balanceScreen'
|
||||
import Send from '../../pageobjects/sendScreen'
|
||||
import Receive from '../../pageobjects/receiveScreen'
|
||||
import Bond from '../../pageobjects/bondScreen'
|
||||
import Unbond from '../../pageobjects/unbondScreen'
|
||||
import Delegation from '../../pageobjects/delegationScreen'
|
||||
const userData = require("../../../common/user-data.json");
|
||||
const Helper = require('../../../common/helper');
|
||||
|
||||
|
||||
describe('Nav Items behave correctly', () => {
|
||||
|
||||
it('switch from light to dark mode and back', async () => {
|
||||
|
||||
//log in
|
||||
await Helper.freshMnemonicLoginQaNetwork()
|
||||
// click on different modes
|
||||
await Helper.navigateAndClick(Nav.lightMode)
|
||||
await Helper.navigateAndClick(Nav.darkMode)
|
||||
await Helper.elementVisible(Nav.lightMode)
|
||||
|
||||
})
|
||||
|
||||
it('clicking terminal opens the modal', async () => {
|
||||
|
||||
// ensure the terminal button opens the terminal
|
||||
await Helper.elementVisible(Nav.terminalIcon)
|
||||
await Helper.navigateAndClick(Nav.terminalIcon)
|
||||
await Helper.elementVisible(Nav.terminalTitle)
|
||||
await Helper.verifyPartialText(Nav.terminalTitle, 'Terminal')
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('Menu items lead to correct screen', () => {
|
||||
|
||||
//TO-DO none of this works
|
||||
//check each menu item opens the right screen/modal
|
||||
it('check Balance link works', async () => {
|
||||
await Helper.navigateAndClick(Nav.balance)
|
||||
await Helper.verifyPartialText(Balance.balance, 'Balance')
|
||||
})
|
||||
|
||||
it('check Send link works', async () => {
|
||||
await Helper.navigateAndClick(Nav.send)
|
||||
await Helper.verifyPartialText(Send.sendHeader, 'Send')
|
||||
await Helper.navigateAndClick(Nav.closeIcon)
|
||||
})
|
||||
|
||||
it('check Receive link works', async () => {
|
||||
await Helper.navigateAndClick(Nav.receive)
|
||||
await Helper.verifyPartialText(Receive.receiveNymTitle, 'Receive NYM')
|
||||
})
|
||||
|
||||
it('check Bond link works', async () => {
|
||||
await Helper.navigateAndClick(Nav.bond)
|
||||
await Helper.verifyPartialText(Bond.bondTitle, 'Bond')
|
||||
})
|
||||
|
||||
it('check Unbond link works', async () => {
|
||||
await Helper.navigateAndClick(Nav.unbond)
|
||||
await Helper.verifyPartialText(Unbond.unbondTitle, 'Unbond')
|
||||
})
|
||||
|
||||
it('check Delegation link works', async () => {
|
||||
await Helper.navigateAndClick(Nav.delegation)
|
||||
await Helper.verifyPartialText(Delegation.delegationTitle, 'Delegation')
|
||||
})
|
||||
|
||||
})
|
||||
@@ -0,0 +1,101 @@
|
||||
import Auth from '../../pageobjects/authScreens'
|
||||
import Balance from '../../pageobjects/balanceScreen'
|
||||
const textConstants = require("../../../common/text-constants");
|
||||
const userData = require("../../../common/user-data.json");
|
||||
const deleteScript = require("../../../scripts/deletesavedwallet")
|
||||
const Helper = require('../../../common/helper');
|
||||
|
||||
|
||||
describe('Create a new account and verify it exists', () => {
|
||||
|
||||
it('generate new mnemonic and verify mnemonic words', async () => {
|
||||
|
||||
// delete any existing saved-wallet.json
|
||||
deleteScript
|
||||
// click through create account flow
|
||||
await Helper.navigateAndClick(Auth.createAccount)
|
||||
await Helper.elementVisible(Auth.mnemonicPhrase)
|
||||
// save mnemonic phrase
|
||||
let mnemonic = await (await Auth.mnemonicPhrase).getText()
|
||||
let arrayMnemonic = mnemonic.split(" ")
|
||||
await Helper.navigateAndClick(Auth.copyMnemonic)
|
||||
await Helper.navigateAndClick(Auth.iSavedMnemonic)
|
||||
// verify the mnemonic words in the correct order
|
||||
let mnemonicWordTiles = await (await Auth.mnemonicWordTile)
|
||||
let wordTileIndex = await (await Auth.wordIndex)
|
||||
|
||||
const wordsArray: any[] = []
|
||||
|
||||
for (const word of mnemonicWordTiles) {
|
||||
const wordText = await word.getText()
|
||||
const index = arrayMnemonic.indexOf(wordText)
|
||||
wordsArray.push({ word, index })
|
||||
}
|
||||
|
||||
for (const index of wordTileIndex) {
|
||||
const indexValue = await index.getText()
|
||||
const match = wordsArray.find((word) => +word.index === +indexValue - 1)
|
||||
if (match) {
|
||||
await match.word.click()
|
||||
}
|
||||
}
|
||||
// ensure that once the task above is complete, the 'next' button is enabled
|
||||
const nextButton = await Auth.nextToStep3
|
||||
const isNextDisabled = await nextButton.getAttribute('disabled')
|
||||
expect(isNextDisabled).toBe(null)
|
||||
|
||||
})
|
||||
|
||||
it('click skip password', async () => {
|
||||
|
||||
// click on skip password creation
|
||||
await Helper.navigateAndClick(Auth.nextToStep3)
|
||||
await Helper.navigateAndClick(Auth.skipPasswordAndSignInWithMnemonic)
|
||||
// can see mnemonic login page
|
||||
await Helper.elementVisible(Auth.mnemonicInput)
|
||||
await Helper.navigateAndClick(Auth.backToSignInOptions)
|
||||
|
||||
})
|
||||
|
||||
it('set up invalid password for new account', async () => {
|
||||
|
||||
// enter invalid password in both fields
|
||||
await Helper.navigateAndClick(Auth.password)
|
||||
await Helper.addValueToTextField(Auth.password, textConstants.incorrectPassword)
|
||||
await Helper.navigateAndClick(Auth.confirmPassword)
|
||||
await Helper.addValueToTextField(Auth.confirmPassword, textConstants.incorrectPassword)
|
||||
// verify that the 'next' button is still disabled
|
||||
const nextButton = await Auth.nextStorePassword
|
||||
const isNextDisabled = await nextButton.getAttribute('disabled')
|
||||
expect(isNextDisabled).toBe("true")
|
||||
|
||||
})
|
||||
|
||||
it('set up valid password for new account', async () => {
|
||||
|
||||
// enter a valid password in both fields
|
||||
await Helper.navigateAndClick(Auth.password)
|
||||
await Helper.addValueToTextField(Auth.password, textConstants.password)
|
||||
await Helper.navigateAndClick(Auth.confirmPassword)
|
||||
await Helper.addValueToTextField(Auth.confirmPassword, textConstants.password)
|
||||
// verify that the 'next' button is clickable
|
||||
const nextButton = await Auth.nextStorePassword
|
||||
const isNextDisabled = await nextButton.getAttribute('disabled')
|
||||
expect(isNextDisabled).toBe(null)
|
||||
|
||||
})
|
||||
|
||||
it('proceed to login with newly created password', async () => {
|
||||
|
||||
// login with a password
|
||||
await Helper.navigateAndClick(Auth.nextStorePassword)
|
||||
await Helper.navigateAndClick(Auth.enterPassword)
|
||||
await Helper.addValueToTextField(Auth.enterPassword, textConstants.password)
|
||||
await Helper.navigateAndClick(Auth.signInPasswordButton)
|
||||
// TO-DO for some reason this is failing due to failed to decrypt the wallet etc error
|
||||
await Helper.elementVisible(Balance.balance)
|
||||
//new accounts will always default to mainnet, so 0 balance
|
||||
await Helper.verifyStrictText(Balance.nymBalance, textConstants.noNym)
|
||||
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,62 @@
|
||||
import Balance from '../../pageobjects/balanceScreen'
|
||||
import Auth from '../../pageobjects/authScreens'
|
||||
import Nav from '../../pageobjects/appNavConstants'
|
||||
import Send from '../../pageobjects/sendScreen'
|
||||
const Helper = require('../../../common/helper');
|
||||
const textConstants = require("../../../common/text-constants");
|
||||
const userData = require("../../../common/user-data.json");
|
||||
|
||||
describe.skip('Send modal functions correctly', () => {
|
||||
|
||||
it('entering an invalid recipient address shows error', async () => {
|
||||
|
||||
// sign in with mnemonic and select QA
|
||||
await Helper.freshMnemonicLoginQaNetwork()
|
||||
// click on send and check modal appears
|
||||
await Helper.navigateAndClick(Nav.send)
|
||||
await Helper.elementVisible(Send.sendHeader)
|
||||
// add an invalid recipient address
|
||||
await Helper.addValueToTextField(Send.recipientAddress, textConstants.invalidRecipientAddress)
|
||||
// TO-DO -- question: should there not be an error message before clicking on Next to warn that the address is invalid?
|
||||
})
|
||||
|
||||
it('entering an valid recipient address with negative amount value shows error', async () => {
|
||||
|
||||
await Helper.navigateAndClick(Send.recipientAddress)
|
||||
// TO-DO figure out how to clear a text field before adding new value
|
||||
await (Send.recipientAddress).clearValue()
|
||||
await Helper.addValueToTextField(Send.recipientAddress, userData.receiver_address)
|
||||
await Helper.navigateAndClick(Send.sendAmount)
|
||||
await Helper.addValueToTextField(Send.sendAmount, textConstants.negativeAmount)
|
||||
//next button is still disabled and error message appears
|
||||
const nextButton = await Send.next
|
||||
const isNextDisabled = await nextButton.getAttribute('disabled')
|
||||
expect(isNextDisabled).toBe("true")
|
||||
|
||||
})
|
||||
|
||||
it('enter a valid recipient and value', async () => {
|
||||
|
||||
// enter valid data
|
||||
await Helper.addValueToTextField(Send.recipientAddress, userData.receiver_address)
|
||||
const getCurrentBalance = await (await Balance.nymBalance).getText()
|
||||
await Helper.addValueToTextField(Send.sendAmount, textConstants.amountToSend)
|
||||
// click on next and verify details
|
||||
await Helper.navigateAndClick(Send.next)
|
||||
const fee = await (await Send.fee).getText()
|
||||
await Helper.verifyPartialText(Send.sendDetailsHeader, textConstants.sendDetails)
|
||||
await Helper.verifyPartialText(Send.amount, textConstants.confirmedAmount)
|
||||
|
||||
await Helper.navigateAndClick(Send.confirm)
|
||||
await Helper.elementVisible(Send.viewOnBlockchain)
|
||||
await Helper.elementClickable(Send.done)
|
||||
|
||||
// calculate the transaction and verify it has been correctly executed
|
||||
let sumCost = await Helper.calculateFees(getCurrentBalance, fee, textConstants.amountToSend, true)
|
||||
const getNewBalance = await Balance.nymBalance.getText()
|
||||
|
||||
await Helper.navigateAndClick(Send.done)
|
||||
// TO-DO the following fails with "TypeError: elem[prop] is not a function"
|
||||
expect(getNewBalance).toEqual(sumCost)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,30 @@
|
||||
import ValidatorClient from '@nymproject/nym-validator-client';
|
||||
|
||||
describe.skip('Creating valid account', () => {
|
||||
it('create mnemonic', async () => {
|
||||
const benny = "giraffe note order sun cradle bottom crime humble able antique rural donkey guess parent potato tongue truly way disagree exile zebra someone else typical";
|
||||
const mnemonic = ValidatorClient.randomMnemonic();
|
||||
console.log(ValidatorClient);
|
||||
const newAccountClient = await ValidatorClient.connect(mnemonic,
|
||||
'https://qa-validator.nymtech.net', 'https://qa-validator-api.nymtech.net/api', 'n', 'n1suhgf5svhu4usrurvxzlgn54ksxmn8gljarjtxqnapv8kjnp4nrsd3qaep', 'n1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3sjkxkav', 'nym');
|
||||
const address = newAccountClient.address;
|
||||
console.log({ address, mnemonic });
|
||||
|
||||
const client = await ValidatorClient.connect(
|
||||
benny, 'https://qa-validator.nymtech.net', 'https://qa-validator-api.nymtech.net/api', 'n', 'n1suhgf5svhu4usrurvxzlgn54ksxmn8gljarjtxqnapv8kjnp4nrsd3qaep', 'n1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3sjkxkav', 'nym');
|
||||
|
||||
await client.send(address, [{ amount: '10000000', denom: 'unym' }]);
|
||||
const balance = await client.getBalance(address);
|
||||
console.log({ balance });
|
||||
expect(Number.parseFloat(balance.amount)).toBe(10000000);
|
||||
}).timeout(5000);
|
||||
})
|
||||
|
||||
|
||||
// the newly created address from the test above:
|
||||
|
||||
// address: 'n13l7rwrygs0m3kx3en2eh55dtmwlzm0vskw0hxq',
|
||||
// mnemonic: 'tree upset require kitten inquiry truck emotion ladder reject elbow page ability spot win board frog child much credit pizza picture hover medal zoo'
|
||||
|
||||
// always make sure it's on QA, unless youre on debug branch (~look in nym_path wdio.config.ts to check)
|
||||
// ENABLE_QA_MODE=true target/release/nym-wallet
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"types": [
|
||||
"node",
|
||||
"webdriverio/async",
|
||||
"@wdio/mocha-framework",
|
||||
"expect-webdriverio",
|
||||
"./wdio.conf.ts"
|
||||
],
|
||||
"target": "ES5"
|
||||
},
|
||||
"include": [
|
||||
"wallet-ui-tests/*"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
const os = require('os')
|
||||
const path = require('path')
|
||||
const { spawn, spawnSync } = require('child_process')
|
||||
//insert path to binary
|
||||
const nym_path = '../target/debug/nym_wallet'
|
||||
|
||||
let tauriDriver: any
|
||||
|
||||
exports.config = {
|
||||
autoCompileOpts: {
|
||||
autoCompile: true,
|
||||
tsNodeOpts: {
|
||||
transpileOnly: true,
|
||||
project: 'tsconfig.json',
|
||||
},
|
||||
},
|
||||
specs: ['./tests/specs/**/*.ts'],
|
||||
|
||||
suites: {
|
||||
signup: [
|
||||
'./tests/specs/newaccount/*.ts',
|
||||
],
|
||||
login: [
|
||||
'./tests/specs/existingaccount/*.ts',
|
||||
],
|
||||
balance: [
|
||||
'./tests/specs/balance/*.ts',
|
||||
],
|
||||
nav: [
|
||||
'./tests/specs/navbaritems/*.ts',
|
||||
],
|
||||
send: [
|
||||
'./tests/specs/send/*.ts',
|
||||
],
|
||||
delegation: [
|
||||
'./tests/specs/delegation/*.ts',
|
||||
],
|
||||
},
|
||||
// Patterns to exclude.
|
||||
exclude: [
|
||||
// 'path/to/excluded/files'
|
||||
],
|
||||
maxInstances: 1,
|
||||
capabilities: [
|
||||
{
|
||||
maxInstances: 1,
|
||||
'tauri:options': {
|
||||
application: nym_path,
|
||||
},
|
||||
},
|
||||
],
|
||||
//
|
||||
// ===================
|
||||
// Test Configurations
|
||||
// ===================
|
||||
// Define all options that are relevant for the WebdriverIO instance here
|
||||
//
|
||||
// Level of logging verbosity: trace | debug | info | warn | error | silent
|
||||
logLevel: 'info',
|
||||
bail: 0,
|
||||
framework: 'mocha',
|
||||
reporters: ['spec'],
|
||||
mochaOpts: {
|
||||
ui: 'bdd',
|
||||
timeout: 60000,
|
||||
},
|
||||
// ===================
|
||||
// Test Reporters
|
||||
// ===================
|
||||
// reporters: [
|
||||
// [
|
||||
// "allure",
|
||||
// {
|
||||
// outputDir: "allure-results",
|
||||
// disableWebdriverStepsReporting: true,
|
||||
// disableWebdriverScreenshotsReporting: true,
|
||||
// },
|
||||
// ],
|
||||
// ],
|
||||
|
||||
// this is documentented in the readme - you will need to build the project first
|
||||
// ensure the rust project is built since we expect this binary to exist for the webdriver sessions
|
||||
//onPrepare: () => spawnSync("cargo", ["build", "--release"]),
|
||||
|
||||
// ensure we are running `tauri-driver` before the session starts so that we can proxy the webdriver requests
|
||||
beforeSession: () =>
|
||||
(tauriDriver = spawn(path.resolve(os.homedir(), '.cargo', 'bin', 'tauri-driver'), [], {
|
||||
stdio: [null, process.stdout, process.stderr],
|
||||
})),
|
||||
|
||||
// afterTest: function (
|
||||
// test,
|
||||
// context,
|
||||
// { error, result, duration, passed, retries }
|
||||
// ) {
|
||||
// if (error) {
|
||||
// browser.takeScreenshot();
|
||||
// }
|
||||
// },
|
||||
|
||||
// clean up the `tauri-driver` process we spawned at the start of the session
|
||||
afterSession: () => tauriDriver.kill(),
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
reports
|
||||
allure-results
|
||||
node_modules
|
||||
.vscode
|
||||
.idea
|
||||
@@ -1,86 +0,0 @@
|
||||
<!--
|
||||
Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
# Nym Wallet Webdriverio testsuite
|
||||
|
||||
A webdriverio test suite implementation using tauri driver
|
||||
with a page object model design. This is to provide quick iterative feedback
|
||||
on the UI of the nym wallet. Currently, tauri-driver is available to run on Windows and Linux machines.
|
||||
|
||||
## Installation prerequisites
|
||||
|
||||
- `Yarn`
|
||||
- `NodeJS >= v16.8.0`
|
||||
- `Rust & cargo >= v1.56.1`
|
||||
- `tauri-driver`
|
||||
- `That you have an existing mnemonic and you can login to the app`
|
||||
- `Have the details listed below to provide the user-data.json file`
|
||||
|
||||
## Key Information
|
||||
|
||||
- Please read the instructions on the `nym/tauri-wallet/README.md` in the root of the project on how to build the application
|
||||
- Please ensure you have the relevant Webdriver kits installed on your machine -
|
||||
|
||||
```
|
||||
linux:
|
||||
sudo apt-get install -y webkit2gtk-driver
|
||||
```
|
||||
|
||||
```
|
||||
windows:
|
||||
download msedgedriver.exe from https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
|
||||
```
|
||||
|
||||
please visit [Tauri Studio](https://tauri.studio/en/docs/usage/guides/webdriver/introduction), this will specify the additional drivers you need
|
||||
|
||||
- The path to run the application is set in the `wdio.conf.js` which lives in the root directory
|
||||
- Before running the suite you need to build the application and check that the application has
|
||||
built successfully, if so, you will have an executable sitting in the target directory in `tauri-wallet/target/*/nym_wallet` (refer to point 1)
|
||||
- The suite will not be able to detect elements on screen if you select a release build, however you can run tests against a release target
|
||||
|
||||
## Installation & usage
|
||||
|
||||
- `test excution happens inside /webdriver directory`
|
||||
- `test data needs to be provided inside the user-data.json`
|
||||
- `check the wdio.conf.cjs to see the test execution along with the path location of the binary`
|
||||
|
||||
```
|
||||
example:
|
||||
//mnemonic is a base64 enconded value, which is your 24 character passphrase, these values are for illustration purposes
|
||||
{
|
||||
"mnemonic" : "dGhpcyBpcyBhIHBhc3NwaHJhc2UK",
|
||||
"punk_address" : "punk1f3dzkhmunma5ze5q952daxca6371989189",
|
||||
"receiver_address" : "punk1p0ce82jxxglpmutvhq4mdwgcwf4avm5n1821982",
|
||||
"amount_to_send" : "1",
|
||||
"identity_key_to_delegate_mix_node": "value",
|
||||
"identity_key_to_delegate_gateway" : "value",
|
||||
"delegate_amount" : "1"
|
||||
}
|
||||
```
|
||||
|
||||
- `yarn test:runall` - the first test run will take some time to spin up be patient
|
||||
- You can run tests individually by passing through the script situated in the package.json for example `yarn test:newuser`
|
||||
|
||||
Tests are categorised and run by their pages, they follow a sequential flow, if one test case fails before the next execution it may derail the next test.
|
||||
|
||||
//todo improve in near future
|
||||
|
||||
## Test reporting
|
||||
|
||||
Currently the tests use allure reporting, the configuration can be altered in the `wdio.conf.cjs`. At present it takes snapshots of any failing tests, the test output run can be seen in the allure-results directory
|
||||
Tests ouput:
|
||||
|
||||
- <guid-testuite.xml>
|
||||
- <guid-attachment.png>
|
||||
|
||||
If any tests fail in their test run it will produce the stack trace error along with the test in question
|
||||
|
||||
## TODO
|
||||
|
||||
_Disclaimer_: Still WIP
|
||||
|
||||
Implement error handling/ beforeTest() - validating json file exists with data for test execution
|
||||
|
||||
Currently this is dev'd against a Linux based OS, not tested against windows yet.
|
||||
@@ -1,12 +0,0 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
targets: {
|
||||
node: "14",
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
module.exports = {
|
||||
//receivePage
|
||||
recievePageInformation:
|
||||
"You can receive tokens by providing this address to the sender",
|
||||
receivePageHeaderText: "Receive Nym",
|
||||
|
||||
//sendPage
|
||||
sendPunk: "Send punk",
|
||||
|
||||
//homePage
|
||||
homePageErrorMnemonic: "Error parsing bip39 mnemonic",
|
||||
homePageSignIn: "Sign in",
|
||||
createOne: "Create one",
|
||||
walletSuccess:
|
||||
"Please store your mnemonic in a safe place. You'll need it to access your wallet",
|
||||
|
||||
//bondPage // unbondPage
|
||||
bondAlreadyNoded: "Looks like you already have a mixnode bonded.",
|
||||
bondNodeHeaderText: "Bond a node or gateway",
|
||||
unbondNodeHeaderText: "Unbond a mixnode or gateway",
|
||||
unbondMixNodeText: "Looks like you already have a mixnode bonded.",
|
||||
unbondMixNode: "UNBOND",
|
||||
|
||||
//delegatePage // undelegatePage
|
||||
delegateHeaderText: "Delegate\nDelegate to mixnode",
|
||||
nodeIdentityValidationText: "identity is a required field",
|
||||
amountValidationText: "amount is a required field",
|
||||
undelegateHeaderText: "Undelegate from a mixnode or gateway",
|
||||
delegationComplete: "Delegation complete",
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"mnemonic": "value",
|
||||
"punk_address": "",
|
||||
"receiver_address": "",
|
||||
"amount_to_send": "",
|
||||
"identity_key_to_delegate_mix_node": "",
|
||||
"identity_key_to_delegate_gateway": "",
|
||||
"delegate_amount": ""
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user