Compare commits
509 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f25f76c1df | |||
| 096a599673 | |||
| 41da67ad6f | |||
| 273a741cdf | |||
| b5c8b69547 | |||
| 5bd87bdaa8 | |||
| 7d64618701 | |||
| 4151c65251 | |||
| ccb48f92cd | |||
| 8fce478a1f | |||
| 4f712ad4ba | |||
| 562fd44a30 | |||
| 603e897e2d | |||
| 6c122aad10 | |||
| b4ac601a82 | |||
| ce380a6b0d | |||
| 5b02801c04 | |||
| 29f95febe9 | |||
| 525372d7ac | |||
| e473a05250 | |||
| a55d604bf5 | |||
| 5075894ff5 | |||
| c392266a4c | |||
| 9b540936db | |||
| 7bf1036b68 | |||
| 1d82ec56d8 | |||
| 3ae5b59141 | |||
| 929b401f95 | |||
| d158deba77 | |||
| 5c77b48708 | |||
| 73d53653db | |||
| 74bedead20 | |||
| 1bec95d2a1 | |||
| 30137e285d | |||
| 5253d5ec51 | |||
| 7ed7329917 | |||
| 4abc0ae0ba | |||
| 47d8fcb21a | |||
| acef5a5652 | |||
| cb919a3af9 | |||
| 8e021a4419 | |||
| e5db7cb915 | |||
| 9bd03af3e9 | |||
| e8a026ef0b | |||
| 86755aa6ba | |||
| 77e0c6425e | |||
| 0373e2b02a | |||
| e8dd347186 | |||
| 5681920092 | |||
| edbf35cb34 | |||
| c46d04d3c4 | |||
| 4ebd1dd7f5 | |||
| 62ab760656 | |||
| 32de7efc32 | |||
| deae210b82 | |||
| 5b2b45a6eb | |||
| bc0f0cfc55 | |||
| 2661e4539e | |||
| 2fe5a5249c | |||
| c5b678d4e9 | |||
| 487f07ef35 | |||
| 6a63be63e9 | |||
| 552c99389e | |||
| 55502d210c | |||
| 66967ca88e | |||
| ba6d02b1db | |||
| ebc957c04d | |||
| 81c3ad74ca | |||
| 88f57e6d87 | |||
| 28a965e698 | |||
| 029c445805 | |||
| 358c95d541 | |||
| 0f7793a881 | |||
| 5478c23563 | |||
| 9f39e93e7b | |||
| 896a3e1be6 | |||
| 800390db85 | |||
| 1eaa13155c | |||
| fad3346096 | |||
| 150f832f8e | |||
| 202336b8a1 | |||
| f0e94f8e5e | |||
| 6cd00b8d10 | |||
| 534187cc8f | |||
| 25b4934f69 | |||
| 5ef7e24893 | |||
| 87ef46bc05 | |||
| f7bc5be8e4 | |||
| b309583886 | |||
| 245185710a | |||
| b7cfe31d72 | |||
| 68ca41a6be | |||
| 5621e7d22e | |||
| a1a5c7772d | |||
| b47deafc14 | |||
| cc6a6d8db2 | |||
| 5b28e24c17 | |||
| f8d68d8ef0 | |||
| a9d86508b5 | |||
| bb7fa587de | |||
| 6585732dfc | |||
| 2065e0fc17 | |||
| 3f7bdad59c | |||
| 6209e78c1e | |||
| 8e5062af96 | |||
| 496e642d7f | |||
| 07e18ec198 | |||
| d5953c28c1 | |||
| 3aa4b66588 | |||
| 005f0ce340 | |||
| 8d1d025fa2 | |||
| 1d53a2f954 | |||
| 966d123608 | |||
| 963d55273f | |||
| 6872d7bf77 | |||
| 6fe93bcda0 | |||
| 78d568e04e | |||
| 8880bdd857 | |||
| cc83ecf7e4 | |||
| 796f5a678a | |||
| 00b60f5493 | |||
| 0dfd1cca44 | |||
| eacefd3697 | |||
| 424c25768c | |||
| e460c1700e | |||
| 9935c99d41 | |||
| 2c4aee63bf | |||
| 0ebc395df9 | |||
| 1de3317e75 | |||
| 91c20af893 | |||
| 1365e2f246 | |||
| cfa1ce46f2 | |||
| 3f4f76859b | |||
| 3f7f4b82de | |||
| 934ba2b027 | |||
| 221e1870e5 | |||
| 9b36bccf0c | |||
| 80d7285497 | |||
| b94f2a483d | |||
| f64cfb4cd1 | |||
| eda223ed3d | |||
| c98d4305fa | |||
| 2eecbca6eb | |||
| a58c80ef08 | |||
| ac9d0db8be | |||
| 7521d98963 | |||
| 1e98131090 | |||
| 46bf65462c | |||
| e3df4c2d68 | |||
| 45c013350f | |||
| 30e2f27c64 | |||
| 6fecc53975 | |||
| e4dbfb1904 | |||
| 3113c1e9a7 | |||
| f822d3db7b | |||
| 9d23766288 | |||
| fd4930b198 | |||
| 5d7be89edb | |||
| 47f5b4ceac | |||
| 790220039b | |||
| 16fdfa4583 | |||
| 1d8a931e0c | |||
| 48d0883b31 | |||
| e271370326 | |||
| cbbeb66b5b | |||
| 3f0d4846df | |||
| de020f46a6 | |||
| 9bfcdbe8e2 | |||
| 8c4885ce2c | |||
| f24bb5c038 | |||
| 79dfe7eeda | |||
| 0108c6ed19 | |||
| 926389df89 | |||
| b55db00408 | |||
| cfcb64f7e5 | |||
| 0e8f60d501 | |||
| 9c6c5f5170 | |||
| f28888e3e7 | |||
| 6e30e6178b | |||
| 9549bed8bb | |||
| 7c65d61d91 | |||
| ad2efb7e62 | |||
| a50c9bfa1a | |||
| 30cdbf535a | |||
| f5365cbca9 | |||
| 22e7cb887b | |||
| b571f1a881 | |||
| b1c4e3ded7 | |||
| 4694ded8bd | |||
| 7971573026 | |||
| c4780c8af2 | |||
| 246f0b3f52 | |||
| 7879d76592 | |||
| 0f62ea25d8 | |||
| 6dbe8205d6 | |||
| 1b94ad5c4c | |||
| 37be99ab8f | |||
| 6f5cee8c36 | |||
| 58d805ab72 | |||
| 68ad75f737 | |||
| 73ea2b5fec | |||
| a0b37daeb0 | |||
| c9972047f6 | |||
| ccdf698380 | |||
| c10ed5a2f3 | |||
| 600b6d2b03 | |||
| b1391bbb17 | |||
| a171103a80 | |||
| 3e2009aa9d | |||
| 4b6e942667 | |||
| a6723044b9 | |||
| f60a25ee2d | |||
| 770baefe35 | |||
| 1c3403d7e6 | |||
| 342fd869a2 | |||
| 6f7db4172f | |||
| 55fd7b8890 | |||
| a14b4dc80c | |||
| c81f6962d7 | |||
| 9f4ef6842b | |||
| 7ca0c06c87 | |||
| 57aa763a84 | |||
| ba5fecf6b3 | |||
| 35343509f9 | |||
| 42d8b06346 | |||
| f30f0e8316 | |||
| e1aaf509d1 | |||
| 8db5eadea6 | |||
| 4dda824d37 | |||
| 0579b3afb0 | |||
| d328c458e6 | |||
| c8651cddbb | |||
| cde2a1ab26 | |||
| 8d78c92c03 | |||
| af311c3d33 | |||
| 906bcf1634 | |||
| 843bd4f4fa | |||
| 9bbe4a96d0 | |||
| 974ac0691c | |||
| 1188e48313 | |||
| e7ed5f3de3 | |||
| d45b2de241 | |||
| 3d9cbf351f | |||
| 844e22d94d | |||
| 09c905910e | |||
| 8fd8bf8792 | |||
| 243658637c | |||
| 5603a79d49 | |||
| 0007a4cc74 | |||
| 3dafe02f0e | |||
| e62e9cde02 | |||
| cde53c02e7 | |||
| de64da8e20 | |||
| 683790b068 | |||
| f9c24c8a23 | |||
| 886bb95e18 | |||
| 214fd0caf5 | |||
| 4aeac1acd2 | |||
| 679be24074 | |||
| 36e07f546d | |||
| d264feaf22 | |||
| 32b7b7afdc | |||
| 7a50f0c3b2 | |||
| 091382ef30 | |||
| 2da6a2fbfa | |||
| d910a4e0ee | |||
| 672ab79421 | |||
| 1ad97adc7c | |||
| 2bd585a0ff | |||
| df0b0367a4 | |||
| bb9e26d745 | |||
| dc5c765ecb | |||
| 95e2e3d0d2 | |||
| 690c4164a7 | |||
| ee656aa3ef | |||
| 3d4123aca5 | |||
| 29a8e23f72 | |||
| a4c5407b04 | |||
| 75bc36a9e6 | |||
| b8e2fb46fb | |||
| eff931f9ca | |||
| e4d8d721c0 | |||
| 21335b5ff1 | |||
| dadfdacf14 | |||
| e3eeef4301 | |||
| 6a519f4a1a | |||
| fde8bd89b6 | |||
| 099013bc6d | |||
| 11eef024ea | |||
| cc6017db3b | |||
| 84c1679973 | |||
| b1d18a5974 | |||
| 5019b4b266 | |||
| 790e7a0e1e | |||
| 0b1b6947e8 | |||
| c79b2cfb78 | |||
| dd699bce9a | |||
| 5ce017ef3d | |||
| 59c1ce2639 | |||
| 4fb63d8892 | |||
| a3b4d04d02 | |||
| aa3af8faea | |||
| 20c7f0e96f | |||
| e21142f1bd | |||
| ba3a6eaeb5 | |||
| 9d0bc8ab9e | |||
| 0d65ca78c4 | |||
| 0505a4807d | |||
| 01aa06e488 | |||
| 3b8dd1f4a5 | |||
| 4a837ce28c | |||
| 696f6c399c | |||
| ac9290de27 | |||
| b026e9107f | |||
| 1347535e8f | |||
| 479327849a | |||
| 21611a9434 | |||
| 78d9030567 | |||
| 4feb168cf7 | |||
| f3c16476f9 | |||
| 4678059eaf | |||
| a69d4bb457 | |||
| 50e3f2be38 | |||
| 276edfd562 | |||
| 605f8fcde3 | |||
| 645c9b5e67 | |||
| f0e4d1a7cf | |||
| 055ec4bdd5 | |||
| 5761f9ac7f | |||
| 32620fd55f | |||
| abb5cdbe06 | |||
| 8cad2b0076 | |||
| bcd6c19a97 | |||
| 764a3a6228 | |||
| d17aa72829 | |||
| d62658f515 | |||
| e6d4095bf9 | |||
| 9ace9d6960 | |||
| 6c32ff9708 | |||
| 5eae62ae33 | |||
| 331483f86a | |||
| 4ee0aeb2b1 | |||
| 08354f7651 | |||
| f1f599dd09 | |||
| 51251668e3 | |||
| 6e72433f99 | |||
| e6957e7a99 | |||
| de2406a2c7 | |||
| 956a264106 | |||
| 9b62d18101 | |||
| 390730f304 | |||
| e134ef8e15 | |||
| 7bd1550195 | |||
| 134ab2f0d6 | |||
| 1a4e7433b2 | |||
| f211b1e366 | |||
| b2db208e6e | |||
| c9c0de1fba | |||
| 9d91a018b2 | |||
| 0f7e3fe53e | |||
| ae9c1b4070 | |||
| e0d98af04f | |||
| 81e31c0550 | |||
| 1c771df941 | |||
| adcd8703d3 | |||
| aee4c2d80d | |||
| 5e04f48500 | |||
| a7610a7a88 | |||
| 28e6e9140c | |||
| 17c2aecd99 | |||
| 85074f3ac8 | |||
| c7020da81c | |||
| 271a126556 | |||
| 7da444c7a4 | |||
| 2a7fd71416 | |||
| 6ffd211e51 | |||
| f61ed48240 | |||
| 8d3dc405a5 | |||
| 21bf0fb27b | |||
| 7313f56c01 | |||
| cfef9e96e6 | |||
| 8b9a5cf500 | |||
| ce94ce058f | |||
| 018e4d6079 | |||
| ebadd9799f | |||
| 268fa02b83 | |||
| cb525477e5 | |||
| 4d6d2f0d33 | |||
| c7f8b05604 | |||
| 2878e9be9d | |||
| 7b419c2b12 | |||
| 0049126a91 | |||
| 80c5194d8b | |||
| 27a6b99453 | |||
| 61982de511 | |||
| efd9883197 | |||
| ce4ae8d90c | |||
| 1d2722f994 | |||
| 7e109e7f2d | |||
| f7a0b305df | |||
| 746ec71a0d | |||
| 41a63a0985 | |||
| 5a149c5492 | |||
| 7ff0becf72 | |||
| 4c2967a733 | |||
| 2b80e5d1c9 | |||
| 4e7ff53214 | |||
| 9ec36e49b7 | |||
| cdfa5ee540 | |||
| 71853f69f3 | |||
| dd13073037 | |||
| 1010df1077 | |||
| 9eaf9cf491 | |||
| 8e96318478 | |||
| bedff1f258 | |||
| 71a10a9a8b | |||
| 54287666e8 | |||
| 6de829163d | |||
| 605aed6f20 | |||
| adb5ed7c30 | |||
| 2b019e57df | |||
| 30c07712e3 | |||
| 82c92501d9 | |||
| c2a871a1a7 | |||
| dfd7bd5889 | |||
| 5aee4b1660 | |||
| 68a7bb67de | |||
| 7ff043d8df | |||
| 31e93428cf | |||
| 5f56b3eeea | |||
| e69b05693a | |||
| 8ae2451340 | |||
| b3b3279345 | |||
| 94a451c79b | |||
| ec7b959028 | |||
| 7061beea6e | |||
| e408162e26 | |||
| 25ae3895cb | |||
| 60296f2a41 | |||
| 3b97844310 | |||
| c904d245d2 | |||
| d315a2a91b | |||
| 0741d05ab3 | |||
| 61aa920362 | |||
| 24b9b17e64 | |||
| 5e3e633c4b | |||
| 8e6d3c34e2 | |||
| f3cff902ba | |||
| 4fe1b4c26f | |||
| cb24a08b06 | |||
| 597a53d11a | |||
| 639deeb502 | |||
| 03e082725e | |||
| 3e3307887e | |||
| d85683aaa8 | |||
| e89ed985fc | |||
| b1fb8bb18c | |||
| 45ebd7c37a | |||
| 3506020e55 | |||
| eca77d684b | |||
| e263a4a21f | |||
| dc4353c682 | |||
| e1d8069967 | |||
| 060726b7a3 | |||
| f72ccb0f0d | |||
| 2ff6bfbdd8 | |||
| d4f0b4772b | |||
| 17d258d094 | |||
| 8288d38257 | |||
| 1cd560c85e | |||
| 9018642992 | |||
| 04e652441e | |||
| ccf5990bc7 | |||
| 3d7c9ee2b8 | |||
| ad35c4006e | |||
| 2ec790e851 | |||
| 8f8cec0785 | |||
| 4a80cd301b | |||
| 63524eceff | |||
| a477b007e1 | |||
| 5b81510325 | |||
| 3bef973326 | |||
| bc5bb271d8 | |||
| 158e3cb073 | |||
| 36fb0eba29 | |||
| 1b37e85418 | |||
| 6a93497c8f | |||
| b8ee3465f8 | |||
| a7dfb36a84 | |||
| 14a7b5bdc8 | |||
| ffbd76539a | |||
| bdcc19e86a | |||
| 7929bac685 | |||
| f590aad42c | |||
| ec23f3dcb7 | |||
| 9644eb4329 | |||
| 7a4c6e4ed4 | |||
| d5ad504104 | |||
| d684f6d7ae | |||
| f0d9703587 | |||
| c08efef8ed | |||
| 6d29774744 | |||
| af6bab7703 | |||
| 7033f92d82 | |||
| 128dfa6d81 | |||
| 0b0ec075bb | |||
| cca4d21e7c | |||
| 4f59678ded | |||
| 8a1d2af3cf |
+17
-22
@@ -11,30 +11,25 @@
|
||||
# In each subsection folders are ordered first by depth, then alphabetically.
|
||||
# This should make it easy to add new rules without breaking existing ones.
|
||||
|
||||
# Something weird not covered by anything else
|
||||
* @futurechimp @mmsinclair
|
||||
# contracts
|
||||
/contracts/mixnet @durch @jstuczyn
|
||||
/contracts/vesting @durch @jstuczyn
|
||||
/contracts/service-provider-directory @octol
|
||||
|
||||
# Rust rules:
|
||||
*.rs @durch @futurechimp @jstuczyn @neacsu @octol
|
||||
Cargo.* @durch @futurechimp @jstuczyn @neacsu @octol
|
||||
# crypto code
|
||||
/common/crypto/ @jstuczyn
|
||||
/common/nymcoconut/ @jstuczyn
|
||||
/common/dkg/ @jstuczyn
|
||||
/common/nymsphinx/ @jstuczyn
|
||||
|
||||
# JS rules:
|
||||
*.js @mmsinclair @fmtabbara
|
||||
*.ts @mmsinclair @fmtabbara
|
||||
*.tsx @mmsinclair @fmtabbara
|
||||
*.jsx @mmsinclair @fmtabbara
|
||||
# rust sdk
|
||||
/sdk/rust/ @octol
|
||||
|
||||
# Something looking like possible documentation rules:
|
||||
*.md @mfahampshire
|
||||
# nym-connect (rust)
|
||||
/nym-connect/desktop/src-tauri/ @octol
|
||||
|
||||
# our docker scripts
|
||||
/docker/ @neacsu
|
||||
# nym-wallet (rust)
|
||||
/nym-wallet/src-tauri/ @octol
|
||||
|
||||
# if there are any changes in the core crypto, I feel like Ania should take a look:
|
||||
/common/crypto/ @aniampio
|
||||
/common/nymsphinx/ @aniampio
|
||||
|
||||
# Explorer and wallet should probably get looked by the product team
|
||||
/explorer/ @nymtech/product
|
||||
/nym-wallet/ @nymtech/product
|
||||
/wallet-web/ @nymtech/product
|
||||
# documentation
|
||||
/documentation @mfahampshire
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: 'Documentation'
|
||||
about: Suggest a fix or enhancement to the documentation or developer portal content
|
||||
title: "[DOCS]"
|
||||
labels: documentation
|
||||
assignees: mfahampshire
|
||||
|
||||
---
|
||||
|
||||
Is your issue either:
|
||||
- [ ] a fix to existing documentation (e.g. fixing a broken link or incorrect command)
|
||||
- [ ] an enhancement (e.g. adding a description for an undocumented feature)
|
||||
|
||||
Please briefly describe your issue:
|
||||
@@ -0,0 +1,16 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
# Maintain dependencies for GitHub Actions
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
commit-message:
|
||||
prefix: build
|
||||
prefix-development: chore
|
||||
include: scope
|
||||
@@ -79,6 +79,9 @@ jobs:
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Install wasm-opt
|
||||
run: cargo install --version 0.112.0 wasm-opt
|
||||
|
||||
- name: Build release contracts
|
||||
run: make wasm
|
||||
|
||||
@@ -95,10 +98,15 @@ jobs:
|
||||
cp target/release/nym-network-requester $OUTPUT_DIR
|
||||
cp target/release/nym-network-statistics $OUTPUT_DIR
|
||||
cp target/release/nym-cli $OUTPUT_DIR
|
||||
cp target/release/credential $OUTPUT_DIR
|
||||
cp target/release/nym-credential-client $OUTPUT_DIR
|
||||
cp target/release/explorer-api $OUTPUT_DIR
|
||||
|
||||
cp contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm $OUTPUT_DIR
|
||||
cp contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm $OUTPUT_DIR
|
||||
cp contracts/target/wasm32-unknown-unknown/release/nym_coconut_bandwidth.wasm $OUTPUT_DIR
|
||||
cp contracts/target/wasm32-unknown-unknown/release/nym_coconut_dkg.wasm $OUTPUT_DIR
|
||||
cp contracts/target/wasm32-unknown-unknown/release/cw3_flex_multisig.wasm $OUTPUT_DIR
|
||||
cp contracts/target/wasm32-unknown-unknown/release/cw4_group.wasm $OUTPUT_DIR
|
||||
|
||||
- name: Deploy branch to CI www
|
||||
continue-on-error: true
|
||||
|
||||
@@ -9,12 +9,14 @@ on:
|
||||
- 'gateway/**'
|
||||
- 'integrations/**'
|
||||
- 'mixnode/**'
|
||||
- 'sdk/lib/socks5-listener/**'
|
||||
- 'sdk/rust/nym-sdk/**'
|
||||
- 'service-providers/**'
|
||||
- 'nym-api/**'
|
||||
- 'nym-outfox/**'
|
||||
- 'tools/nym-cli/**'
|
||||
- 'tools/ts-rs-cli/**'
|
||||
- 'Cargo.toml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'clients/**'
|
||||
@@ -23,12 +25,14 @@ on:
|
||||
- 'gateway/**'
|
||||
- 'integrations/**'
|
||||
- 'mixnode/**'
|
||||
- 'sdk/lib/socks5-listener/**'
|
||||
- 'sdk/rust/nym-sdk/**'
|
||||
- 'service-providers/**'
|
||||
- 'nym-api/**'
|
||||
- 'nym-outfox/**'
|
||||
- 'tools/nym-cli/**'
|
||||
- 'tools/ts-rs-cli/**'
|
||||
- 'Cargo.toml'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
name: CD dev-portal
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: master
|
||||
paths:
|
||||
- 'documentation/dev-portal/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: custom-runner-linux
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "16"
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Install mdbook
|
||||
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook)
|
||||
- name: Install mdbook plugins
|
||||
run: |
|
||||
cargo install --vers "^0.2.0" mdbook-variables && cargo install \
|
||||
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
|
||||
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \
|
||||
mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck
|
||||
- name: Clean website
|
||||
run: cd documentation/dev-portal && mdbook clean
|
||||
- name: Build website
|
||||
run: cd documentation/dev-portal && mdbook build
|
||||
- name: Deploy branch master to dev
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "documentation/dev-portal/book/html/"
|
||||
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_DEV }}
|
||||
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET_DEVP }}/
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Deploy branch master to prod
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "documentation/dev-portal/book/html/"
|
||||
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_PROD }}
|
||||
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET_DEVP }}/
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Matrix - Send Notification
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: cd-dev
|
||||
NYM_PROJECT_NAME: "Dev portal CD"
|
||||
NYM_CI_WWW_BASE: "${{ secrets.NYM_CD_WWW_BASE }}"
|
||||
NYM_CI_WWW_LOCATION: "${{ env.GITHUB_REF_SLUG }}"
|
||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_DEVP }}"
|
||||
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
||||
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
||||
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||
@@ -0,0 +1,82 @@
|
||||
name: CD docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: master
|
||||
paths:
|
||||
- 'documentation/docs/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: custom-runner-linux
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "16"
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Build all binaries
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --workspace --release --all
|
||||
- name: Install mdbook
|
||||
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook)
|
||||
- name: Install mdbook plugins
|
||||
run: |
|
||||
cargo install --vers "^0.2.0" mdbook-variables && cargo install \
|
||||
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
|
||||
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \
|
||||
mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck && \
|
||||
cargo install --vers "^0.5.0" mdbook-cmdrun
|
||||
- name: Clean website
|
||||
run: cd documentation/docs && mdbook clean
|
||||
- name: Build website
|
||||
run: cd documentation/docs && mdbook build
|
||||
- name: Deploy branch master to dev
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "documentation/docs/book/"
|
||||
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_DEV }}
|
||||
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET }}/
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Deploy branch master to prod
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "documentation/docs/book/"
|
||||
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_PROD }}
|
||||
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET }}/
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Matrix - Send Notification
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: cd-docs
|
||||
NYM_PROJECT_NAME: "Docs CD"
|
||||
NYM_CI_WWW_BASE: "${{ secrets.NYM_CD_WWW_BASE }}"
|
||||
NYM_CI_WWW_LOCATION: "${{ env.GITHUB_REF_SLUG }}"
|
||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_DOCS }}"
|
||||
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
||||
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
||||
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||
@@ -0,0 +1,66 @@
|
||||
name: CI dev-portal
|
||||
|
||||
on:
|
||||
push:
|
||||
branches-ignore: master
|
||||
paths:
|
||||
- 'documentation/dev-portal/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: custom-runner-linux
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "16"
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Install mdbook
|
||||
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook)
|
||||
- name: Install mdbook plugins
|
||||
run: |
|
||||
cargo install --vers "^0.2.0" mdbook-variables && cargo install \
|
||||
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
|
||||
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" mdbook-theme \
|
||||
&& cargo install --vers "^0.7.7" mdbook-linkcheck
|
||||
- name: Clean website
|
||||
run: cd documentation/dev-portal && mdbook clean
|
||||
- name: Build website
|
||||
run: cd documentation/dev-portal && mdbook build
|
||||
- name: Deploy branch to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "documentation/dev-portal/book/html/"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/dev-portal-${{ env.GITHUB_REF_SLUG }}
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Matrix - Send Notification
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: ci-dev
|
||||
NYM_PROJECT_NAME: "Dev portal CI"
|
||||
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
|
||||
NYM_CI_WWW_LOCATION: "dev-portal-${{ env.GITHUB_REF_SLUG }}"
|
||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_DEVP }}"
|
||||
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
||||
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
||||
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||
@@ -0,0 +1,72 @@
|
||||
name: CI docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches-ignore: master
|
||||
paths:
|
||||
- 'documentation/docs/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: custom-runner-linux
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "16"
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Build all binaries
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --workspace --release --all
|
||||
- name: Install mdbook
|
||||
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook)
|
||||
- name: Install mdbook plugins
|
||||
run: |
|
||||
cargo install --vers "^0.2.0" mdbook-variables && cargo install \
|
||||
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
|
||||
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \
|
||||
mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck && \
|
||||
cargo install --vers "^0.5.0" mdbook-cmdrun
|
||||
- name: Clean website
|
||||
run: cd documentation/docs && mdbook clean
|
||||
- name: Build website
|
||||
run: cd documentation/docs && mdbook build
|
||||
- name: Deploy branch to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "documentation/docs/book/"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/docs-${{ env.GITHUB_REF_SLUG }}
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Matrix - Send Notification
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: ci-docs
|
||||
NYM_PROJECT_NAME: "Docs CI"
|
||||
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
|
||||
NYM_CI_WWW_LOCATION: "docs-${{ env.GITHUB_REF_SLUG }}"
|
||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_DOCS }}"
|
||||
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
||||
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
||||
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||
@@ -6,7 +6,7 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-contracts-') && github.event_name == 'release' }}
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-contracts-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
runs-on: [self-hosted, custom-runner-linux]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -19,6 +19,9 @@ jobs:
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Install wasm-opt
|
||||
run: cargo install --version 0.112.0 wasm-opt
|
||||
|
||||
- name: Build release contracts
|
||||
run: make wasm
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ jobs:
|
||||
continue-on-error: ${{ matrix.rust == 'nightly' }}
|
||||
needs: matrix_prep
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -63,4 +64,4 @@ jobs:
|
||||
if: ${{ matrix.rust != 'nightly' }}
|
||||
with:
|
||||
command: clippy
|
||||
args: --manifest-path contracts/Cargo.toml --workspace -- -D warnings
|
||||
args: --manifest-path contracts/Cargo.toml --workspace --all-targets -- -D warnings
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
name: Greetings
|
||||
|
||||
on: [pull_request_target, issues]
|
||||
|
||||
jobs:
|
||||
greeting:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/first-interaction@v1
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-message: 'Thank you for raising this issue'
|
||||
pr-message: 'Thank you for making this first PR'
|
||||
@@ -1,57 +0,0 @@
|
||||
name: CI for Network Explorer API
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
env:
|
||||
NETWORK: mainnet
|
||||
|
||||
jobs:
|
||||
publish-nym:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-explorer-api-') && (github.event_name == 'release' || github.event_name == 'workflow_dispatch') }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu-20.04]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install Dependencies (Linux)
|
||||
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools
|
||||
continue-on-error: true
|
||||
|
||||
- name: Check the release tag starts with `nym-explorer-api-`
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
script: |
|
||||
core.setFailed('Release tag did not start with nym-explorer-api-...')
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Build all explorer-api
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --manifest-path explorer-api/Cargo.toml --workspace --release
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: my-artifact
|
||||
path: |
|
||||
target/release/explorer-api
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
target/release/explorer-api
|
||||
@@ -6,7 +6,7 @@
|
||||
},
|
||||
|
||||
{
|
||||
"os":"windows-latest",
|
||||
"os":"windows10",
|
||||
"rust":"stable",
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
@@ -22,7 +22,7 @@
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
{
|
||||
"os":"windows-latest",
|
||||
"os":"windows10",
|
||||
"rust":"beta",
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
@@ -38,7 +38,7 @@
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
{
|
||||
"os":"windows-latest",
|
||||
"os":"windows10",
|
||||
"rust":"nightly",
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
name: Publish Nym CLI binaries
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
env:
|
||||
NETWORK: mainnet
|
||||
|
||||
jobs:
|
||||
publish-nym-cli:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-cli-') && (github.event_name == 'release' || github.event_name == 'workflow_dispatch') }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu-20.04, windows-latest, macos-latest]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Check the release tag starts with `nym-cli-`
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
script: |
|
||||
core.setFailed('Release tag did not start with nym-cli-...')
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Build binary
|
||||
run: make build-nym-cli
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-cli-${{ matrix.platform }}
|
||||
path: |
|
||||
target/release/nym-cli*
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
target/release/nym-cli
|
||||
@@ -10,7 +10,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release' }}
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
@@ -10,7 +10,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release' }}
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
@@ -16,7 +16,7 @@ env:
|
||||
|
||||
jobs:
|
||||
publish-nym:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release' }}
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
@@ -10,7 +10,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release' }}
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
@@ -9,7 +9,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release' }}
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
const Handlebars = require('handlebars');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
async function addToContextAndValidate(context) {
|
||||
if (!context.env.NYM_CI_WWW_LOCATION) {
|
||||
throw new Error('Please ensure the env var NYM_CI_WWW_LOCATION is set');
|
||||
}
|
||||
if (!context.env.NYM_CI_WWW_BASE) {
|
||||
throw new Error('Please ensure the env var NYM_CI_WWW_BASE is set');
|
||||
}
|
||||
}
|
||||
|
||||
async function getMessageBody(context) {
|
||||
const source = fs
|
||||
.readFileSync(
|
||||
context.env.IS_SUCCESS === 'true'
|
||||
? path.resolve(__dirname, 'templates', 'success')
|
||||
: path.resolve(__dirname, 'templates', 'failure'),
|
||||
)
|
||||
.toString();
|
||||
const template = Handlebars.compile(source);
|
||||
return template(context);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
addToContextAndValidate,
|
||||
getMessageBody,
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||
>
|
||||
> 🔴 **FAILURE** :cry:
|
||||
>
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
>
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
>
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
>
|
||||
|
||||
Commit message:
|
||||
|
||||
```
|
||||
{{ env.GIT_COMMIT_MESSAGE }}
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View output:** https://{{ env.NYM_CI_WWW_BASE }}/developers/
|
||||
>
|
||||
> ✅ **SUCCESS**
|
||||
>
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
>
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
>
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
>
|
||||
|
||||
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
|
||||
|
||||
```
|
||||
{{ env.GIT_COMMIT_MESSAGE }}
|
||||
```
|
||||
@@ -0,0 +1,29 @@
|
||||
const Handlebars = require('handlebars');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
async function addToContextAndValidate(context) {
|
||||
if (!context.env.NYM_CI_WWW_LOCATION) {
|
||||
throw new Error('Please ensure the env var NYM_CI_WWW_LOCATION is set');
|
||||
}
|
||||
if (!context.env.NYM_CI_WWW_BASE) {
|
||||
throw new Error('Please ensure the env var NYM_CI_WWW_BASE is set');
|
||||
}
|
||||
}
|
||||
|
||||
async function getMessageBody(context) {
|
||||
const source = fs
|
||||
.readFileSync(
|
||||
context.env.IS_SUCCESS === 'true'
|
||||
? path.resolve(__dirname, 'templates', 'success')
|
||||
: path.resolve(__dirname, 'templates', 'failure'),
|
||||
)
|
||||
.toString();
|
||||
const template = Handlebars.compile(source);
|
||||
return template(context);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
addToContextAndValidate,
|
||||
getMessageBody,
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||
> 🔴 **FAILURE** :cry:
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
|
||||
Commit message:
|
||||
```
|
||||
{{ env.GIT_COMMIT_MESSAGE }}
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View output:** https://{{ env.NYM_CI_WWW_BASE }}/docs/
|
||||
>
|
||||
> ✅ **SUCCESS**
|
||||
>
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
>
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
>
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
>
|
||||
|
||||
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
|
||||
|
||||
```
|
||||
{{ env.GIT_COMMIT_MESSAGE }}
|
||||
```
|
||||
@@ -0,0 +1,29 @@
|
||||
const Handlebars = require('handlebars');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
async function addToContextAndValidate(context) {
|
||||
if (!context.env.NYM_CI_WWW_LOCATION) {
|
||||
throw new Error('Please ensure the env var NYM_CI_WWW_LOCATION is set');
|
||||
}
|
||||
if (!context.env.NYM_CI_WWW_BASE) {
|
||||
throw new Error('Please ensure the env var NYM_CI_WWW_BASE is set');
|
||||
}
|
||||
}
|
||||
|
||||
async function getMessageBody(context) {
|
||||
const source = fs
|
||||
.readFileSync(
|
||||
context.env.IS_SUCCESS === 'true'
|
||||
? path.resolve(__dirname, 'templates', 'success')
|
||||
: path.resolve(__dirname, 'templates', 'failure'),
|
||||
)
|
||||
.toString();
|
||||
const template = Handlebars.compile(source);
|
||||
return template(context);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
addToContextAndValidate,
|
||||
getMessageBody,
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||
>
|
||||
> 🔴 **FAILURE** :cry:
|
||||
>
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
>
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
>
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
>
|
||||
|
||||
Commit message:
|
||||
|
||||
```
|
||||
{{ env.GIT_COMMIT_MESSAGE }}
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View output:** https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}/
|
||||
>
|
||||
> ✅ **SUCCESS**
|
||||
>
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
>
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
>
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
>
|
||||
|
||||
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
|
||||
|
||||
```
|
||||
{{ env.GIT_COMMIT_MESSAGE }}
|
||||
```
|
||||
@@ -0,0 +1,29 @@
|
||||
const Handlebars = require('handlebars');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
async function addToContextAndValidate(context) {
|
||||
if (!context.env.NYM_CI_WWW_LOCATION) {
|
||||
throw new Error('Please ensure the env var NYM_CI_WWW_LOCATION is set');
|
||||
}
|
||||
if (!context.env.NYM_CI_WWW_BASE) {
|
||||
throw new Error('Please ensure the env var NYM_CI_WWW_BASE is set');
|
||||
}
|
||||
}
|
||||
|
||||
async function getMessageBody(context) {
|
||||
const source = fs
|
||||
.readFileSync(
|
||||
context.env.IS_SUCCESS === 'true'
|
||||
? path.resolve(__dirname, 'templates', 'success')
|
||||
: path.resolve(__dirname, 'templates', 'failure'),
|
||||
)
|
||||
.toString();
|
||||
const template = Handlebars.compile(source);
|
||||
return template(context);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
addToContextAndValidate,
|
||||
getMessageBody,
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||
>
|
||||
> 🔴 **FAILURE** :cry:
|
||||
>
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
>
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
>
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
>
|
||||
|
||||
Commit message:
|
||||
|
||||
```
|
||||
{{ env.GIT_COMMIT_MESSAGE }}
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View output:** https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}/
|
||||
>
|
||||
> ✅ **SUCCESS**
|
||||
>
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
>
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
>
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
>
|
||||
|
||||
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
|
||||
|
||||
```
|
||||
{{ env.GIT_COMMIT_MESSAGE }}
|
||||
```
|
||||
@@ -3,7 +3,7 @@ require('dotenv').config();
|
||||
const { sendMatrixMessage } = require('./send_message_to_matrix');
|
||||
|
||||
let context = {
|
||||
kinds: ['nym-wallet', 'ts-packages', 'network-explorer', 'nightly', 'nym-connect','security'],
|
||||
kinds: ['nym-wallet', 'ts-packages', 'network-explorer', 'nightly', 'nym-connect','security','ci-docs','cd-docs','ci-dev','cd-dev'],
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,6 +22,6 @@
|
||||
"unified": "^9.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "2.3.2"
|
||||
"prettier": "^2.8.7"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
name: Upload nyxd to CI
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
publish-nyxd:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu-20.04]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare build output directory
|
||||
shell: bash
|
||||
env:
|
||||
OUTPUT_DIR: ci-builds/nyxd
|
||||
run: |
|
||||
rm -rf ci-builds || true
|
||||
mkdir -p $OUTPUT_DIR
|
||||
echo $OUTPUT_DIR
|
||||
|
||||
- name: Install Dependencies (Linux)
|
||||
run: sudo apt-get update && sudo apt-get -y install build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools git
|
||||
continue-on-error: true
|
||||
|
||||
- name: Update env variables to include go
|
||||
run: |
|
||||
sudo rm -rf /usr/local/go
|
||||
curl https://dl.google.com/go/go1.19.2.linux-amd64.tar.gz | sudo tar -C/usr/local -zxvf -
|
||||
cat <<'EOF' >>$HOME/.profile
|
||||
export GOROOT=/usr/local/go
|
||||
export GOPATH=$HOME/go
|
||||
export GO111MODULE=on
|
||||
export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin
|
||||
EOF
|
||||
source $HOME/.profile
|
||||
|
||||
- name: Verify Go is installed
|
||||
run: go version
|
||||
|
||||
- name: Clone nyxd repo
|
||||
run: |
|
||||
git clone https://github.com/tommyv1987/nyxd
|
||||
cd nyxd
|
||||
git checkout release/v0.30.2
|
||||
|
||||
- name: Run nyxd
|
||||
run: |
|
||||
pwd
|
||||
cd nyxd && make build
|
||||
sleep 10
|
||||
ls /home/runner/work/nym/nym/nyxd/build
|
||||
|
||||
- name: Prepare build output
|
||||
shell: bash
|
||||
env:
|
||||
OUTPUT_DIR: ci-builds/nyxd
|
||||
run: |
|
||||
cp /home/runner/work/nym/nym/nyxd/build/nyxd $OUTPUT_DIR
|
||||
WASMVM_SO=$(ldd /home/runner/work/nym/nym/nyxd/build/nyxd | grep "libwasm*" | awk '{ print $3 }')
|
||||
ls $WASMVM_SO
|
||||
sleep 3
|
||||
cp $(echo $WASMVM_SO) $OUTPUT_DIR
|
||||
|
||||
- name: Deploy nyxd to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-avzr"
|
||||
SOURCE: "ci-builds/"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/builds/
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
@@ -64,4 +64,4 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: --manifest-path nym-wallet/Cargo.toml --workspace --all-features -- -D warnings
|
||||
args: --manifest-path nym-wallet/Cargo.toml --workspace --all-features --all-targets -- -D warnings
|
||||
|
||||
+3
-2
@@ -8,6 +8,7 @@
|
||||
.idea
|
||||
target
|
||||
.env
|
||||
.env.dev
|
||||
/.vscode/settings.json
|
||||
validator/.vscode
|
||||
sample-configs/validator-config.toml
|
||||
@@ -39,7 +40,7 @@ validator-api-config.toml
|
||||
dist
|
||||
storybook-static
|
||||
envs/qwerty.env
|
||||
Cargo.lock
|
||||
nym-connect/Cargo.lock
|
||||
.parcel-cache
|
||||
**/.DS_Store
|
||||
cpu-cycles/libcpucycles/build
|
||||
foxyfox.env
|
||||
+155
@@ -4,6 +4,161 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v1.1.19] (2023-05-16)
|
||||
|
||||
- nym-name-service endpoint in nym-api ([#3403])
|
||||
- Implement key storage for WASM client using IndexedDB (for browser) ([#3329])
|
||||
- Initial version of nym-name-service contract providing name aliases for nym-addresses ([#3274])
|
||||
- Update Cargo.lock ([#3410])
|
||||
|
||||
[#3403]: https://github.com/nymtech/nym/issues/3403
|
||||
[#3329]: https://github.com/nymtech/nym/issues/3329
|
||||
[#3274]: https://github.com/nymtech/nym/issues/3274
|
||||
[#3410]: https://github.com/nymtech/nym/pull/3410
|
||||
|
||||
## [v1.1.18] (2023-05-09)
|
||||
|
||||
- Implement heartbeat messages between socks5 proxy and network requester ([#3215])
|
||||
|
||||
[#3215]: https://github.com/nymtech/nym/issues/3215
|
||||
|
||||
## [v1.1.17] (2023-05-02)
|
||||
|
||||
- Add service-provider-directory-contract support to nym-cli ([#3334])
|
||||
- Start using the node-testing-utils (implemented in #3270) in nym-api Network monitor to simplify the logic there ([#3312])
|
||||
- Add service-provider-directory support to validator-client ([#3296])
|
||||
- Allow topology injection in our WASM client ('test my node' feature) ([#3270])
|
||||
- Expose service-provider-directory contract data in nym-api endpoints ([#3242])
|
||||
- Cache service provider contract in nym-api ([#3241])
|
||||
- Feature/1 1 17 docs ([#3370])
|
||||
- adding a test for SP endpoint ([#3367])
|
||||
- Feature/store cipher ([#3350])
|
||||
|
||||
[#3334]: https://github.com/nymtech/nym/issues/3334
|
||||
[#3312]: https://github.com/nymtech/nym/issues/3312
|
||||
[#3296]: https://github.com/nymtech/nym/issues/3296
|
||||
[#3270]: https://github.com/nymtech/nym/issues/3270
|
||||
[#3242]: https://github.com/nymtech/nym/issues/3242
|
||||
[#3241]: https://github.com/nymtech/nym/issues/3241
|
||||
[#3370]: https://github.com/nymtech/nym/pull/3370
|
||||
[#3367]: https://github.com/nymtech/nym/pull/3367
|
||||
[#3350]: https://github.com/nymtech/nym/pull/3350
|
||||
|
||||
## [v1.1.16] (2023-04-25)
|
||||
|
||||
- Explorer - Fix sorting function on Stake Saturation. It is currently working per page and not globally ([#3320])
|
||||
- Poisson process gets stuck at too slow rate. Rework to more aggressively up-regulate ([#3309])
|
||||
- decrease the logging level of warnings associated with clients dropping packets due to gateway being overloaded (I'd say reduce it to debug/trace) - there are few sources of those, e.g. in real and cover traffic streams ([#3299])
|
||||
- Make the buffer size in `AvailableReader` depend on packet sizes the client is using + introduce read timeouts ([#3213])
|
||||
- Rust SDK - Support coconut, credential storage etc ([#2755])
|
||||
- version bump for next release ([#3349])
|
||||
- added coconut credential generation example ([#3339])
|
||||
- update mix-node setup docs with node description ([#3325])
|
||||
- exposed missing gateway commands in nym-cli ([#3324])
|
||||
- make sure to clear inner 'ack_map' in 'GatewaysReader' ([#3300])
|
||||
|
||||
[#3320]: https://github.com/nymtech/nym/issues/3320
|
||||
[#3309]: https://github.com/nymtech/nym/issues/3309
|
||||
[#3299]: https://github.com/nymtech/nym/issues/3299
|
||||
[#3213]: https://github.com/nymtech/nym/issues/3213
|
||||
[#2755]: https://github.com/nymtech/nym/issues/2755
|
||||
[#3349]: https://github.com/nymtech/nym/pull/3349
|
||||
[#3339]: https://github.com/nymtech/nym/pull/3339
|
||||
[#3325]: https://github.com/nymtech/nym/pull/3325
|
||||
[#3324]: https://github.com/nymtech/nym/pull/3324
|
||||
[#3300]: https://github.com/nymtech/nym/pull/3300
|
||||
|
||||
## [v1.1.15] (2023-04-18)
|
||||
|
||||
- Fix verloc being stuck waiting for shutdown signal ([#3250])
|
||||
- Introduce `--output json` flag to `sign` command to allow to more easily capture the output ([#3249])
|
||||
- Explorer - Dont fetch Service Provider list on Testnet ([#3245])
|
||||
- When determining active set, rather than weighting the nodes by just the `stake`, use `stake * performance` ([#3234])
|
||||
- Introduce dual packet sizes to our clients (as in use two packet sizes at the same time depending on message size) ([#3189])
|
||||
- Experiment with offline signing in our validator client ([#3174])
|
||||
- Modify network requester binary to reload `allowed.list` periodically to pull in any changes made upstream without having to restart the service ([#3149])
|
||||
- Standardise all `--output json` on binary inits, we pass the output json at different points for different binaries. ([#3080])
|
||||
- Service provider directory contract: initial version ([#2759])
|
||||
- Fix issue where network-requester run failed on fresh init due to missing allow file ([#3316])
|
||||
|
||||
[#3250]: https://github.com/nymtech/nym/issues/3250
|
||||
[#3249]: https://github.com/nymtech/nym/issues/3249
|
||||
[#3245]: https://github.com/nymtech/nym/issues/3245
|
||||
[#3234]: https://github.com/nymtech/nym/issues/3234
|
||||
[#3189]: https://github.com/nymtech/nym/issues/3189
|
||||
[#3174]: https://github.com/nymtech/nym/issues/3174
|
||||
[#3149]: https://github.com/nymtech/nym/issues/3149
|
||||
[#3080]: https://github.com/nymtech/nym/issues/3080
|
||||
[#2759]: https://github.com/nymtech/nym/issues/2759
|
||||
[#3316]: https://github.com/nymtech/nym/pull/3316
|
||||
|
||||
## [v1.1.14] (2023-04-04)
|
||||
|
||||
- Investigate cause of qwerty validator being in invalid rewarding state ([#3224])
|
||||
- Fix NR config due to changes in #3199 ([#3223])
|
||||
- [Issue] Mixnodes and gateway do not close connections properly ([#3187])
|
||||
- disable sign-ext when using wasm-opt + update wasm-opt ([#3203])
|
||||
- chore: tidy up client `Debug` config section ([#3199])
|
||||
|
||||
[#3224]: https://github.com/nymtech/nym/issues/3224
|
||||
[#3223]: https://github.com/nymtech/nym/issues/3223
|
||||
[#3187]: https://github.com/nymtech/nym/issues/3187
|
||||
[#3203]: https://github.com/nymtech/nym/pull/3203
|
||||
[#3199]: https://github.com/nymtech/nym/pull/3199
|
||||
>>>>>>> master
|
||||
|
||||
## [v1.1.13] (2023-03-15)
|
||||
|
||||
- NE - instead of throwing a "Mixnode/Gateway not found" error for blacklisted nodes due to bad performance, show their history but tag them as "Having poor performance" ([#2979])
|
||||
- NE - Upgrade Sandbox and make below changes: ([#2332])
|
||||
- Explorer - Updates ([#3168])
|
||||
- Website v2 - deploy infrastructure for strapi and CI ([#2213])
|
||||
- add blockstream green to sp list ([#3180])
|
||||
- mock-nym-api: fix .storybook lint error ([#3178])
|
||||
- Validating new interval config parameters to prevent division by zero ([#3153])
|
||||
|
||||
[#2979]: https://github.com/nymtech/nym/issues/2979
|
||||
[#2332]: https://github.com/nymtech/nym/issues/2332
|
||||
[#3168]: https://github.com/nymtech/nym/issues/3168
|
||||
[#2213]: https://github.com/nymtech/nym/issues/2213
|
||||
[#3180]: https://github.com/nymtech/nym/pull/3180
|
||||
[#3178]: https://github.com/nymtech/nym/pull/3178
|
||||
[#3153]: https://github.com/nymtech/nym/pull/3153
|
||||
|
||||
## [v1.1.12] (2023-03-07)
|
||||
|
||||
- Fix generated docs for mixnet and vesting contract on docs.rs ([#3093])
|
||||
- Introduce a way of injecting topology into the client ([#3044])
|
||||
- Update mixnet TypeScript client methods #1 ([#2783])
|
||||
- Update tooltips for routing and average score ([#3133])
|
||||
- update selected service provider description style ([#3128])
|
||||
|
||||
[#3093]: https://github.com/nymtech/nym/issues/3093
|
||||
[#3044]: https://github.com/nymtech/nym/issues/3044
|
||||
[#2783]: https://github.com/nymtech/nym/issues/2783
|
||||
[#3133]: https://github.com/nymtech/nym/pull/3133
|
||||
[#3128]: https://github.com/nymtech/nym/pull/3128
|
||||
|
||||
## [v1.1.11] (2023-02-28)
|
||||
|
||||
- Fix empty dealer set loop ([#3105])
|
||||
- The nym-api db.sqlite is broken when trying to run against it it in `enabled-credentials-mode true` there is an ordering issue with migrations when using the credential binary to purchase bandwidth ([#3100])
|
||||
- Feature/latency based gateway selection ([#3081])
|
||||
- Fix the credential binary to handle transactions to sleep when in non-inProgress epochs ([#3057])
|
||||
- Publish mixnet contract to crates.io ([#1919])
|
||||
- Publish vesting contract to crates.io ([#1920])
|
||||
- Feature/update checker to use master ([#3097])
|
||||
- Feature/improve binary checks ([#3094])
|
||||
|
||||
[#3105]: https://github.com/nymtech/nym/issues/3105
|
||||
[#3100]: https://github.com/nymtech/nym/issues/3100
|
||||
[#3081]: https://github.com/nymtech/nym/pull/3081
|
||||
[#3057]: https://github.com/nymtech/nym/issues/3057
|
||||
[#1919]: https://github.com/nymtech/nym/issues/1919
|
||||
[#1920]: https://github.com/nymtech/nym/issues/1920
|
||||
[#3097]: https://github.com/nymtech/nym/pull/3097
|
||||
[#3094]: https://github.com/nymtech/nym/pull/3094
|
||||
|
||||
## [v1.1.10] (2023-02-21)
|
||||
|
||||
- Verloc listener causing mixnode unexpected shutdown ([#3038])
|
||||
|
||||
Generated
+1848
-1337
File diff suppressed because it is too large
Load Diff
+30
-6
@@ -17,13 +17,14 @@ opt-level = 3
|
||||
|
||||
resolver = "2"
|
||||
members = [
|
||||
"clients/client-core",
|
||||
"clients/credential",
|
||||
"clients/native",
|
||||
"clients/native/websocket-requests",
|
||||
"clients/socks5",
|
||||
"common/bandwidth-claim-contract",
|
||||
"common/async-file-watcher",
|
||||
"common/bandwidth-controller",
|
||||
"common/bin-common",
|
||||
"common/client-core",
|
||||
"common/client-libs/gateway-client",
|
||||
"common/client-libs/mixnet-client",
|
||||
"common/client-libs/validator-client",
|
||||
@@ -36,8 +37,9 @@ members = [
|
||||
"common/cosmwasm-smart-contracts/group-contract",
|
||||
"common/cosmwasm-smart-contracts/mixnet-contract",
|
||||
"common/cosmwasm-smart-contracts/multisig-contract",
|
||||
"common/cosmwasm-smart-contracts/name-service",
|
||||
"common/cosmwasm-smart-contracts/service-provider-directory",
|
||||
"common/cosmwasm-smart-contracts/vesting-contract",
|
||||
"common/mobile-storage",
|
||||
"common/credential-storage",
|
||||
"common/credentials",
|
||||
"common/crypto",
|
||||
@@ -47,6 +49,7 @@ members = [
|
||||
"common/ledger",
|
||||
"common/mixnode-common",
|
||||
"common/network-defaults",
|
||||
"common/node-tester-utils",
|
||||
"common/nonexhaustive-delayqueue",
|
||||
"common/nymcoconut",
|
||||
"common/nymsphinx",
|
||||
@@ -58,11 +61,14 @@ members = [
|
||||
"common/nymsphinx/forwarding",
|
||||
"common/nymsphinx/framing",
|
||||
"common/nymsphinx/params",
|
||||
"common/nymsphinx/routing",
|
||||
"common/nymsphinx/types",
|
||||
"common/pemstore",
|
||||
"common/socks5-client-core",
|
||||
"common/socks5/proxy-helpers",
|
||||
"common/socks5/requests",
|
||||
"common/statistics",
|
||||
"common/store-cipher",
|
||||
"common/task",
|
||||
"common/topology",
|
||||
"common/types",
|
||||
@@ -72,6 +78,7 @@ members = [
|
||||
"gateway/gateway-requests",
|
||||
"integrations/bity",
|
||||
"mixnode",
|
||||
"sdk/lib/socks5-listener",
|
||||
"sdk/rust/nym-sdk",
|
||||
"service-providers/common",
|
||||
"service-providers/network-requester",
|
||||
@@ -94,7 +101,7 @@ default-members = [
|
||||
"explorer-api",
|
||||
]
|
||||
|
||||
exclude = ["explorer", "contracts", "clients/webassembly", "nym-wallet", "nym-connect/mobile/src-tauri", "nym-connect/desktop"]
|
||||
exclude = ["explorer", "contracts", "clients/webassembly", "nym-wallet", "nym-connect/mobile/src-tauri", "nym-connect/desktop", "cpu-cycles"]
|
||||
|
||||
[workspace.package]
|
||||
authors = ["Nym Technologies SA"]
|
||||
@@ -105,9 +112,25 @@ edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
|
||||
[workspace.dependencies]
|
||||
async-trait = "0.1.63"
|
||||
async-trait = "0.1.64"
|
||||
anyhow = "1.0.71"
|
||||
bip39 = { version = "2.0.0", features = ["zeroize"] }
|
||||
cfg-if = "1.0.0"
|
||||
dotenv = "0.15.0"
|
||||
cosmwasm-derive = "=1.2.5"
|
||||
cosmwasm-schema = "=1.2.5"
|
||||
cosmwasm-std = "=1.2.5"
|
||||
cosmwasm-storage = "=1.2.5"
|
||||
cosmrs = "=0.8.0"
|
||||
cw-utils = "=1.0.1"
|
||||
cw-storage-plus = "=1.0.1"
|
||||
cw2 = { version = "=1.0.1" }
|
||||
cw3 = { version = "=1.0.1" }
|
||||
cw3-fixed-multisig = { version = "=1.0.1" }
|
||||
cw4 = { version = "=1.0.1" }
|
||||
cw-controllers = { version = "=1.0.1" }
|
||||
dotenvy = "0.15.6"
|
||||
generic-array = "0.14.7"
|
||||
k256 = "0.11"
|
||||
lazy_static = "1.4.0"
|
||||
log = "0.4"
|
||||
once_cell = "1.7.2"
|
||||
@@ -118,3 +141,4 @@ tap = "1.0.1"
|
||||
thiserror = "1.0.38"
|
||||
tokio = "1.24.1"
|
||||
url = "2.2"
|
||||
zeroize = "1.6.0"
|
||||
|
||||
@@ -1,132 +1,122 @@
|
||||
# Default target
|
||||
all: test
|
||||
|
||||
test: clippy-all cargo-test wasm fmt
|
||||
|
||||
test-all: test cargo-test-expensive
|
||||
|
||||
no-clippy: build cargo-test wasm fmt
|
||||
|
||||
happy: fmt clippy-happy test
|
||||
clippy-all: clippy-main clippy-main-examples clippy-all-contracts clippy-all-wallet clippy-all-connect clippy-all-connect-mobile clippy-all-wasm-client
|
||||
clippy-happy: clippy-happy-main clippy-happy-contracts clippy-happy-wallet clippy-happy-connect clippy-happy-connect-mobile
|
||||
cargo-test: test-main test-contracts test-wallet test-connect test-connect-mobile
|
||||
cargo-test-expensive: test-main-expensive test-contracts-expensive test-wallet-expensive test-connect-expensive
|
||||
build: build-contracts build-wallet build-main build-main-examples build-connect build-connect-mobile build-wasm-client
|
||||
fmt: fmt-main fmt-contracts fmt-wallet fmt-connect fmt-connect-mobile fmt-wasm-client
|
||||
|
||||
clippy-happy-main:
|
||||
cargo clippy
|
||||
# Building release binaries is a little manual as we can't just build --release
|
||||
# on all workspaces.
|
||||
build-release: build-release-main wasm
|
||||
|
||||
clippy-happy-contracts:
|
||||
cargo clippy --manifest-path contracts/Cargo.toml --target wasm32-unknown-unknown
|
||||
# Deprecated
|
||||
# For backwards compatibility
|
||||
clippy-all: clippy
|
||||
|
||||
clippy-happy-wallet:
|
||||
cargo clippy --manifest-path nym-wallet/Cargo.toml
|
||||
# -----------------------------------------------------------------------------
|
||||
# Define targets for a given workspace
|
||||
# $(1): name
|
||||
# $(2): path to workspace
|
||||
# $(3): extra arguments to cargo
|
||||
# -----------------------------------------------------------------------------
|
||||
define add_cargo_workspace
|
||||
|
||||
clippy-happy-connect:
|
||||
cargo clippy --manifest-path nym-connect/desktop/Cargo.toml
|
||||
clippy-happy-$(1):
|
||||
cargo clippy --manifest-path $(2)/Cargo.toml $(3)
|
||||
|
||||
clippy-happy-connect-mobile:
|
||||
cargo clippy --manifest-path nym-connect/mobile/src-tauri/Cargo.toml
|
||||
clippy-$(1):
|
||||
cargo clippy --manifest-path $(2)/Cargo.toml --workspace $(3) -- -D warnings
|
||||
|
||||
clippy-main:
|
||||
cargo clippy --workspace -- -D warnings
|
||||
clippy-examples-$(1):
|
||||
cargo clippy --manifest-path $(2)/Cargo.toml --workspace --examples -- -D warnings
|
||||
|
||||
clippy-main-examples:
|
||||
cargo clippy --workspace --examples -- -D warnings
|
||||
check-$(1):
|
||||
cargo check --manifest-path $(2)/Cargo.toml --workspace $(3)
|
||||
|
||||
clippy-wasm:
|
||||
cargo clippy --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown --workspace -- -D warnings
|
||||
test-$(1):
|
||||
cargo test --manifest-path $(2)/Cargo.toml --workspace
|
||||
|
||||
test-expensive-$(1):
|
||||
cargo test --manifest-path $(2)/Cargo.toml --workspace -- --ignored
|
||||
|
||||
clippy-all-contracts:
|
||||
cargo clippy --workspace --manifest-path contracts/Cargo.toml --all-features --target wasm32-unknown-unknown -- -D warnings
|
||||
build-$(1):
|
||||
cargo build --manifest-path $(2)/Cargo.toml --workspace $(3)
|
||||
|
||||
clippy-all-wallet:
|
||||
cargo clippy --workspace --manifest-path nym-wallet/Cargo.toml --all-features -- -D warnings
|
||||
build-examples-$(1):
|
||||
cargo build --manifest-path $(2)/Cargo.toml --workspace --examples
|
||||
|
||||
clippy-all-connect:
|
||||
cargo clippy --workspace --manifest-path nym-connect/desktop/Cargo.toml --all-features -- -D warnings
|
||||
build-release-$(1):
|
||||
cargo build --manifest-path $(2)/Cargo.toml --workspace --release $(3)
|
||||
|
||||
clippy-all-connect-mobile:
|
||||
cargo clippy --workspace --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --all-features -- -D warnings
|
||||
fmt-$(1):
|
||||
cargo fmt --manifest-path $(2)/Cargo.toml --all
|
||||
|
||||
clippy-all-wasm-client:
|
||||
cargo clippy --workspace --manifest-path clients/webassembly/Cargo.toml --all-features --target wasm32-unknown-unknown -- -D warnings
|
||||
clippy-happy: clippy-happy-$(1)
|
||||
clippy: clippy-$(1) clippy-examples-$(1)
|
||||
check: check-$(1)
|
||||
cargo-test: test-$(1)
|
||||
cargo-test-expensive: test-expensive-$(1)
|
||||
build: build-$(1) build-examples-$(1)
|
||||
build-release-all: build-release-$(1)
|
||||
fmt: fmt-$(1)
|
||||
|
||||
test-main:
|
||||
cargo test --workspace
|
||||
endef
|
||||
|
||||
test-main-expensive:
|
||||
cargo test --workspace -- --ignored
|
||||
# -----------------------------------------------------------------------------
|
||||
# Rust workspaces
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
test-contracts:
|
||||
cargo test --manifest-path contracts/Cargo.toml --all-features
|
||||
# Generate targets for the various cargo workspaces
|
||||
|
||||
test-contracts-expensive:
|
||||
cargo test --manifest-path contracts/Cargo.toml --all-features -- --ignored
|
||||
$(eval $(call add_cargo_workspace,main,.))
|
||||
$(eval $(call add_cargo_workspace,contracts,contracts,--target wasm32-unknown-unknown))
|
||||
$(eval $(call add_cargo_workspace,wasm-client,clients/webassembly,--target wasm32-unknown-unknown))
|
||||
$(eval $(call add_cargo_workspace,wallet,nym-wallet,))
|
||||
$(eval $(call add_cargo_workspace,connect,nym-connect/desktop))
|
||||
ifdef NYM_MOBILE
|
||||
$(eval $(call add_cargo_workspace,connect-mobile,nym-connect/mobile/src-tauri))
|
||||
endif
|
||||
|
||||
test-wallet:
|
||||
cargo test --manifest-path nym-wallet/Cargo.toml --all-features
|
||||
|
||||
test-wallet-expensive:
|
||||
cargo test --manifest-path nym-wallet/Cargo.toml --all-features -- --ignored
|
||||
|
||||
test-connect:
|
||||
cargo test --manifest-path nym-connect/desktop/Cargo.toml --all-features
|
||||
|
||||
test-connect-expensive:
|
||||
cargo test --manifest-path nym-connect/desktop/Cargo.toml --all-features -- --ignored
|
||||
|
||||
test-connect-mobile:
|
||||
cargo test --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --all-features
|
||||
|
||||
test-connect-mobile-expensive:
|
||||
cargo test --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --all-features -- --ignored
|
||||
|
||||
build-main:
|
||||
cargo build --workspace
|
||||
|
||||
build-main-examples:
|
||||
cargo build --workspace --examples
|
||||
|
||||
build-contracts:
|
||||
cargo build --manifest-path contracts/Cargo.toml --workspace
|
||||
|
||||
build-wallet:
|
||||
cargo build --manifest-path nym-wallet/Cargo.toml --workspace
|
||||
|
||||
build-connect:
|
||||
cargo build --manifest-path nym-connect/desktop/Cargo.toml --workspace
|
||||
|
||||
build-connect-mobile:
|
||||
cargo build --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --workspace
|
||||
# -----------------------------------------------------------------------------
|
||||
# Convenience targets for crates that are already part of the main workspace
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
build-explorer-api:
|
||||
cargo build --manifest-path explorer-api/Cargo.toml --workspace
|
||||
|
||||
build-wasm-client:
|
||||
cargo build --manifest-path clients/webassembly/Cargo.toml --workspace --target wasm32-unknown-unknown
|
||||
cargo build -p explorer-api
|
||||
|
||||
build-nym-cli:
|
||||
cargo build --release --manifest-path tools/nym-cli/Cargo.toml
|
||||
cargo build -p nym-cli --release
|
||||
|
||||
fmt-main:
|
||||
cargo fmt --all
|
||||
# -----------------------------------------------------------------------------
|
||||
# Build contracts ready for deploy
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
fmt-contracts:
|
||||
cargo fmt --manifest-path contracts/Cargo.toml --all
|
||||
CONTRACTS_OUT_DIR=contracts/target/wasm32-unknown-unknown/release
|
||||
VESTING_CONTRACT=$(CONTRACTS_OUT_DIR)/vesting_contract.wasm
|
||||
MIXNET_CONTRACT=$(CONTRACTS_OUT_DIR)/mixnet_contract.wasm
|
||||
SERVICE_PROVIDER_DIRECTORY_CONTRACT=$(CONTRACTS_OUT_DIR)/nym_service_provider_directory.wasm
|
||||
NAME_SERVICE_CONTRACT=$(CONTRACTS_OUT_DIR)/nym_name_service.wasm
|
||||
|
||||
fmt-wallet:
|
||||
cargo fmt --manifest-path nym-wallet/Cargo.toml --all
|
||||
wasm: wasm-build wasm-opt
|
||||
|
||||
fmt-connect:
|
||||
cargo fmt --manifest-path nym-connect/desktop/Cargo.toml --all
|
||||
|
||||
fmt-connect-mobile:
|
||||
cargo fmt --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --all
|
||||
|
||||
fmt-wasm-client:
|
||||
cargo fmt --manifest-path clients/webassembly/Cargo.toml --all
|
||||
|
||||
wasm:
|
||||
wasm-build:
|
||||
RUSTFLAGS='-C link-arg=-s' cargo build --manifest-path contracts/Cargo.toml --release --target wasm32-unknown-unknown
|
||||
|
||||
wasm-opt:
|
||||
wasm-opt --disable-sign-ext -Os $(VESTING_CONTRACT) -o $(VESTING_CONTRACT)
|
||||
wasm-opt --disable-sign-ext -Os $(MIXNET_CONTRACT) -o $(MIXNET_CONTRACT)
|
||||
wasm-opt --disable-sign-ext -Os $(SERVICE_PROVIDER_DIRECTORY_CONTRACT) -o $(SERVICE_PROVIDER_DIRECTORY_CONTRACT)
|
||||
wasm-opt --disable-sign-ext -Os $(NAME_SERVICE_CONTRACT) -o $(NAME_SERVICE_CONTRACT)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Misc
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# NOTE: this seems deprecated an not needed anymore?
|
||||
mixnet-opt: wasm
|
||||
cd contracts/mixnet && make opt
|
||||
|
||||
|
||||
@@ -16,12 +16,12 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
|
||||
* nym-wallet - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
|
||||
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
[](https://github.com/nymtech/nym/actions?query=branch%3Adevelop)
|
||||
[](https://github.com/nymtech/nym/actions?query=branch%3Adevelop)
|
||||
|
||||
|
||||
### Building
|
||||
|
||||
Platform build instructions are available on [our docs site](https://nymtech.net/docs/stable/run-nym-nodes/build-nym).
|
||||
Platform build instructions are available on [our docs site](https://nymtech.net/docs/binaries/building-nym.html).
|
||||
Wallet build instructions are also available on [our docs site](https://nymtech.net/docs/stable/nym-apps/wallet#for-developers).
|
||||
|
||||
### Developing
|
||||
@@ -32,7 +32,7 @@ For Typescript components, please see [ts-packages](./ts-packages).
|
||||
|
||||
### Developer chat
|
||||
|
||||
You can chat to us in [Keybase](https://keybase.io). Download their chat app, then click **Teams -> Join a team**. Type **nymtech.friends** into the team name and hit **continue**. For general chat, hang out in the **#general** channel. Our development takes places in the **#dev** channel. Node operators should be in the **#node-operators** channel.
|
||||
You can chat with us in [Keybase](https://keybase.io). Download their chat app, then click **Teams -> Join a team**. Type **nymtech.friends** into the team name and hit **continue**. For general chat, hang out in the **#general** channel. Our development takes place in the **#dev** channel. Node operators should be in the **#node-operators** channel.
|
||||
|
||||
### Rewards
|
||||
|
||||
@@ -46,7 +46,7 @@ Node, node operator and delegator rewards are determined according to the princi
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=\lambda_{i}#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}\lambda_{i}#gh-dark-mode-only">|ratio of stake operator has pledged to their node to the token circulating supply.
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=\omega_{i}#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}\omega_{i}#gh-dark-mode-only">|fraction of total effort undertaken by node `i`, set to `1/k`.
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=k#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}k#gh-dark-mode-only">|number of nodes stakeholders are incentivised to create, set by the validators, a matter of governance. Currently determined by the `reward set` size, and set to 720 in testnet Sandbox.
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=\alpha#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}\alpha#gh-dark-mode-only">|Sybil attack resistance parameter - the higher this parameter is set the stronger the reduction in competitivness gets for a Sybil attacker.
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=\alpha#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}\alpha#gh-dark-mode-only">|Sybil attack resistance parameter - the higher this parameter is set the stronger the reduction in competitiveness gets for a Sybil attacker.
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=PM_{i}#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}PM_{i}#gh-dark-mode-only">|declared profit margin of operator `i`, defaults to 10% in.
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=PF_{i}#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}PF_{i}#gh-dark-mode-only">|uptime of node `i`, scaled to 0 - 1, for the rewarding epoch
|
||||
|<img src="https://render.githubusercontent.com/render/math?math=PP_{i}#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}PP_{i}#gh-dark-mode-only">|cost of operating node `i` for the duration of the rewarding epoch, set to 40 NYMT.
|
||||
@@ -70,7 +70,7 @@ Operator of node `i` is credited with the following amount:
|
||||
<img src="https://render.githubusercontent.com/render/math?math=min\{PP_{i},R_{i})\} %2b max\{0, (PM_{i} %2b (1 - PM_{i}) \cdot \lambda_{i}/\delta_{i}) \cdot (R_{i} - PP_{i})\}#gh-light-mode-only">
|
||||
<img src="https://render.githubusercontent.com/render/math?math=\color{white}min\{PP_{i},R_{i})\} %2b max\{0, (PM_{i} %2b (1 - PM_{i}) \cdot \lambda_{i}/\delta_{i}) \cdot (R_{i} - PP_{i})\}#gh-dark-mode-only">
|
||||
|
||||
Delegate with stake `s` recieves:
|
||||
Delegate with stake `s` receives:
|
||||
|
||||
<img src="https://render.githubusercontent.com/render/math?math=max\{0, (1-PM_{i}) \cdot (s^'/\sigma_{i}) \cdot (R_{i} - PP_{i})\}#gh-light-mode-only">
|
||||
<img src="https://render.githubusercontent.com/render/math?math=\color{white}max\{0, (1-PM_{i}) \cdot (s^'/\sigma_{i}) \cdot (R_{i} - PP_{i})\}#gh-dark-mode-only">
|
||||
|
||||
+3
-3
@@ -3,8 +3,8 @@ Critical bug or security issue 💥
|
||||
If you're here because you're trying to figure out how to notify us of a security issue, go to Discord, and alert the core engineers:
|
||||
|
||||
Dave Hrycyszyn futurechimp#5430
|
||||
Drazen Urch drazen#4873
|
||||
Jedrzej Stuczynski "Jedrzej | Nym#5666"
|
||||
Fran Arbanas | franarbanas#0995
|
||||
Mark Sinclair | marknym#8088
|
||||
|
||||
|
||||
Please avoid opening public issues on GitHub that contain information about a potential security vulnerability as this makes it difficult to reduce the impact and harm of valid security issues.
|
||||
Please avoid opening public issues on GitHub that contain information about a potential security vulnerability as this makes it difficult to reduce the impact and harm of valid security issues.
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::replies::reply_storage::{
|
||||
fs_backend, CombinedReplyStorage, ReplyStorageBackend,
|
||||
};
|
||||
use crate::config::DebugConfig;
|
||||
use crate::error::ClientCoreError;
|
||||
use log::{error, info};
|
||||
use std::path::Path;
|
||||
use std::{fs, io};
|
||||
use time::OffsetDateTime;
|
||||
|
||||
async fn setup_fresh_backend<P: AsRef<Path>>(
|
||||
db_path: P,
|
||||
debug_config: &DebugConfig,
|
||||
) -> Result<fs_backend::Backend, ClientCoreError> {
|
||||
info!("creating fresh surb database");
|
||||
let mut storage_backend = match fs_backend::Backend::init(db_path).await {
|
||||
Ok(backend) => backend,
|
||||
Err(err) => {
|
||||
error!("failed to setup persistent storage backend for our reply needs: {err}");
|
||||
return Err(ClientCoreError::SurbStorageError {
|
||||
source: Box::new(err),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// while I kinda hate that we're going to be creating `CombinedReplyStorage` twice,
|
||||
// it will only be happening on the very first run and in practice won't incur huge
|
||||
// costs since the storage is going to be empty
|
||||
let mem_store = CombinedReplyStorage::new(
|
||||
debug_config.minimum_reply_surb_storage_threshold,
|
||||
debug_config.maximum_reply_surb_storage_threshold,
|
||||
);
|
||||
storage_backend
|
||||
.init_fresh(&mem_store)
|
||||
.await
|
||||
.map_err(|err| ClientCoreError::SurbStorageError {
|
||||
source: Box::new(err),
|
||||
})?;
|
||||
|
||||
Ok(storage_backend)
|
||||
}
|
||||
|
||||
fn setup_inactive_backend(debug_config: &DebugConfig) -> fs_backend::Backend {
|
||||
info!("creating inactive surb database");
|
||||
fs_backend::Backend::new_inactive(
|
||||
debug_config.minimum_reply_surb_storage_threshold,
|
||||
debug_config.maximum_reply_surb_storage_threshold,
|
||||
)
|
||||
}
|
||||
|
||||
fn archive_corrupted_database<P: AsRef<Path>>(db_path: P) -> io::Result<()> {
|
||||
let db_path = db_path.as_ref();
|
||||
debug_assert!(db_path.exists());
|
||||
|
||||
let now = OffsetDateTime::now_utc().unix_timestamp();
|
||||
|
||||
let suffix = format!("_{now}.corrupted");
|
||||
|
||||
let new_extension =
|
||||
if let Some(existing_extension) = db_path.extension().and_then(|ext| ext.to_str()) {
|
||||
format!("{existing_extension}.{suffix}")
|
||||
} else {
|
||||
suffix
|
||||
};
|
||||
|
||||
let mut renamed = db_path.to_owned();
|
||||
renamed.set_extension(new_extension);
|
||||
|
||||
fs::rename(db_path, renamed)
|
||||
}
|
||||
|
||||
pub async fn setup_fs_reply_surb_backend<P: AsRef<Path>>(
|
||||
db_path: Option<P>,
|
||||
debug_config: &DebugConfig,
|
||||
) -> Result<fs_backend::Backend, ClientCoreError> {
|
||||
if let Some(db_path) = db_path {
|
||||
// if the database file doesnt exist, initialise fresh storage, otherwise attempt to load
|
||||
// the existing one
|
||||
let db_path = db_path.as_ref();
|
||||
if db_path.exists() {
|
||||
info!("loading existing surb database");
|
||||
match fs_backend::Backend::try_load(db_path).await {
|
||||
Ok(backend) => Ok(backend),
|
||||
Err(err) => {
|
||||
error!("failed to setup persistent storage backend for our reply needs: {err}. We're going to create a fresh database instead. This behaviour might change in the future");
|
||||
|
||||
archive_corrupted_database(db_path)?;
|
||||
setup_fresh_backend(db_path, debug_config).await
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setup_fresh_backend(db_path, debug_config).await
|
||||
}
|
||||
} else {
|
||||
Ok(setup_inactive_backend(debug_config))
|
||||
}
|
||||
}
|
||||
@@ -1,227 +0,0 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||
use gateway_requests::registration::handshake::SharedKeys;
|
||||
use log::*;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_sphinx::acknowledgements::AckKey;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
|
||||
// Note: to support key rotation in the future, all keys will require adding an extra smart pointer,
|
||||
// most likely an AtomicCell, or if it doesn't work as I think it does, a Mutex. Although I think
|
||||
// AtomicCell includes a Mutex implicitly if the underlying type does not work atomically.
|
||||
// And I guess there will need to be some mechanism for a grace period when you can still
|
||||
// use the old key after new one was issued.
|
||||
|
||||
// Remember that Arc<T> has Deref implementation for T
|
||||
#[derive(Clone)]
|
||||
pub struct KeyManager {
|
||||
/// identity key associated with the client instance.
|
||||
identity_keypair: Arc<identity::KeyPair>,
|
||||
|
||||
/// encryption key associated with the client instance.
|
||||
encryption_keypair: Arc<encryption::KeyPair>,
|
||||
|
||||
/// shared key derived with the gateway during "registration handshake"
|
||||
gateway_shared_key: Option<Arc<SharedKeys>>,
|
||||
|
||||
/// key used for producing and processing acknowledgement packets.
|
||||
ack_key: Arc<AckKey>,
|
||||
}
|
||||
|
||||
// The expected flow of a KeyManager "lifetime" is as follows:
|
||||
/*
|
||||
1. ::new() is called during client-init
|
||||
2. after gateway registration is completed [in init] ::insert_gateway_shared_key() is called
|
||||
3. ::store_keys() is called before init finishes execution.
|
||||
4. ::load_keys() is called at the beginning of each subsequent client-run
|
||||
5. [not implemented] ::rotate_keys() is called periodically during client-run I presume?
|
||||
*/
|
||||
|
||||
impl KeyManager {
|
||||
/// Creates new instance of a [`KeyManager`]
|
||||
pub fn new<R>(rng: &mut R) -> Self
|
||||
where
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
KeyManager {
|
||||
identity_keypair: Arc::new(identity::KeyPair::new(rng)),
|
||||
encryption_keypair: Arc::new(encryption::KeyPair::new(rng)),
|
||||
gateway_shared_key: None,
|
||||
ack_key: Arc::new(AckKey::new(rng)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_keys(
|
||||
id_keypair: identity::KeyPair,
|
||||
enc_keypair: encryption::KeyPair,
|
||||
gateway_shared_key: SharedKeys,
|
||||
ack_key: AckKey,
|
||||
) -> Self {
|
||||
Self {
|
||||
identity_keypair: Arc::new(id_keypair),
|
||||
encryption_keypair: Arc::new(enc_keypair),
|
||||
gateway_shared_key: Some(Arc::new(gateway_shared_key)),
|
||||
ack_key: Arc::new(ack_key),
|
||||
}
|
||||
}
|
||||
|
||||
/// Loads previously stored client keys from the disk.
|
||||
fn load_client_keys(client_pathfinder: &ClientKeyPathfinder) -> io::Result<Self> {
|
||||
let identity_keypair: identity::KeyPair =
|
||||
nym_pemstore::load_keypair(&nym_pemstore::KeyPairPath::new(
|
||||
client_pathfinder.private_identity_key().to_owned(),
|
||||
client_pathfinder.public_identity_key().to_owned(),
|
||||
))?;
|
||||
let encryption_keypair: encryption::KeyPair =
|
||||
nym_pemstore::load_keypair(&nym_pemstore::KeyPairPath::new(
|
||||
client_pathfinder.private_encryption_key().to_owned(),
|
||||
client_pathfinder.public_encryption_key().to_owned(),
|
||||
))?;
|
||||
|
||||
let ack_key: AckKey = nym_pemstore::load_key(client_pathfinder.ack_key())?;
|
||||
|
||||
Ok(KeyManager {
|
||||
identity_keypair: Arc::new(identity_keypair),
|
||||
encryption_keypair: Arc::new(encryption_keypair),
|
||||
gateway_shared_key: None,
|
||||
ack_key: Arc::new(ack_key),
|
||||
})
|
||||
}
|
||||
|
||||
/// Loads previously stored keys from the disk. Fails if not all, including the shared gateway
|
||||
/// key, is available.
|
||||
pub fn load_keys(client_pathfinder: &ClientKeyPathfinder) -> io::Result<Self> {
|
||||
let mut key_manager = Self::load_client_keys(client_pathfinder)?;
|
||||
|
||||
let gateway_shared_key: SharedKeys =
|
||||
nym_pemstore::load_key(client_pathfinder.gateway_shared_key())?;
|
||||
|
||||
key_manager.gateway_shared_key = Some(Arc::new(gateway_shared_key));
|
||||
|
||||
Ok(key_manager)
|
||||
}
|
||||
|
||||
/// Loads previously stored keys from the disk. Fails if client keys are not availabe, but the
|
||||
/// shared gateway key is optional.
|
||||
pub fn load_keys_but_gateway_is_optional(
|
||||
client_pathfinder: &ClientKeyPathfinder,
|
||||
) -> io::Result<Self> {
|
||||
let mut key_manager = Self::load_client_keys(client_pathfinder)?;
|
||||
|
||||
let gateway_shared_key: Result<SharedKeys, io::Error> =
|
||||
nym_pemstore::load_key(client_pathfinder.gateway_shared_key());
|
||||
|
||||
// It's ok if the gateway key was not found
|
||||
let gateway_shared_key = match gateway_shared_key {
|
||||
Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
|
||||
Err(err) => Err(err),
|
||||
Ok(key) => Ok(Some(key)),
|
||||
}?;
|
||||
|
||||
key_manager.gateway_shared_key = gateway_shared_key.map(Arc::new);
|
||||
|
||||
Ok(key_manager)
|
||||
}
|
||||
|
||||
/// Stores all available keys on the disk.
|
||||
// While perhaps there is no much point in storing the `AckKey` on the disk,
|
||||
// it is done so for the consistency sake so that you wouldn't require an rng instance
|
||||
// during `load_keys` to generate the said key.
|
||||
pub fn store_keys(&self, client_pathfinder: &ClientKeyPathfinder) -> io::Result<()> {
|
||||
nym_pemstore::store_keypair(
|
||||
self.identity_keypair.as_ref(),
|
||||
&nym_pemstore::KeyPairPath::new(
|
||||
client_pathfinder.private_identity_key().to_owned(),
|
||||
client_pathfinder.public_identity_key().to_owned(),
|
||||
),
|
||||
)?;
|
||||
nym_pemstore::store_keypair(
|
||||
self.encryption_keypair.as_ref(),
|
||||
&nym_pemstore::KeyPairPath::new(
|
||||
client_pathfinder.private_encryption_key().to_owned(),
|
||||
client_pathfinder.public_encryption_key().to_owned(),
|
||||
),
|
||||
)?;
|
||||
|
||||
nym_pemstore::store_key(self.ack_key.as_ref(), client_pathfinder.ack_key())?;
|
||||
|
||||
match self.gateway_shared_key.as_ref() {
|
||||
None => debug!("No gateway shared key available to store!"),
|
||||
Some(gate_key) => {
|
||||
nym_pemstore::store_key(gate_key.as_ref(), client_pathfinder.gateway_shared_key())?
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn store_gateway_key(&self, client_pathfinder: &ClientKeyPathfinder) -> io::Result<()> {
|
||||
match self.gateway_shared_key.as_ref() {
|
||||
None => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"trying to store a non-existing key",
|
||||
))
|
||||
}
|
||||
Some(gate_key) => {
|
||||
nym_pemstore::store_key(gate_key.as_ref(), client_pathfinder.gateway_shared_key())?
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Overwrite the existing identity keypair
|
||||
pub fn set_identity_keypair(&mut self, id_keypair: identity::KeyPair) {
|
||||
self.identity_keypair = Arc::new(id_keypair);
|
||||
}
|
||||
|
||||
/// Gets an atomically reference counted pointer to [`identity::KeyPair`].
|
||||
pub fn identity_keypair(&self) -> Arc<identity::KeyPair> {
|
||||
Arc::clone(&self.identity_keypair)
|
||||
}
|
||||
|
||||
/// Overwrite the existing encryption keypair
|
||||
pub fn set_encryption_keypair(&mut self, enc_keypair: encryption::KeyPair) {
|
||||
self.encryption_keypair = Arc::new(enc_keypair);
|
||||
}
|
||||
|
||||
/// Gets an atomically reference counted pointer to [`encryption::KeyPair`].
|
||||
pub fn encryption_keypair(&self) -> Arc<encryption::KeyPair> {
|
||||
Arc::clone(&self.encryption_keypair)
|
||||
}
|
||||
|
||||
/// Overwrite the existing ack key
|
||||
pub fn set_ack_key(&mut self, ack_key: AckKey) {
|
||||
self.ack_key = Arc::new(ack_key);
|
||||
}
|
||||
|
||||
/// Gets an atomically reference counted pointer to [`AckKey`].
|
||||
pub fn ack_key(&self) -> Arc<AckKey> {
|
||||
Arc::clone(&self.ack_key)
|
||||
}
|
||||
|
||||
/// After shared key with the gateway is derived, puts its ownership to this instance of a [`KeyManager`].
|
||||
pub fn insert_gateway_shared_key(&mut self, gateway_shared_key: Arc<SharedKeys>) {
|
||||
self.gateway_shared_key = Some(gateway_shared_key)
|
||||
}
|
||||
|
||||
/// Gets an atomically reference counted pointer to [`SharedKey`].
|
||||
// since this function is not fully public, it is not expected to be used externally and
|
||||
// hence it's up to us to ensure it's called in correct context
|
||||
pub fn gateway_shared_key(&self) -> Arc<SharedKeys> {
|
||||
Arc::clone(
|
||||
self.gateway_shared_key
|
||||
.as_ref()
|
||||
.expect("tried to unwrap empty gateway key!"),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_gateway_key_set(&self) -> bool {
|
||||
self.gateway_shared_key.is_some()
|
||||
}
|
||||
}
|
||||
@@ -1,336 +0,0 @@
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::spawn_future;
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::params::DEFAULT_NUM_MIX_HOPS;
|
||||
use nym_topology::{nym_topology_from_detailed, NymTopology, NymTopologyError};
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::{RwLock, RwLockReadGuard};
|
||||
use url::Url;
|
||||
|
||||
// I'm extremely curious why compiler NEVER complained about lack of Debug here before
|
||||
#[derive(Debug)]
|
||||
pub struct TopologyAccessorInner(Option<NymTopology>);
|
||||
|
||||
impl AsRef<Option<NymTopology>> for TopologyAccessorInner {
|
||||
fn as_ref(&self) -> &Option<NymTopology> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl TopologyAccessorInner {
|
||||
fn new() -> Self {
|
||||
TopologyAccessorInner(None)
|
||||
}
|
||||
|
||||
fn update(&mut self, new: Option<NymTopology>) {
|
||||
self.0 = new;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TopologyReadPermit<'a> {
|
||||
permit: RwLockReadGuard<'a, TopologyAccessorInner>,
|
||||
}
|
||||
|
||||
impl<'a> Deref for TopologyReadPermit<'a> {
|
||||
type Target = TopologyAccessorInner;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.permit
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TopologyReadPermit<'a> {
|
||||
/// Using provided topology read permit, tries to get an immutable reference to the underlying
|
||||
/// topology. For obvious reasons the lifetime of the topology reference is bound to the permit.
|
||||
pub(super) fn try_get_valid_topology_ref(
|
||||
&'a self,
|
||||
ack_recipient: &Recipient,
|
||||
packet_recipient: Option<&Recipient>,
|
||||
) -> Result<&'a NymTopology, NymTopologyError> {
|
||||
// 1. Have we managed to get anything from the refresher, i.e. have the nym-api queries gone through?
|
||||
let topology = self
|
||||
.permit
|
||||
.as_ref()
|
||||
.as_ref()
|
||||
.ok_or(NymTopologyError::EmptyNetworkTopology)?;
|
||||
|
||||
// 2. does it have any mixnode at all?
|
||||
// 3. does it have any gateways at all?
|
||||
// 4. does it have a mixnode on each layer?
|
||||
topology.ensure_can_construct_path_through(DEFAULT_NUM_MIX_HOPS)?;
|
||||
|
||||
// 5. does it contain OUR gateway (so that we could create an ack packet)?
|
||||
if !topology.gateway_exists(ack_recipient.gateway()) {
|
||||
return Err(NymTopologyError::NonExistentGatewayError {
|
||||
identity_key: ack_recipient.gateway().to_base58_string(),
|
||||
});
|
||||
}
|
||||
|
||||
// 6. for our target recipient, does it contain THEIR gateway (so that we could create
|
||||
if let Some(recipient) = packet_recipient {
|
||||
if !topology.gateway_exists(recipient.gateway()) {
|
||||
return Err(NymTopologyError::NonExistentGatewayError {
|
||||
identity_key: recipient.gateway().to_base58_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(topology)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<RwLockReadGuard<'a, TopologyAccessorInner>> for TopologyReadPermit<'a> {
|
||||
fn from(read_permit: RwLockReadGuard<'a, TopologyAccessorInner>) -> Self {
|
||||
TopologyReadPermit {
|
||||
permit: read_permit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TopologyAccessor {
|
||||
// `RwLock` *seems to* be the better approach for this as write access is only requested every
|
||||
// few seconds, while reads are needed every single packet generated.
|
||||
// However, proper benchmarks will be needed to determine if `RwLock` is indeed a better
|
||||
// approach than a `Mutex`
|
||||
inner: Arc<RwLock<TopologyAccessorInner>>,
|
||||
}
|
||||
|
||||
impl TopologyAccessor {
|
||||
pub fn new() -> Self {
|
||||
TopologyAccessor {
|
||||
inner: Arc::new(RwLock::new(TopologyAccessorInner::new())),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_read_permit(&self) -> TopologyReadPermit<'_> {
|
||||
self.inner.read().await.into()
|
||||
}
|
||||
|
||||
async fn update_global_topology(&self, new_topology: Option<NymTopology>) {
|
||||
self.inner.write().await.update(new_topology);
|
||||
}
|
||||
|
||||
// only used by the client at startup to get a slightly more reasonable error message
|
||||
// (currently displays as unused because health checker is disabled due to required changes)
|
||||
pub async fn ensure_is_routable(&self) -> Result<(), NymTopologyError> {
|
||||
match &self.inner.read().await.0 {
|
||||
None => Err(NymTopologyError::EmptyNetworkTopology),
|
||||
Some(ref topology) => topology.ensure_can_construct_path_through(DEFAULT_NUM_MIX_HOPS),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TopologyAccessor {
|
||||
fn default() -> Self {
|
||||
TopologyAccessor::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TopologyRefresherConfig {
|
||||
nym_api_urls: Vec<Url>,
|
||||
refresh_rate: Duration,
|
||||
client_version: String,
|
||||
}
|
||||
|
||||
impl TopologyRefresherConfig {
|
||||
pub fn new(nym_api_urls: Vec<Url>, refresh_rate: Duration, client_version: String) -> Self {
|
||||
TopologyRefresherConfig {
|
||||
nym_api_urls,
|
||||
refresh_rate,
|
||||
client_version,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TopologyRefresher {
|
||||
validator_client: validator_client::client::NymApiClient,
|
||||
client_version: String,
|
||||
|
||||
nym_api_urls: Vec<Url>,
|
||||
topology_accessor: TopologyAccessor,
|
||||
refresh_rate: Duration,
|
||||
|
||||
currently_used_api: usize,
|
||||
was_latest_valid: bool,
|
||||
}
|
||||
|
||||
impl TopologyRefresher {
|
||||
pub fn new(mut cfg: TopologyRefresherConfig, topology_accessor: TopologyAccessor) -> Self {
|
||||
cfg.nym_api_urls.shuffle(&mut thread_rng());
|
||||
|
||||
TopologyRefresher {
|
||||
validator_client: validator_client::client::NymApiClient::new(
|
||||
cfg.nym_api_urls[0].clone(),
|
||||
),
|
||||
client_version: cfg.client_version,
|
||||
nym_api_urls: cfg.nym_api_urls,
|
||||
topology_accessor,
|
||||
refresh_rate: cfg.refresh_rate,
|
||||
currently_used_api: 0,
|
||||
was_latest_valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
fn use_next_nym_api(&mut self) {
|
||||
if self.nym_api_urls.len() == 1 {
|
||||
warn!("There's only a single nym API available - it won't be possible to use a different one");
|
||||
return;
|
||||
}
|
||||
|
||||
self.currently_used_api = (self.currently_used_api + 1) % self.nym_api_urls.len();
|
||||
self.validator_client
|
||||
.change_nym_api(self.nym_api_urls[self.currently_used_api].clone())
|
||||
}
|
||||
|
||||
/// Verifies whether nodes a reasonably distributed among all mix layers.
|
||||
///
|
||||
/// In ideal world we would have 33% nodes on layer 1, 33% on layer 2 and 33% on layer 3.
|
||||
/// However, this is a rather unrealistic expectation, instead we check whether there exists
|
||||
/// a layer with more than 66% of nodes or with fewer than 15% and if so, we trigger a failure.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `topology`: active topology constructed from validator api data
|
||||
fn check_layer_distribution(&self, active_topology: &NymTopology) -> bool {
|
||||
let mixes = active_topology.mixes();
|
||||
let mixnodes_count = active_topology.num_mixnodes();
|
||||
|
||||
if active_topology.gateways().is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// trivial check to see if have at least a single node on each layer (regardless of active set size)
|
||||
if mixes.get(&1).is_none() || mixes.get(&2).is_none() || mixes.get(&3).is_none() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let upper_bound = (mixnodes_count as f32 * 0.66) as usize;
|
||||
let lower_bound = (mixnodes_count as f32 * 0.15) as usize;
|
||||
|
||||
let layer1 = mixes.get(&1).unwrap().len();
|
||||
let layer2 = mixes.get(&2).unwrap().len();
|
||||
let layer3 = mixes.get(&3).unwrap().len();
|
||||
|
||||
if layer1 < lower_bound || layer1 > upper_bound {
|
||||
warn!(
|
||||
"nodes: {}, layer1: {}, layer2: {}, layer3: {}",
|
||||
mixnodes_count, layer1, layer2, layer3
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if layer2 < lower_bound || layer2 > upper_bound {
|
||||
warn!(
|
||||
"nodes: {}, layer1: {}, layer2: {}, layer3: {}",
|
||||
mixnodes_count, layer1, layer2, layer3
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if layer3 < lower_bound || layer3 > upper_bound {
|
||||
warn!(
|
||||
"nodes: {}, layer1: {}, layer2: {}, layer3: {}",
|
||||
mixnodes_count, layer1, layer2, layer3
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
async fn get_current_compatible_topology(&self) -> Option<NymTopology> {
|
||||
// TODO: optimization for the future:
|
||||
// only refresh mixnodes on timer and refresh gateways only when
|
||||
// we have to send to a new, unknown, gateway
|
||||
|
||||
let mixnodes = match self.validator_client.get_cached_active_mixnodes().await {
|
||||
Err(err) => {
|
||||
error!("failed to get network mixnodes - {err}");
|
||||
return None;
|
||||
}
|
||||
Ok(mixes) => mixes,
|
||||
};
|
||||
|
||||
let gateways = match self.validator_client.get_cached_gateways().await {
|
||||
Err(err) => {
|
||||
error!("failed to get network gateways - {err}");
|
||||
return None;
|
||||
}
|
||||
Ok(gateways) => gateways,
|
||||
};
|
||||
|
||||
let topology = nym_topology_from_detailed(mixnodes, gateways)
|
||||
.filter_system_version(&self.client_version);
|
||||
|
||||
if !self.check_layer_distribution(&topology) {
|
||||
warn!("The current filtered active topology has extremely skewed layer distribution. It cannot be used.");
|
||||
None
|
||||
} else {
|
||||
Some(topology)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn refresh(&mut self) {
|
||||
trace!("Refreshing the topology");
|
||||
let new_topology = self.get_current_compatible_topology().await;
|
||||
|
||||
if new_topology.is_none() {
|
||||
self.use_next_nym_api();
|
||||
}
|
||||
|
||||
if new_topology.is_none() && self.was_latest_valid {
|
||||
// if we failed to grab this topology, but the one before it was alright, let's assume
|
||||
// validator had a tiny hiccup and use the old data
|
||||
warn!("we're going to keep on using the old topology for this iteration");
|
||||
self.was_latest_valid = false;
|
||||
return;
|
||||
} else if new_topology.is_some() {
|
||||
self.was_latest_valid = true;
|
||||
}
|
||||
|
||||
self.topology_accessor
|
||||
.update_global_topology(new_topology)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn ensure_topology_is_routable(&self) -> Result<(), NymTopologyError> {
|
||||
self.topology_accessor.ensure_is_routable().await
|
||||
}
|
||||
|
||||
pub fn start_with_shutdown(mut self, mut shutdown: nym_task::TaskClient) {
|
||||
spawn_future(async move {
|
||||
debug!("Started TopologyRefresher with graceful shutdown support");
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let mut interval = tokio_stream::wrappers::IntervalStream::new(tokio::time::interval(
|
||||
self.refresh_rate,
|
||||
));
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let mut interval =
|
||||
gloo_timers::future::IntervalStream::new(self.refresh_rate.as_millis() as u32);
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
_ = interval.next() => {
|
||||
self.refresh().await;
|
||||
},
|
||||
_ = shutdown.recv() => {
|
||||
log::trace!("TopologyRefresher: Received shutdown");
|
||||
},
|
||||
}
|
||||
}
|
||||
shutdown.recv_timeout().await;
|
||||
log::debug!("TopologyRefresher: Exiting");
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{
|
||||
client::key_manager::KeyManager,
|
||||
config::{persistence::key_pathfinder::ClientKeyPathfinder, Config},
|
||||
error::ClientCoreError,
|
||||
};
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use gateway_client::wasm_mockups::SigningNyxdClient;
|
||||
use gateway_client::GatewayClient;
|
||||
use gateway_requests::registration::handshake::SharedKeys;
|
||||
use nym_config::NymConfig;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_topology::{filter::VersionFilterable, gateway};
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use tap::TapFallible;
|
||||
use url::Url;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use validator_client::nyxd::SigningNyxdClient;
|
||||
|
||||
pub(super) async fn query_gateway_details(
|
||||
validator_servers: Vec<Url>,
|
||||
chosen_gateway_id: Option<identity::PublicKey>,
|
||||
) -> Result<gateway::Node, ClientCoreError> {
|
||||
let nym_api = validator_servers
|
||||
.choose(&mut thread_rng())
|
||||
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
|
||||
let validator_client = validator_client::client::NymApiClient::new(nym_api.clone());
|
||||
|
||||
log::trace!("Fetching list of gateways from: {}", nym_api);
|
||||
let gateways = validator_client.get_cached_gateways().await?;
|
||||
let valid_gateways = gateways
|
||||
.into_iter()
|
||||
.filter_map(|gateway| gateway.try_into().ok())
|
||||
.collect::<Vec<gateway::Node>>();
|
||||
|
||||
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
|
||||
|
||||
// if we have chosen particular gateway - use it, otherwise choose a random one.
|
||||
// (remember that in active topology all gateways have at least 100 reputation so should
|
||||
// be working correctly)
|
||||
if let Some(gateway_id) = chosen_gateway_id {
|
||||
filtered_gateways
|
||||
.iter()
|
||||
.find(|gateway| gateway.identity_key == gateway_id)
|
||||
.ok_or_else(|| ClientCoreError::NoGatewayWithId(gateway_id.to_string()))
|
||||
.cloned()
|
||||
} else {
|
||||
filtered_gateways
|
||||
.choose(&mut rand::thread_rng())
|
||||
.ok_or(ClientCoreError::NoGatewaysOnNetwork)
|
||||
.cloned()
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) async fn register_with_gateway(
|
||||
gateway: &gateway::Node,
|
||||
our_identity: Arc<identity::KeyPair>,
|
||||
) -> Result<Arc<SharedKeys>, ClientCoreError> {
|
||||
let timeout = Duration::from_millis(1500);
|
||||
let mut gateway_client: GatewayClient<SigningNyxdClient> = GatewayClient::new_init(
|
||||
gateway.clients_address(),
|
||||
gateway.identity_key,
|
||||
our_identity.clone(),
|
||||
timeout,
|
||||
);
|
||||
gateway_client
|
||||
.establish_connection()
|
||||
.await
|
||||
.tap_err(|_| log::warn!("Failed to establish connection with gateway!"))?;
|
||||
let shared_keys = gateway_client
|
||||
.perform_initial_authentication()
|
||||
.await
|
||||
.tap_err(|_| log::warn!("Failed to register with the gateway!"))?;
|
||||
Ok(shared_keys)
|
||||
}
|
||||
|
||||
pub(super) fn store_keys<T>(
|
||||
key_manager: &KeyManager,
|
||||
config: &Config<T>,
|
||||
) -> Result<(), ClientCoreError>
|
||||
where
|
||||
T: NymConfig,
|
||||
{
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config);
|
||||
Ok(key_manager
|
||||
.store_keys(&pathfinder)
|
||||
.tap_err(|err| log::error!("Failed to generate keys: {err}"))?)
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//! Collection of initialization steps used by client implementations
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
use nym_sphinx::addressing::{clients::Recipient, nodes::NodeIdentity};
|
||||
use rand::rngs::OsRng;
|
||||
use serde::Serialize;
|
||||
use tap::TapFallible;
|
||||
|
||||
use nym_config::NymConfig;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use url::Url;
|
||||
|
||||
use crate::client::key_manager::KeyManager;
|
||||
use crate::{
|
||||
config::{
|
||||
persistence::key_pathfinder::ClientKeyPathfinder, ClientCoreConfigTrait, Config,
|
||||
GatewayEndpointConfig,
|
||||
},
|
||||
error::ClientCoreError,
|
||||
};
|
||||
|
||||
mod helpers;
|
||||
|
||||
/// Struct describing the results of the client initialization procedure.
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct InitResults {
|
||||
version: String,
|
||||
id: String,
|
||||
identity_key: String,
|
||||
encryption_key: String,
|
||||
gateway_id: String,
|
||||
gateway_listener: String,
|
||||
}
|
||||
|
||||
impl InitResults {
|
||||
pub fn new<T>(config: &Config<T>, address: &Recipient) -> Self
|
||||
where
|
||||
T: NymConfig,
|
||||
{
|
||||
Self {
|
||||
version: config.get_version().to_string(),
|
||||
id: config.get_id(),
|
||||
identity_key: address.identity().to_base58_string(),
|
||||
encryption_key: address.encryption_key().to_base58_string(),
|
||||
gateway_id: config.get_gateway_id(),
|
||||
gateway_listener: config.get_gateway_listener(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for InitResults {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
writeln!(f, "Version: {}", self.version)?;
|
||||
writeln!(f, "ID: {}", self.id)?;
|
||||
writeln!(f, "Identity key: {}", self.identity_key)?;
|
||||
writeln!(f, "Encryption: {}", self.encryption_key)?;
|
||||
writeln!(f, "Gateway ID: {}", self.gateway_id)?;
|
||||
write!(f, "Gateway: {}", self.gateway_listener)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new set of client keys.
|
||||
pub fn new_client_keys() -> KeyManager {
|
||||
let mut rng = OsRng;
|
||||
KeyManager::new(&mut rng)
|
||||
}
|
||||
|
||||
/// Authenticate and register with a gateway.
|
||||
/// Either pick one at random by querying the available gateways from the nym-api, or use the
|
||||
/// chosen one if it's among the available ones.
|
||||
/// The shared key is added to the supplied `KeyManager` and the endpoint details are returned.
|
||||
pub async fn register_with_gateway(
|
||||
key_manager: &mut KeyManager,
|
||||
nym_api_endpoints: Vec<Url>,
|
||||
chosen_gateway_id: Option<identity::PublicKey>,
|
||||
) -> Result<GatewayEndpointConfig, ClientCoreError> {
|
||||
// Get the gateway details of the gateway we will use
|
||||
let gateway = helpers::query_gateway_details(nym_api_endpoints, chosen_gateway_id).await?;
|
||||
log::debug!("Querying gateway gives: {}", gateway);
|
||||
|
||||
let our_identity = key_manager.identity_keypair();
|
||||
|
||||
// Establish connection, authenticate and generate keys for talking with the gateway
|
||||
let shared_keys = helpers::register_with_gateway(&gateway, our_identity).await?;
|
||||
key_manager.insert_gateway_shared_key(shared_keys);
|
||||
|
||||
Ok(gateway.into())
|
||||
}
|
||||
|
||||
/// Convenience function for setting up the gateway for a client given a `Config`. Depending on the
|
||||
/// arguments given it will do the sensible thing. Either it will
|
||||
///
|
||||
/// a. Reuse existing gateway configuration from storage.
|
||||
/// b. Create a new gateway configuration but keep existing keys. This assumes that the caller
|
||||
/// knows what they are doing and that the keys match the requested gateway.
|
||||
/// c. Create a new gateway configuration with a newly registered gateway and keys.
|
||||
pub async fn setup_gateway_from_config<C, T>(
|
||||
register_gateway: bool,
|
||||
user_chosen_gateway_id: Option<identity::PublicKey>,
|
||||
config: &Config<T>,
|
||||
) -> Result<GatewayEndpointConfig, ClientCoreError>
|
||||
where
|
||||
C: NymConfig + ClientCoreConfigTrait,
|
||||
T: NymConfig,
|
||||
{
|
||||
let id = config.get_id();
|
||||
|
||||
// If we are not going to register gateway, and an explicitly chosed gateway is not passed in,
|
||||
// load the existing configuration file
|
||||
if !register_gateway && user_chosen_gateway_id.is_none() {
|
||||
println!("Not registering gateway, will reuse existing config and keys");
|
||||
return load_existing_gateway_config::<C>(&id);
|
||||
}
|
||||
|
||||
// Else, we preceed by querying the nym-api
|
||||
let gateway =
|
||||
helpers::query_gateway_details(config.get_nym_api_endpoints(), user_chosen_gateway_id)
|
||||
.await?;
|
||||
log::debug!("Querying gateway gives: {}", gateway);
|
||||
|
||||
// If we are not registering, just return this and assume the caller has the keys already and
|
||||
// wants to keep the,
|
||||
if !register_gateway && user_chosen_gateway_id.is_some() {
|
||||
println!("Using gateway provided by user, keeping existing keys");
|
||||
return Ok(gateway.into());
|
||||
}
|
||||
|
||||
// Create new keys and derive our identity
|
||||
let mut key_manager = new_client_keys();
|
||||
let our_identity = key_manager.identity_keypair();
|
||||
|
||||
// Establish connection, authenticate and generate keys for talking with the gateway
|
||||
println!("Registering with new gateway");
|
||||
let shared_keys = helpers::register_with_gateway(&gateway, our_identity).await?;
|
||||
key_manager.insert_gateway_shared_key(shared_keys);
|
||||
|
||||
// Write all keys to storage and just return the gateway endpoint config. It is assumed that we
|
||||
// will load keys from storage when actually connecting.
|
||||
helpers::store_keys(&key_manager, config)?;
|
||||
Ok(gateway.into())
|
||||
}
|
||||
|
||||
/// Read and reuse the existing gateway configuration from a file that was generate earlier.
|
||||
pub fn load_existing_gateway_config<T>(id: &str) -> Result<GatewayEndpointConfig, ClientCoreError>
|
||||
where
|
||||
T: NymConfig + ClientCoreConfigTrait,
|
||||
{
|
||||
T::load_from_file(id)
|
||||
.map(|existing_config| existing_config.get_gateway_endpoint().clone())
|
||||
.map_err(|err| {
|
||||
log::error!(
|
||||
"Unable to configure gateway: {err}. \n
|
||||
Seems like the client was already initialized but it was not possible to read \
|
||||
the existing configuration file. \n
|
||||
CAUTION: Consider backing up your gateway keys and try force gateway registration, or \
|
||||
removing the existing configuration and starting over."
|
||||
);
|
||||
ClientCoreError::CouldNotLoadExistingGatewayConfiguration(err)
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the full client address from the client keys and the gateway identity
|
||||
pub fn get_client_address(
|
||||
key_manager: &KeyManager,
|
||||
gateway_config: &GatewayEndpointConfig,
|
||||
) -> Recipient {
|
||||
Recipient::new(
|
||||
*key_manager.identity_keypair().public_key(),
|
||||
*key_manager.encryption_keypair().public_key(),
|
||||
// TODO: below only works under assumption that gateway address == gateway id
|
||||
// (which currently is true)
|
||||
NodeIdentity::from_base58_string(&gateway_config.gateway_id).unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Get the client address by loading the keys from stored files.
|
||||
pub fn get_client_address_from_stored_keys<T>(
|
||||
config: &Config<T>,
|
||||
) -> Result<Recipient, ClientCoreError>
|
||||
where
|
||||
T: nym_config::NymConfig,
|
||||
{
|
||||
fn load_identity_keys(
|
||||
pathfinder: &ClientKeyPathfinder,
|
||||
) -> Result<identity::KeyPair, ClientCoreError> {
|
||||
let identity_keypair: identity::KeyPair =
|
||||
nym_pemstore::load_keypair(&nym_pemstore::KeyPairPath::new(
|
||||
pathfinder.private_identity_key().to_owned(),
|
||||
pathfinder.public_identity_key().to_owned(),
|
||||
))
|
||||
.tap_err(|_| log::error!("Failed to read stored identity key files"))?;
|
||||
Ok(identity_keypair)
|
||||
}
|
||||
|
||||
fn load_sphinx_keys(
|
||||
pathfinder: &ClientKeyPathfinder,
|
||||
) -> Result<encryption::KeyPair, ClientCoreError> {
|
||||
let sphinx_keypair: encryption::KeyPair =
|
||||
nym_pemstore::load_keypair(&nym_pemstore::KeyPairPath::new(
|
||||
pathfinder.private_encryption_key().to_owned(),
|
||||
pathfinder.public_encryption_key().to_owned(),
|
||||
))
|
||||
.tap_err(|_| log::error!("Failed to read stored sphinx key files"))?;
|
||||
Ok(sphinx_keypair)
|
||||
}
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config);
|
||||
let identity_keypair = load_identity_keys(&pathfinder)?;
|
||||
let sphinx_keypair = load_sphinx_keys(&pathfinder)?;
|
||||
|
||||
let client_recipient = Recipient::new(
|
||||
*identity_keypair.public_key(),
|
||||
*sphinx_keypair.public_key(),
|
||||
// TODO: below only works under assumption that gateway address == gateway id
|
||||
// (which currently is true)
|
||||
NodeIdentity::from_base58_string(config.get_gateway_id())?,
|
||||
);
|
||||
|
||||
Ok(client_recipient)
|
||||
}
|
||||
|
||||
pub fn output_to_json<T: Serialize>(init_results: &T, output_file: &str) {
|
||||
match std::fs::File::create(output_file) {
|
||||
Ok(file) => match serde_json::to_writer_pretty(file, init_results) {
|
||||
Ok(_) => println!("Saved: {output_file}"),
|
||||
Err(err) => eprintln!("Could not save {output_file}: {err}"),
|
||||
},
|
||||
Err(err) => eprintln!("Could not save {output_file}: {err}"),
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,23 @@
|
||||
[package]
|
||||
name = "credential"
|
||||
name = "nym-credential-client"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bip39 = "1.0.1"
|
||||
clap = { version = "4.0", features = ["cargo", "derive"] }
|
||||
log = "0.4"
|
||||
rand = "0.7.3"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
thiserror = "1.0"
|
||||
url = "2.2"
|
||||
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal", "macros"] } # async runtime
|
||||
|
||||
coconut-interface = { path = "../../common/coconut-interface" }
|
||||
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
|
||||
nym-config = { path = "../../common/config" }
|
||||
credentials = { path = "../../common/credentials" }
|
||||
credential-storage = { path = "../../common/credential-storage" }
|
||||
nym-crypto = { path = "../../common/crypto", features = ["rand", "asymmetric", "symmetric", "aes", "hashing"] }
|
||||
nym-credentials = { path = "../../common/credentials" }
|
||||
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||
nym-bin-common = { path = "../../common/bin-common"}
|
||||
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||
nym-pemstore = { path = "../../common/pemstore" }
|
||||
validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
|
||||
nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<!--
|
||||
Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
## Credential binary
|
||||
|
||||
The credential binary is used to acquire coconut bandwidth credentials in exchange for nym tokens. Those credentials are stored in the client's `data` directory, so that they can be used as the client sees fit.
|
||||
|
||||
### Warning
|
||||
|
||||
The credential binary is still experimental software. The infrastructure for using it is not yet deployed to mainnet and it's still in the process of being deployed to sandbox.
|
||||
|
||||
### Building
|
||||
|
||||
From the project's root directory, run:
|
||||
```
|
||||
cargo build -p credential
|
||||
```
|
||||
which generates the `credential` binary in `target/debug/credential`.
|
||||
|
||||
|
||||
### Running
|
||||
|
||||
For example, you can get a credential worth 3 nym (3000000 unym) in a socks5 client that was already initialized like so:
|
||||
|
||||
```
|
||||
./target/debug/credential --config-env-file envs/sandbox.env --client-home-directory ~/.nym/socks5-clients/cred_client --nyxd-url https://sandbox-validator1.nymtech.net --mnemonic $MNEMONIC --recovery-dir /tmp/recovery --amount 3000000
|
||||
```
|
||||
|
||||
More information regarding how to run the binary can be found by running it with the `--help` argument.
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
use crate::error::Result;
|
||||
use bip39::Mnemonic;
|
||||
use nym_network_defaults::{NymNetworkDetails, VOUCHER_INFO};
|
||||
use nym_validator_client::nyxd;
|
||||
use nym_validator_client::nyxd::traits::CoconutBandwidthSigningClient;
|
||||
use nym_validator_client::nyxd::{Coin, DirectSigningNyxdClient, Fee, NyxdClient};
|
||||
use std::str::FromStr;
|
||||
use url::Url;
|
||||
use validator_client::nyxd;
|
||||
use validator_client::nyxd::traits::CoconutBandwidthSigningClient;
|
||||
use validator_client::nyxd::{Coin, Fee, NyxdClient, SigningNyxdClient};
|
||||
|
||||
pub(crate) struct Client {
|
||||
nyxd_client: NyxdClient<SigningNyxdClient>,
|
||||
nyxd_client: NyxdClient<DirectSigningNyxdClient>,
|
||||
mix_denom_base: String,
|
||||
}
|
||||
|
||||
|
||||
@@ -3,26 +3,13 @@
|
||||
|
||||
use clap::{ArgGroup, Args, Subcommand};
|
||||
use log::*;
|
||||
use nym_bandwidth_controller::acquire::state::State;
|
||||
use nym_bin_common::completions::ArgShell;
|
||||
use rand::rngs::OsRng;
|
||||
use std::str::FromStr;
|
||||
use nym_credential_storage::persistent_storage::PersistentStorage;
|
||||
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
||||
|
||||
use coconut_interface::{Base58, Parameters};
|
||||
use credential_storage::storage::Storage;
|
||||
use credential_storage::PersistentStorage;
|
||||
use credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES};
|
||||
use credentials::coconut::utils::obtain_aggregate_signature;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_network_defaults::VOUCHER_INFO;
|
||||
use validator_client::nyxd::traits::DkgQueryClient;
|
||||
use validator_client::nyxd::tx::Hash;
|
||||
use validator_client::nyxd::CosmWasmClient;
|
||||
use validator_client::CoconutApiClient;
|
||||
|
||||
use crate::client::Client;
|
||||
use crate::error::{CredentialClientError, Result};
|
||||
use crate::error::Result;
|
||||
use crate::recovery_storage::RecoveryStorage;
|
||||
use crate::state::{KeyPair, State};
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub(crate) enum Command {
|
||||
@@ -47,10 +34,6 @@ pub(crate) struct Run {
|
||||
#[clap(long)]
|
||||
pub(crate) client_home_directory: std::path::PathBuf,
|
||||
|
||||
/// The nyxd URL that should be used
|
||||
#[clap(long)]
|
||||
pub(crate) nyxd_url: String,
|
||||
|
||||
/// A mnemonic for the account that buys the credential
|
||||
#[clap(long)]
|
||||
pub(crate) mnemonic: String,
|
||||
@@ -69,82 +52,16 @@ pub(crate) struct Run {
|
||||
pub(crate) recovery_mode: bool,
|
||||
}
|
||||
|
||||
pub(crate) async fn deposit(nyxd_url: &str, mnemonic: &str, amount: u64) -> Result<State> {
|
||||
let mut rng = OsRng;
|
||||
let signing_keypair = KeyPair::from(identity::KeyPair::new(&mut rng));
|
||||
let encryption_keypair = KeyPair::from(encryption::KeyPair::new(&mut rng));
|
||||
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
|
||||
|
||||
let client = Client::new(nyxd_url, mnemonic);
|
||||
let tx_hash = client
|
||||
.deposit(
|
||||
amount,
|
||||
signing_keypair.public_key.clone(),
|
||||
encryption_keypair.public_key.clone(),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let voucher = BandwidthVoucher::new(
|
||||
¶ms,
|
||||
amount.to_string(),
|
||||
VOUCHER_INFO.to_string(),
|
||||
Hash::from_str(&tx_hash).map_err(|_| CredentialClientError::InvalidTxHash)?,
|
||||
identity::PrivateKey::from_base58_string(&signing_keypair.private_key)?,
|
||||
encryption::PrivateKey::from_base58_string(&encryption_keypair.private_key)?,
|
||||
);
|
||||
|
||||
let state = State { voucher, params };
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_credential<C: Clone + CosmWasmClient + Send + Sync>(
|
||||
state: &State,
|
||||
client: validator_client::Client<C>,
|
||||
shared_storage: PersistentStorage,
|
||||
) -> Result<()> {
|
||||
let epoch_id = client.nyxd.get_current_epoch().await?.epoch_id;
|
||||
let threshold = client
|
||||
.nyxd
|
||||
.get_current_epoch_threshold()
|
||||
.await?
|
||||
.ok_or(CredentialClientError::NoThreshold)?;
|
||||
let coconut_api_clients = CoconutApiClient::all_coconut_api_clients(&client, epoch_id).await?;
|
||||
|
||||
let signature = obtain_aggregate_signature(
|
||||
&state.params,
|
||||
&state.voucher,
|
||||
&coconut_api_clients,
|
||||
threshold,
|
||||
)
|
||||
.await?;
|
||||
info!("Signature: {:?}", signature.to_bs58());
|
||||
shared_storage
|
||||
.insert_coconut_credential(
|
||||
state.voucher.get_voucher_value(),
|
||||
VOUCHER_INFO.to_string(),
|
||||
state.voucher.get_private_attributes()[0].to_bs58(),
|
||||
state.voucher.get_private_attributes()[1].to_bs58(),
|
||||
signature.to_bs58(),
|
||||
epoch_id.to_string(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn recover_credentials<C: Clone + CosmWasmClient + Send + Sync>(
|
||||
client: validator_client::Client<C>,
|
||||
pub(crate) async fn recover_credentials<C: DkgQueryClient + Send + Sync>(
|
||||
client: &C,
|
||||
recovery_storage: &RecoveryStorage,
|
||||
shared_storage: PersistentStorage,
|
||||
shared_storage: &PersistentStorage,
|
||||
) -> Result<()> {
|
||||
for voucher in recovery_storage.unconsumed_vouchers()? {
|
||||
let state = State {
|
||||
voucher,
|
||||
params: Parameters::new(TOTAL_ATTRIBUTES).unwrap(),
|
||||
};
|
||||
if let Err(e) = get_credential(&state, client.clone(), shared_storage.clone()).await {
|
||||
let state = State::new(voucher);
|
||||
if let Err(e) =
|
||||
nym_bandwidth_controller::acquire::get_credential(&state, client, shared_storage).await
|
||||
{
|
||||
error!(
|
||||
"Could not recover deposit {} due to {:?}, try again later",
|
||||
state.voucher.tx_hash(),
|
||||
|
||||
@@ -4,12 +4,10 @@
|
||||
use std::time::SystemTimeError;
|
||||
use thiserror::Error;
|
||||
|
||||
use credential_storage::error::StorageError;
|
||||
use credentials::error::Error as CredentialError;
|
||||
use nym_crypto::asymmetric::encryption::KeyRecoveryError;
|
||||
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
|
||||
use validator_client::nyxd::error::NyxdError;
|
||||
use validator_client::ValidatorClientError;
|
||||
use nym_credential_storage::error::StorageError;
|
||||
use nym_credentials::error::Error as CredentialError;
|
||||
use nym_validator_client::nyxd::error::NyxdError;
|
||||
use nym_validator_client::ValidatorClientError;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, CredentialClientError>;
|
||||
|
||||
@@ -18,6 +16,9 @@ pub enum CredentialClientError {
|
||||
#[error("IO error: {0}")]
|
||||
IOError(#[from] std::io::Error),
|
||||
|
||||
#[error("Bandwidth controller error: {0}")]
|
||||
BandwidthControllerError(#[from] nym_bandwidth_controller::error::BandwidthControllerError),
|
||||
|
||||
#[error("Nyxd error: {0}")]
|
||||
Nyxd(#[from] NyxdError),
|
||||
|
||||
@@ -27,21 +28,9 @@ pub enum CredentialClientError {
|
||||
#[error("Credential error: {0}")]
|
||||
Credential(#[from] CredentialError),
|
||||
|
||||
#[error("The tx hash provided is not valid")]
|
||||
InvalidTxHash,
|
||||
|
||||
#[error("Could not parse Ed25519 data")]
|
||||
Ed25519ParseError(#[from] Ed25519RecoveryError),
|
||||
|
||||
#[error("Could not parse X25519 data")]
|
||||
X25519ParseError(#[from] KeyRecoveryError),
|
||||
|
||||
#[error("Could not use shared storage")]
|
||||
SharedStorageError(#[from] StorageError),
|
||||
|
||||
#[error("Could not get system time")]
|
||||
SysTimeError(#[from] SystemTimeError),
|
||||
|
||||
#[error("Threshold not set yet")]
|
||||
NoThreshold,
|
||||
}
|
||||
|
||||
@@ -1,26 +1,24 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
mod client;
|
||||
mod commands;
|
||||
mod error;
|
||||
mod recovery_storage;
|
||||
mod state;
|
||||
|
||||
use commands::*;
|
||||
use error::Result;
|
||||
use log::*;
|
||||
use nym_bin_common::completions::fig_generate;
|
||||
use nym_config::{DATA_DIR, DB_FILE_NAME};
|
||||
use nym_config::{CRED_DB_FILE_NAME, DATA_DIR};
|
||||
use nym_network_defaults::{setup_env, NymNetworkDetails};
|
||||
use std::process::exit;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
use clap::{CommandFactory, Parser};
|
||||
use nym_bin_common::logging::setup_logging;
|
||||
use validator_client::nyxd::traits::DkgQueryClient;
|
||||
use validator_client::nyxd::CosmWasmClient;
|
||||
use validator_client::Config;
|
||||
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
||||
use nym_validator_client::nyxd::{Coin, CosmWasmClient};
|
||||
use nym_validator_client::Config;
|
||||
|
||||
const SAFETY_BUFFER_SECS: u64 = 60; // 1 minute
|
||||
|
||||
@@ -35,8 +33,8 @@ struct Cli {
|
||||
pub(crate) command: Command,
|
||||
}
|
||||
|
||||
async fn block_until_coconut_is_available<C: Clone + CosmWasmClient + Send + Sync>(
|
||||
client: &validator_client::Client<C>,
|
||||
async fn block_until_coconut_is_available<C: CosmWasmClient + Send + Sync>(
|
||||
client: &nym_validator_client::Client<C>,
|
||||
) -> Result<()> {
|
||||
loop {
|
||||
let epoch = client.nyxd.get_current_epoch().await?;
|
||||
@@ -51,8 +49,11 @@ async fn block_until_coconut_is_available<C: Clone + CosmWasmClient + Send + Syn
|
||||
|
||||
break;
|
||||
} else {
|
||||
// Use 20 additional seconds to avoid the exact moment of going into the final epoch state
|
||||
let secs_until_final = epoch.final_timestamp_secs() + 20 - current_timestamp_secs;
|
||||
// Use 1 additional second to not start the next iteration immediately and spam get_current_epoch queries
|
||||
let secs_until_final = epoch
|
||||
.final_timestamp_secs()
|
||||
.saturating_sub(current_timestamp_secs)
|
||||
+ 1;
|
||||
info!("Approximately {} seconds until coconut is available. Sleeping until then. You can safely kill the process at any moment.", secs_until_final);
|
||||
std::thread::sleep(Duration::from_secs(secs_until_final));
|
||||
}
|
||||
@@ -70,22 +71,38 @@ async fn main() -> Result<()> {
|
||||
|
||||
match args.command {
|
||||
Command::Run(r) => {
|
||||
let db_path = r.client_home_directory.join(DATA_DIR).join(DB_FILE_NAME);
|
||||
let shared_storage = credential_storage::initialise_storage(db_path).await;
|
||||
let db_path = r
|
||||
.client_home_directory
|
||||
.join(DATA_DIR)
|
||||
.join(CRED_DB_FILE_NAME);
|
||||
let shared_storage =
|
||||
nym_credential_storage::initialise_persistent_storage(db_path).await;
|
||||
let recovery_storage = recovery_storage::RecoveryStorage::new(r.recovery_dir)?;
|
||||
|
||||
let network_details = NymNetworkDetails::new_from_env();
|
||||
let config = Config::try_from_nym_network_details(&network_details)?;
|
||||
let client = validator_client::Client::new_query(config)?;
|
||||
let config = Config::try_from_nym_network_details(&network_details).expect(
|
||||
"failed to construct valid validator client config with the provided network",
|
||||
);
|
||||
let amount = Coin::new(
|
||||
r.amount as u128,
|
||||
network_details.chain_details.mix_denom.base,
|
||||
);
|
||||
let client =
|
||||
nym_validator_client::Client::new_signing(config, r.mnemonic.parse().unwrap())?;
|
||||
|
||||
block_until_coconut_is_available(&client).await?;
|
||||
info!("Starting depositing funds, don't kill the process");
|
||||
|
||||
if !r.recovery_mode {
|
||||
let state = deposit(&r.nyxd_url, &r.mnemonic, r.amount).await?;
|
||||
if get_credential(&state, client, shared_storage)
|
||||
.await
|
||||
.is_err()
|
||||
let state =
|
||||
nym_bandwidth_controller::acquire::deposit(&client.nyxd, amount).await?;
|
||||
if nym_bandwidth_controller::acquire::get_credential(
|
||||
&state,
|
||||
&client,
|
||||
&shared_storage,
|
||||
)
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
warn!("Failed to obtain credential. Dumping recovery data.",);
|
||||
match recovery_storage.insert_voucher(&state.voucher) {
|
||||
@@ -98,11 +115,11 @@ async fn main() -> Result<()> {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
recover_credentials(client, &recovery_storage, shared_storage).await?;
|
||||
recover_credentials(&client.nyxd, &recovery_storage, &shared_storage).await?;
|
||||
}
|
||||
}
|
||||
Command::Completions(c) => c.generate(&mut crate::Cli::command(), bin_name),
|
||||
Command::GenerateFigSpec => fig_generate(&mut crate::Cli::command(), bin_name),
|
||||
Command::Completions(c) => c.generate(&mut Cli::command(), bin_name),
|
||||
Command::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use credentials::coconut::bandwidth::BandwidthVoucher;
|
||||
use nym_credentials::coconut::bandwidth::BandwidthVoucher;
|
||||
use std::fs::{create_dir_all, read_dir, File};
|
||||
use std::io::{Read, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
+12
-13
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.10"
|
||||
version = "1.1.19"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
@@ -26,30 +26,29 @@ lazy_static = "1.4.0"
|
||||
log = { workspace = true } # self explanatory
|
||||
pretty_env_logger = "0.4" # for formatting log messages
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] } # rng-related traits + some rng implementation to use
|
||||
serde = { version = "1.0.104", features = ["derive"] } # for config serialization/deserialization
|
||||
serde_json = "1.0"
|
||||
serde = { workspace = true, features = ["derive"] } # for config serialization/deserialization
|
||||
serde_json = { workspace = true }
|
||||
thiserror = "1.0.34"
|
||||
tap = "1.0.1"
|
||||
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal"] } # async runtime
|
||||
tokio-tungstenite = "0.14" # websocket
|
||||
|
||||
## internal
|
||||
nym-bin-common = { path = "../../common/bin-common" }
|
||||
client-core = { path = "../client-core", features = ["fs-surb-storage"] }
|
||||
coconut-interface = { path = "../../common/coconut-interface" }
|
||||
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
|
||||
nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] }
|
||||
nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage"] }
|
||||
nym-coconut-interface = { path = "../../common/coconut-interface" }
|
||||
nym-config = { path = "../../common/config" }
|
||||
credential-storage = { path = "../../common/credential-storage" }
|
||||
credentials = { path = "../../common/credentials" }
|
||||
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||
nym-credentials = { path = "../../common/credentials" }
|
||||
nym-crypto = { path = "../../common/crypto" }
|
||||
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
||||
gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||
nym-sphinx = { path = "../../common/nymsphinx" }
|
||||
nym-pemstore = { path = "../../common/pemstore" }
|
||||
nym-task = { path = "../../common/task" }
|
||||
nym-topology = { path = "../../common/topology" }
|
||||
validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
|
||||
websocket-requests = { path = "websocket-requests" }
|
||||
nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
|
||||
nym-client-websocket-requests = { path = "websocket-requests" }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json = "1.0" # for the "textsend" example
|
||||
|
||||
+41
-41
@@ -13,7 +13,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"webpack": "^5.70.0",
|
||||
"webpack": "^5.76.0",
|
||||
"webpack-cli": "^4.9.2",
|
||||
"webpack-dev-server": "^4.7.4"
|
||||
}
|
||||
@@ -490,9 +490,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.7.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
|
||||
"integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==",
|
||||
"version": "8.8.2",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
|
||||
"integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -1327,9 +1327,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.9.2",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz",
|
||||
"integrity": "sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA==",
|
||||
"version": "5.12.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz",
|
||||
"integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
"tapable": "^2.2.0"
|
||||
@@ -2380,10 +2380,10 @@
|
||||
"node": ">= 10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/json-parse-better-errors": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
|
||||
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
|
||||
"node_modules/json-parse-even-better-errors": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
|
||||
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
|
||||
},
|
||||
"node_modules/json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
@@ -3824,9 +3824,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz",
|
||||
"integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
|
||||
"integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
|
||||
"dependencies": {
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
"graceful-fs": "^4.1.2"
|
||||
@@ -3845,33 +3845,33 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.70.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.70.0.tgz",
|
||||
"integrity": "sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw==",
|
||||
"version": "5.76.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.0.tgz",
|
||||
"integrity": "sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==",
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
"@types/estree": "^0.0.51",
|
||||
"@webassemblyjs/ast": "1.11.1",
|
||||
"@webassemblyjs/wasm-edit": "1.11.1",
|
||||
"@webassemblyjs/wasm-parser": "1.11.1",
|
||||
"acorn": "^8.4.1",
|
||||
"acorn": "^8.7.1",
|
||||
"acorn-import-assertions": "^1.7.6",
|
||||
"browserslist": "^4.14.5",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"enhanced-resolve": "^5.9.2",
|
||||
"enhanced-resolve": "^5.10.0",
|
||||
"es-module-lexer": "^0.9.0",
|
||||
"eslint-scope": "5.1.1",
|
||||
"events": "^3.2.0",
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
"graceful-fs": "^4.2.9",
|
||||
"json-parse-better-errors": "^1.0.2",
|
||||
"json-parse-even-better-errors": "^2.3.1",
|
||||
"loader-runner": "^4.2.0",
|
||||
"mime-types": "^2.1.27",
|
||||
"neo-async": "^2.6.2",
|
||||
"schema-utils": "^3.1.0",
|
||||
"tapable": "^2.1.1",
|
||||
"terser-webpack-plugin": "^5.1.3",
|
||||
"watchpack": "^2.3.1",
|
||||
"watchpack": "^2.4.0",
|
||||
"webpack-sources": "^3.2.3"
|
||||
},
|
||||
"bin": {
|
||||
@@ -4894,9 +4894,9 @@
|
||||
}
|
||||
},
|
||||
"acorn": {
|
||||
"version": "8.7.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
|
||||
"integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ=="
|
||||
"version": "8.8.2",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
|
||||
"integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw=="
|
||||
},
|
||||
"acorn-import-assertions": {
|
||||
"version": "1.8.0",
|
||||
@@ -5527,9 +5527,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"enhanced-resolve": {
|
||||
"version": "5.9.2",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz",
|
||||
"integrity": "sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA==",
|
||||
"version": "5.12.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz",
|
||||
"integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==",
|
||||
"requires": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
"tapable": "^2.2.0"
|
||||
@@ -6305,10 +6305,10 @@
|
||||
"supports-color": "^8.0.0"
|
||||
}
|
||||
},
|
||||
"json-parse-better-errors": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
|
||||
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
|
||||
"json-parse-even-better-errors": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
|
||||
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
@@ -7396,9 +7396,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"watchpack": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz",
|
||||
"integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
|
||||
"integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
|
||||
"requires": {
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
"graceful-fs": "^4.1.2"
|
||||
@@ -7414,33 +7414,33 @@
|
||||
}
|
||||
},
|
||||
"webpack": {
|
||||
"version": "5.70.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.70.0.tgz",
|
||||
"integrity": "sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw==",
|
||||
"version": "5.76.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.0.tgz",
|
||||
"integrity": "sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==",
|
||||
"requires": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
"@types/estree": "^0.0.51",
|
||||
"@webassemblyjs/ast": "1.11.1",
|
||||
"@webassemblyjs/wasm-edit": "1.11.1",
|
||||
"@webassemblyjs/wasm-parser": "1.11.1",
|
||||
"acorn": "^8.4.1",
|
||||
"acorn": "^8.7.1",
|
||||
"acorn-import-assertions": "^1.7.6",
|
||||
"browserslist": "^4.14.5",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"enhanced-resolve": "^5.9.2",
|
||||
"enhanced-resolve": "^5.10.0",
|
||||
"es-module-lexer": "^0.9.0",
|
||||
"eslint-scope": "5.1.1",
|
||||
"events": "^3.2.0",
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
"graceful-fs": "^4.2.9",
|
||||
"json-parse-better-errors": "^1.0.2",
|
||||
"json-parse-even-better-errors": "^2.3.1",
|
||||
"loader-runner": "^4.2.0",
|
||||
"mime-types": "^2.1.27",
|
||||
"neo-async": "^2.6.2",
|
||||
"schema-utils": "^3.1.0",
|
||||
"tapable": "^2.1.1",
|
||||
"terser-webpack-plugin": "^5.1.3",
|
||||
"watchpack": "^2.3.1",
|
||||
"watchpack": "^2.4.0",
|
||||
"webpack-sources": "^3.2.3"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"webpack": "^5.70.0",
|
||||
"webpack": "^5.76.0",
|
||||
"webpack-cli": "^4.9.2",
|
||||
"webpack-dev-server": "^4.7.4"
|
||||
},
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use nym_client_websocket_requests::{requests::ClientRequest, responses::ServerResponse};
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio_tungstenite::{
|
||||
connect_async, tungstenite::protocol::Message, MaybeTlsStream, WebSocketStream,
|
||||
};
|
||||
use websocket_requests::{requests::ClientRequest, responses::ServerResponse};
|
||||
|
||||
// just helpers functions that work in this very particular context because we are sending to ourselves
|
||||
// and hence will always get a response back (i.e. the message we sent)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::template::config_template;
|
||||
use client_core::config::ClientCoreConfigTrait;
|
||||
use nym_client_core::config::ClientCoreConfigTrait;
|
||||
use nym_config::defaults::DEFAULT_WEBSOCKET_LISTENING_PORT;
|
||||
use nym_config::{NymConfig, OptionalSet};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -11,10 +11,11 @@ use std::net::{IpAddr, Ipv4Addr};
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub use client_core::config::Config as BaseConfig;
|
||||
pub use client_core::config::MISSING_VALUE;
|
||||
pub use client_core::config::{DebugConfig, GatewayEndpointConfig};
|
||||
pub use nym_client_core::config::Config as BaseConfig;
|
||||
pub use nym_client_core::config::MISSING_VALUE;
|
||||
pub use nym_client_core::config::{DebugConfig, GatewayEndpointConfig};
|
||||
|
||||
pub mod old_config_v1_1_13;
|
||||
mod template;
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone, Copy)]
|
||||
@@ -80,7 +81,7 @@ impl NymConfig for Config {
|
||||
}
|
||||
|
||||
impl ClientCoreConfigTrait for Config {
|
||||
fn get_gateway_endpoint(&self) -> &client_core::config::GatewayEndpointConfig {
|
||||
fn get_gateway_endpoint(&self) -> &nym_client_core::config::GatewayEndpointConfig {
|
||||
self.base.get_gateway_endpoint()
|
||||
}
|
||||
}
|
||||
@@ -93,6 +94,11 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate(&self) -> bool {
|
||||
// no other sections have explicit requirements (yet)
|
||||
self.base.validate()
|
||||
}
|
||||
|
||||
pub fn with_socket(mut self, socket_type: SocketType) -> Self {
|
||||
self.socket.socket_type = socket_type;
|
||||
self
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::{Config, Socket};
|
||||
use nym_client_core::config::old_config_v1_1_13::OldConfigV1_1_13 as OldBaseConfigV1_1_13;
|
||||
use nym_config::NymConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct OldConfigV1_1_13 {
|
||||
#[serde(flatten)]
|
||||
base: OldBaseConfigV1_1_13<OldConfigV1_1_13>,
|
||||
|
||||
socket: Socket,
|
||||
}
|
||||
|
||||
impl NymConfig for OldConfigV1_1_13 {
|
||||
fn template() -> &'static str {
|
||||
// not intended to be used
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn default_root_directory() -> PathBuf {
|
||||
dirs::home_dir()
|
||||
.expect("Failed to evaluate $HOME value")
|
||||
.join(".nym")
|
||||
.join("clients")
|
||||
}
|
||||
|
||||
fn try_default_root_directory() -> Option<PathBuf> {
|
||||
dirs::home_dir().map(|path| path.join(".nym").join("clients"))
|
||||
}
|
||||
|
||||
fn root_directory(&self) -> PathBuf {
|
||||
self.base.client.nym_root_directory.clone()
|
||||
}
|
||||
|
||||
fn config_directory(&self) -> PathBuf {
|
||||
self.root_directory()
|
||||
.join(&self.base.client.id)
|
||||
.join("config")
|
||||
}
|
||||
|
||||
fn data_directory(&self) -> PathBuf {
|
||||
self.root_directory()
|
||||
.join(&self.base.client.id)
|
||||
.join("data")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OldConfigV1_1_13> for Config {
|
||||
fn from(value: OldConfigV1_1_13) -> Self {
|
||||
Config {
|
||||
base: value.base.into(),
|
||||
socket: value.socket,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,10 +110,15 @@ host = '{{ socket.host }}'
|
||||
|
||||
[debug]
|
||||
|
||||
average_packet_delay = '{{ debug.average_packet_delay }}'
|
||||
average_ack_delay = '{{ debug.average_ack_delay }}'
|
||||
loop_cover_traffic_average_delay = '{{ debug.loop_cover_traffic_average_delay }}'
|
||||
message_sending_average_delay = '{{ debug.message_sending_average_delay }}'
|
||||
[debug.traffic]
|
||||
average_packet_delay = '{{ debug.traffic.average_packet_delay }}'
|
||||
message_sending_average_delay = '{{ debug.traffic.message_sending_average_delay }}'
|
||||
|
||||
[debug.acknowledgements]
|
||||
average_ack_delay = '{{ debug.acknowledgements.average_ack_delay }}'
|
||||
|
||||
[debug.cover_traffic]
|
||||
loop_cover_traffic_average_delay = '{{ debug.cover_traffic.loop_cover_traffic_average_delay }}'
|
||||
|
||||
"#
|
||||
}
|
||||
|
||||
@@ -1,82 +1,60 @@
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::error::Error;
|
||||
|
||||
use crate::client::config::Config;
|
||||
use crate::error::ClientError;
|
||||
use crate::websocket;
|
||||
use client_core::client::base_client::{
|
||||
use futures::channel::mpsc;
|
||||
use log::*;
|
||||
use nym_bandwidth_controller::BandwidthController;
|
||||
use nym_client_core::client::base_client::non_wasm_helpers::create_bandwidth_controller;
|
||||
use nym_client_core::client::base_client::storage::OnDiskPersistent;
|
||||
use nym_client_core::client::base_client::{
|
||||
non_wasm_helpers, BaseClientBuilder, ClientInput, ClientOutput, ClientState,
|
||||
};
|
||||
use client_core::client::inbound_messages::InputMessage;
|
||||
use client_core::client::received_buffer::{
|
||||
use nym_client_core::client::inbound_messages::InputMessage;
|
||||
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
|
||||
use nym_client_core::client::received_buffer::{
|
||||
ReceivedBufferMessage, ReceivedBufferRequestSender, ReconstructedMessagesReceiver,
|
||||
};
|
||||
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||
use futures::channel::mpsc;
|
||||
use gateway_client::bandwidth::BandwidthController;
|
||||
use log::*;
|
||||
use nym_client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||
use nym_credential_storage::persistent_storage::PersistentStorage;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
use nym_task::TaskManager;
|
||||
use nym_validator_client::nyxd::QueryNyxdClient;
|
||||
use nym_validator_client::Client;
|
||||
use std::error::Error;
|
||||
use tokio::sync::watch::error::SendError;
|
||||
use validator_client::nyxd::QueryNyxdClient;
|
||||
|
||||
pub use client_core::client::key_manager::KeyManager;
|
||||
pub use nym_sphinx::addressing::clients::Recipient;
|
||||
pub use nym_sphinx::receiver::ReconstructedMessage;
|
||||
|
||||
pub mod config;
|
||||
|
||||
type NativeClientBuilder<'a> = BaseClientBuilder<'a, Client<QueryNyxdClient>, OnDiskPersistent>;
|
||||
|
||||
pub struct SocketClient {
|
||||
/// Client configuration options, including, among other things, packet sending rates,
|
||||
/// key filepaths, etc.
|
||||
config: Config,
|
||||
|
||||
/// KeyManager object containing smart pointers to all relevant keys used by the client.
|
||||
key_manager: KeyManager,
|
||||
}
|
||||
|
||||
impl SocketClient {
|
||||
pub fn new(config: Config) -> Self {
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
let key_manager = KeyManager::load_keys(&pathfinder).expect("failed to load stored keys");
|
||||
|
||||
SocketClient {
|
||||
config,
|
||||
key_manager,
|
||||
}
|
||||
SocketClient { config }
|
||||
}
|
||||
|
||||
pub fn new_with_keys(config: Config, key_manager: KeyManager) -> Self {
|
||||
SocketClient {
|
||||
config,
|
||||
key_manager,
|
||||
}
|
||||
}
|
||||
|
||||
async fn create_bandwidth_controller(config: &Config) -> BandwidthController<QueryNyxdClient> {
|
||||
let details = nym_network_defaults::NymNetworkDetails::new_from_env();
|
||||
let mut client_config = validator_client::Config::try_from_nym_network_details(&details)
|
||||
.expect("failed to construct validator client config");
|
||||
let nyxd_url = config
|
||||
.get_base()
|
||||
.get_validator_endpoints()
|
||||
.pop()
|
||||
.expect("No nyxd validator endpoint provided");
|
||||
let api_url = config
|
||||
.get_base()
|
||||
.get_nym_api_endpoints()
|
||||
.pop()
|
||||
.expect("No validator api endpoint provided");
|
||||
// overwrite env configuration with config URLs
|
||||
client_config = client_config.with_urls(nyxd_url, api_url);
|
||||
let client = validator_client::Client::new_query(client_config)
|
||||
.expect("Could not construct query client");
|
||||
BandwidthController::new(
|
||||
credential_storage::initialise_storage(config.get_base().get_database_path()).await,
|
||||
client,
|
||||
async fn create_bandwidth_controller(
|
||||
config: &Config,
|
||||
) -> BandwidthController<Client<QueryNyxdClient>, PersistentStorage> {
|
||||
let storage = nym_credential_storage::initialise_persistent_storage(
|
||||
config.get_base().get_database_path(),
|
||||
)
|
||||
.await;
|
||||
|
||||
create_bandwidth_controller(config.get_base(), storage)
|
||||
}
|
||||
|
||||
fn start_websocket_listener(
|
||||
@@ -86,6 +64,7 @@ impl SocketClient {
|
||||
client_state: ClientState,
|
||||
self_address: &Recipient,
|
||||
shutdown: nym_task::TaskClient,
|
||||
packet_type: PacketType,
|
||||
) {
|
||||
info!("Starting websocket listener...");
|
||||
|
||||
@@ -101,6 +80,7 @@ impl SocketClient {
|
||||
let ClientState {
|
||||
shared_lane_queue_lengths,
|
||||
reply_controller_sender,
|
||||
..
|
||||
} = client_state;
|
||||
|
||||
let websocket_handler = websocket::HandlerBuilder::new(
|
||||
@@ -110,6 +90,7 @@ impl SocketClient {
|
||||
self_address,
|
||||
shared_lane_queue_lengths,
|
||||
reply_controller_sender,
|
||||
Some(packet_type),
|
||||
);
|
||||
|
||||
websocket::Listener::new(config.get_listening_ip(), config.get_listening_port())
|
||||
@@ -125,11 +106,13 @@ impl SocketClient {
|
||||
res
|
||||
}
|
||||
|
||||
pub async fn start_socket(self) -> Result<TaskManager, ClientError> {
|
||||
if !self.config.get_socket_type().is_websocket() {
|
||||
return Err(ClientError::InvalidSocketMode);
|
||||
}
|
||||
fn key_store(&self) -> OnDiskKeys {
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(self.config.get_base());
|
||||
OnDiskKeys::new(pathfinder)
|
||||
}
|
||||
|
||||
// TODO: see if this could also be shared with socks5 client / nym-sdk maybe
|
||||
async fn create_base_client_builder(&self) -> Result<NativeClientBuilder, ClientError> {
|
||||
// don't create bandwidth controller if credentials are disabled
|
||||
let bandwidth_controller = if self.config.get_base().get_disabled_credentials_mode() {
|
||||
None
|
||||
@@ -137,19 +120,29 @@ impl SocketClient {
|
||||
Some(Self::create_bandwidth_controller(&self.config).await)
|
||||
};
|
||||
|
||||
let base_builder = BaseClientBuilder::new_from_base_config(
|
||||
let base_client = BaseClientBuilder::new_from_base_config(
|
||||
self.config.get_base(),
|
||||
self.key_manager,
|
||||
self.key_store(),
|
||||
bandwidth_controller,
|
||||
non_wasm_helpers::setup_fs_reply_surb_backend(
|
||||
Some(self.config.get_base().get_reply_surb_database_path()),
|
||||
self.config.get_debug_settings(),
|
||||
self.config.get_base().get_reply_surb_database_path(),
|
||||
&self.config.get_debug_settings().reply_surbs,
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
|
||||
let self_address = base_builder.as_mix_recipient();
|
||||
let mut started_client = base_builder.start_base().await?;
|
||||
Ok(base_client)
|
||||
}
|
||||
|
||||
pub async fn start_socket(self) -> Result<TaskManager, ClientError> {
|
||||
if !self.config.get_socket_type().is_websocket() {
|
||||
return Err(ClientError::InvalidSocketMode);
|
||||
}
|
||||
|
||||
let base_builder = self.create_base_client_builder().await?;
|
||||
let packet_type = self.config.get_base().get_packet_type();
|
||||
let mut started_client = base_builder.start_base(packet_type).await?;
|
||||
let self_address = started_client.address;
|
||||
let client_input = started_client.client_input.register_producer();
|
||||
let client_output = started_client.client_output.register_consumer();
|
||||
let client_state = started_client.client_state;
|
||||
@@ -161,10 +154,11 @@ impl SocketClient {
|
||||
client_state,
|
||||
&self_address,
|
||||
started_client.task_manager.subscribe(),
|
||||
packet_type,
|
||||
);
|
||||
|
||||
info!("Client startup finished!");
|
||||
info!("The address of this client is: {}", self_address);
|
||||
info!("The address of this client is: {self_address}");
|
||||
|
||||
Ok(started_client.task_manager)
|
||||
}
|
||||
@@ -174,27 +168,10 @@ impl SocketClient {
|
||||
return Err(ClientError::InvalidSocketMode);
|
||||
}
|
||||
|
||||
// don't create bandwidth controller if credentials are disabled
|
||||
let bandwidth_controller = if self.config.get_base().get_disabled_credentials_mode() {
|
||||
None
|
||||
} else {
|
||||
Some(Self::create_bandwidth_controller(&self.config).await)
|
||||
};
|
||||
|
||||
let base_client = BaseClientBuilder::new_from_base_config(
|
||||
self.config.get_base(),
|
||||
self.key_manager,
|
||||
bandwidth_controller,
|
||||
non_wasm_helpers::setup_fs_reply_surb_backend(
|
||||
Some(self.config.get_base().get_reply_surb_database_path()),
|
||||
self.config.get_debug_settings(),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
|
||||
let address = base_client.as_mix_recipient();
|
||||
|
||||
let mut started_client = base_client.start_base().await?;
|
||||
let base_builder = self.create_base_client_builder().await?;
|
||||
let packet_type = self.config.get_base().get_packet_type();
|
||||
let mut started_client = base_builder.start_base(packet_type).await?;
|
||||
let address = started_client.address;
|
||||
let client_input = started_client.client_input.register_producer();
|
||||
let client_output = started_client.client_output.register_consumer();
|
||||
|
||||
@@ -215,6 +192,7 @@ impl SocketClient {
|
||||
reconstructed_receiver,
|
||||
address,
|
||||
shutdown_notifier: started_client.task_manager,
|
||||
packet_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -228,6 +206,7 @@ pub struct DirectClient {
|
||||
|
||||
// we need to keep reference to this guy otherwise things will start dropping
|
||||
shutdown_notifier: TaskManager,
|
||||
packet_type: PacketType,
|
||||
}
|
||||
|
||||
impl DirectClient {
|
||||
@@ -248,7 +227,7 @@ impl DirectClient {
|
||||
/// well enough in local tests)
|
||||
pub async fn send_regular_message(&mut self, recipient: Recipient, message: Vec<u8>) {
|
||||
let lane = TransmissionLane::General;
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane);
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane, Some(self.packet_type));
|
||||
|
||||
self.client_input
|
||||
.input_sender
|
||||
@@ -267,7 +246,13 @@ impl DirectClient {
|
||||
reply_surbs: u32,
|
||||
) {
|
||||
let lane = TransmissionLane::General;
|
||||
let input_msg = InputMessage::new_anonymous(recipient, message, reply_surbs, lane);
|
||||
let input_msg = InputMessage::new_anonymous(
|
||||
recipient,
|
||||
message,
|
||||
reply_surbs,
|
||||
lane,
|
||||
Some(self.packet_type),
|
||||
);
|
||||
|
||||
self.client_input
|
||||
.input_sender
|
||||
@@ -281,7 +266,8 @@ impl DirectClient {
|
||||
/// well enough in local tests)
|
||||
pub async fn send_reply(&mut self, recipient_tag: AnonymousSenderTag, message: Vec<u8>) {
|
||||
let lane = TransmissionLane::General;
|
||||
let input_msg = InputMessage::new_reply(recipient_tag, message, lane);
|
||||
let input_msg =
|
||||
InputMessage::new_reply(recipient_tag, message, lane, Some(self.packet_type));
|
||||
|
||||
self.client_input
|
||||
.input_sender
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::try_upgrade_v1_1_13_config;
|
||||
use crate::{
|
||||
client::config::Config,
|
||||
commands::{override_config, OverrideConfig},
|
||||
error::ClientError,
|
||||
};
|
||||
use clap::Args;
|
||||
use nym_bin_common::output_format::OutputFormat;
|
||||
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
|
||||
use nym_config::NymConfig;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
@@ -25,6 +28,11 @@ pub(crate) struct Init {
|
||||
#[clap(long)]
|
||||
gateway: Option<identity::PublicKey>,
|
||||
|
||||
/// Specifies whether the new gateway should be determined based by latency as opposed to being chosen
|
||||
/// uniformly.
|
||||
#[clap(long, conflicts_with = "gateway")]
|
||||
latency_based_selection: bool,
|
||||
|
||||
/// Force register gateway. WARNING: this will overwrite any existing keys for the given id,
|
||||
/// potentially causing loss of access.
|
||||
#[clap(long)]
|
||||
@@ -65,9 +73,8 @@ pub(crate) struct Init {
|
||||
#[clap(long, hide = true)]
|
||||
enabled_credentials_mode: Option<bool>,
|
||||
|
||||
/// Save a summary of the initialization to a json file
|
||||
#[clap(long)]
|
||||
output_json: bool,
|
||||
#[clap(short, long, default_value_t = OutputFormat::default())]
|
||||
output: OutputFormat,
|
||||
}
|
||||
|
||||
impl From<Init> for OverrideConfig {
|
||||
@@ -89,15 +96,17 @@ impl From<Init> for OverrideConfig {
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct InitResults {
|
||||
#[serde(flatten)]
|
||||
client_core: client_core::init::InitResults,
|
||||
client_core: nym_client_core::init::InitResults,
|
||||
client_listening_port: String,
|
||||
client_address: String,
|
||||
}
|
||||
|
||||
impl InitResults {
|
||||
fn new(config: &Config, address: &Recipient) -> Self {
|
||||
Self {
|
||||
client_core: client_core::init::InitResults::new(config.get_base(), address),
|
||||
client_core: nym_client_core::init::InitResults::new(config.get_base(), address),
|
||||
client_listening_port: config.get_listening_port().to_string(),
|
||||
client_address: address.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,25 +114,29 @@ impl InitResults {
|
||||
impl Display for InitResults {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
writeln!(f, "{}", self.client_core)?;
|
||||
write!(f, "Client listening port: {}", self.client_listening_port)
|
||||
writeln!(f, "Client listening port: {}", self.client_listening_port)?;
|
||||
write!(f, "Address of this client: {}", self.client_address)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
|
||||
println!("Initialising client...");
|
||||
eprintln!("Initialising client...");
|
||||
|
||||
let id = &args.id;
|
||||
|
||||
let already_init = Config::default_config_file_path(id).exists();
|
||||
if already_init {
|
||||
println!("Client \"{id}\" was already initialised before");
|
||||
// in case we're using old config, try to upgrade it
|
||||
// (if we're using the current version, it's a no-op)
|
||||
try_upgrade_v1_1_13_config(id)?;
|
||||
eprintln!("Client \"{id}\" was already initialised before");
|
||||
}
|
||||
|
||||
// Usually you only register with the gateway on the first init, however you can force
|
||||
// re-registering if wanted.
|
||||
let user_wants_force_register = args.force_register_gateway;
|
||||
if user_wants_force_register {
|
||||
println!("Instructed to force registering gateway. This might overwrite keys!");
|
||||
eprintln!("Instructed to force registering gateway. This might overwrite keys!");
|
||||
}
|
||||
|
||||
// If the client was already initialized, don't generate new keys and don't re-register with
|
||||
@@ -139,10 +152,13 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
|
||||
|
||||
// Setup gateway by either registering a new one, or creating a new config from the selected
|
||||
// one but with keys kept, or reusing the gateway configuration.
|
||||
let gateway = client_core::init::setup_gateway_from_config::<Config, _>(
|
||||
let key_store = OnDiskKeys::from_config(config.get_base());
|
||||
let gateway = nym_client_core::init::setup_gateway_from_config::<Config, _, _>(
|
||||
&key_store,
|
||||
register_gateway,
|
||||
user_chosen_gateway_id,
|
||||
config.get_base(),
|
||||
args.latency_based_selection,
|
||||
)
|
||||
.await
|
||||
.tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?;
|
||||
@@ -155,28 +171,23 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
|
||||
|
||||
print_saved_config(&config);
|
||||
|
||||
let address = client_core::init::get_client_address_from_stored_keys(config.get_base())?;
|
||||
let address =
|
||||
nym_client_core::init::get_client_address_from_stored_ondisk_keys(config.get_base())?;
|
||||
let init_results = InitResults::new(&config, &address);
|
||||
println!("{init_results}");
|
||||
println!("{}", args.output.format(&init_results));
|
||||
|
||||
// Output summary to a json file, if specified
|
||||
if args.output_json {
|
||||
client_core::init::output_to_json(&init_results, "client_init_results.json");
|
||||
}
|
||||
|
||||
println!("\nThe address of this client is: {address}\n");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_saved_config(config: &Config) {
|
||||
let config_save_location = config.get_config_file_save_location();
|
||||
println!("Saved configuration file to {config_save_location:?}");
|
||||
println!("Using gateway: {}", config.get_base().get_gateway_id());
|
||||
eprintln!("Saved configuration file to {config_save_location:?}");
|
||||
eprintln!("Using gateway: {}", config.get_base().get_gateway_id());
|
||||
log::debug!("Gateway id: {}", config.get_base().get_gateway_id());
|
||||
log::debug!("Gateway owner: {}", config.get_base().get_gateway_owner());
|
||||
log::debug!(
|
||||
"Gateway listener: {}",
|
||||
config.get_base().get_gateway_listener()
|
||||
);
|
||||
println!("Client configuration completed.\n");
|
||||
eprintln!("Client configuration completed.\n");
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::old_config_v1_1_13::OldConfigV1_1_13;
|
||||
use crate::client::config::{BaseConfig, Config};
|
||||
use clap::CommandFactory;
|
||||
use clap::{Parser, Subcommand};
|
||||
use lazy_static::lazy_static;
|
||||
use log::info;
|
||||
use nym_bin_common::build_information::BinaryBuildInformation;
|
||||
use nym_bin_common::completions::{fig_generate, ArgShell};
|
||||
use nym_config::OptionalSet;
|
||||
use nym_config::{NymConfig, OptionalSet};
|
||||
use std::error::Error;
|
||||
use std::net::IpAddr;
|
||||
|
||||
@@ -102,6 +104,20 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
|
||||
)
|
||||
}
|
||||
|
||||
fn try_upgrade_v1_1_13_config(id: &str) -> std::io::Result<()> {
|
||||
// explicitly load it as v1.1.13 (which is incompatible with the current, i.e. 1.1.14+)
|
||||
let Ok(old_config) = OldConfigV1_1_13::load_from_file(id) else {
|
||||
// if we failed to load it, there might have been nothing to upgrade
|
||||
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
|
||||
return Ok(());
|
||||
};
|
||||
info!("It seems the client is using <= v1.1.13 config template.");
|
||||
info!("It is going to get updated to the current specification.");
|
||||
|
||||
let updated: Config = old_config.into();
|
||||
updated.save_to_file(None)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
use std::error::Error;
|
||||
use std::net::IpAddr;
|
||||
|
||||
use crate::commands::try_upgrade_v1_1_13_config;
|
||||
use crate::{
|
||||
client::{config::Config, SocketClient},
|
||||
commands::{override_config, OverrideConfig},
|
||||
error::ClientError,
|
||||
};
|
||||
|
||||
use clap::Args;
|
||||
use log::*;
|
||||
use nym_bin_common::version_checker::is_minor_version_compatible;
|
||||
@@ -100,6 +100,10 @@ fn version_check(cfg: &Config) -> bool {
|
||||
pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
let id = &args.id;
|
||||
|
||||
// in case we're using old config, try to upgrade it
|
||||
// (if we're using the current version, it's a no-op)
|
||||
try_upgrade_v1_1_13_config(id)?;
|
||||
|
||||
let mut config = match Config::load_from_file(id) {
|
||||
Ok(cfg) => cfg,
|
||||
Err(err) => {
|
||||
@@ -108,6 +112,10 @@ pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn Error + Send + Syn
|
||||
}
|
||||
};
|
||||
|
||||
if !config.validate() {
|
||||
return Err(Box::new(ClientError::ConfigValidationFailure));
|
||||
}
|
||||
|
||||
let override_config_fields = OverrideConfig::from(args.clone());
|
||||
config = override_config(config, override_config_fields);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use client_core::error::ClientCoreError;
|
||||
use nym_client_core::error::ClientCoreError;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum ClientError {
|
||||
@@ -11,6 +11,10 @@ pub enum ClientError {
|
||||
#[error("Failed to load config for: {0}")]
|
||||
FailedToLoadConfig(String),
|
||||
|
||||
// TODO: add more details here
|
||||
#[error("Failed to validate the loaded config")]
|
||||
ConfigValidationFailure,
|
||||
|
||||
#[error("Failed local version check, client and config mismatch")]
|
||||
FailedLocalVersionCheck,
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use std::error::Error;
|
||||
|
||||
use clap::{crate_name, crate_version, Parser};
|
||||
use nym_bin_common::logging::{banner, setup_logging};
|
||||
use nym_bin_common::logging::{maybe_print_banner, setup_logging};
|
||||
use nym_network_defaults::setup_env;
|
||||
|
||||
pub mod client;
|
||||
@@ -15,7 +15,7 @@ pub mod websocket;
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
setup_logging();
|
||||
println!("{}", banner(crate_name!(), crate_version!()));
|
||||
maybe_print_banner(crate_name!(), crate_version!());
|
||||
|
||||
let args = commands::Cli::parse();
|
||||
setup_env(args.config_env_file.as_ref());
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use client_core::client::replies::reply_controller::requests::ReplyControllerSender;
|
||||
use client_core::client::{
|
||||
use futures::channel::mpsc;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use log::*;
|
||||
use nym_client_core::client::replies::reply_controller::requests::ReplyControllerSender;
|
||||
use nym_client_core::client::{
|
||||
inbound_messages::{InputMessage, InputMessageSender},
|
||||
received_buffer::{
|
||||
ReceivedBufferMessage, ReceivedBufferRequestSender, ReconstructedMessagesReceiver,
|
||||
},
|
||||
};
|
||||
use futures::channel::mpsc;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use log::*;
|
||||
use nym_client_websocket_requests::{requests::ClientRequest, responses::ServerResponse};
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_sphinx::receiver::ReconstructedMessage;
|
||||
use nym_task::connections::{
|
||||
ConnectionCommand, ConnectionCommandSender, ConnectionId, LaneQueueLengths, TransmissionLane,
|
||||
@@ -25,7 +27,6 @@ use tokio_tungstenite::{
|
||||
tungstenite::{protocol::Message as WsMessage, Error as WsError},
|
||||
WebSocketStream,
|
||||
};
|
||||
use websocket_requests::{requests::ClientRequest, responses::ServerResponse};
|
||||
|
||||
#[derive(Default)]
|
||||
enum ReceivedResponseType {
|
||||
@@ -41,6 +42,7 @@ pub(crate) struct HandlerBuilder {
|
||||
self_full_address: Recipient,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
packet_type: Option<PacketType>,
|
||||
}
|
||||
|
||||
impl HandlerBuilder {
|
||||
@@ -51,6 +53,7 @@ impl HandlerBuilder {
|
||||
self_full_address: &Recipient,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
packet_type: Option<PacketType>,
|
||||
) -> Self {
|
||||
Self {
|
||||
msg_input,
|
||||
@@ -59,6 +62,7 @@ impl HandlerBuilder {
|
||||
self_full_address: *self_full_address,
|
||||
lane_queue_lengths,
|
||||
reply_controller_sender,
|
||||
packet_type,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +77,7 @@ impl HandlerBuilder {
|
||||
received_response_type: Default::default(),
|
||||
lane_queue_lengths: self.lane_queue_lengths.clone(),
|
||||
reply_controller_sender: self.reply_controller_sender.clone(),
|
||||
packet_type: self.packet_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,6 +91,7 @@ pub(crate) struct Handler {
|
||||
received_response_type: ReceivedResponseType,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
packet_type: Option<PacketType>,
|
||||
}
|
||||
|
||||
impl Drop for Handler {
|
||||
@@ -160,7 +166,7 @@ impl Handler {
|
||||
});
|
||||
|
||||
// the ack control is now responsible for chunking, etc.
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane);
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane, self.packet_type);
|
||||
self.msg_input
|
||||
.send(input_msg)
|
||||
.await
|
||||
@@ -191,7 +197,8 @@ impl Handler {
|
||||
TransmissionLane::ConnectionId(id)
|
||||
});
|
||||
|
||||
let input_msg = InputMessage::new_anonymous(recipient, message, reply_surbs, lane);
|
||||
let input_msg =
|
||||
InputMessage::new_anonymous(recipient, message, reply_surbs, lane, self.packet_type);
|
||||
self.msg_input
|
||||
.send(input_msg)
|
||||
.await
|
||||
@@ -218,7 +225,7 @@ impl Handler {
|
||||
TransmissionLane::ConnectionId(id)
|
||||
});
|
||||
|
||||
let input_msg = InputMessage::new_reply(recipient_tag, message, lane);
|
||||
let input_msg = InputMessage::new_reply(recipient_tag, message, lane, self.packet_type);
|
||||
self.msg_input
|
||||
.send(input_msg)
|
||||
.await
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "websocket-requests"
|
||||
name = "nym-client-websocket-requests"
|
||||
version = "0.1.0"
|
||||
authors = ["Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
edition = "2021"
|
||||
@@ -7,7 +7,7 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
nym-sphinx = { path = "../../../common/nymsphinx" }
|
||||
|
||||
+10
-25
@@ -1,24 +1,16 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.10"
|
||||
version = "1.1.19"
|
||||
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"
|
||||
rust-version = "1.56"
|
||||
|
||||
[lib]
|
||||
name = "nym_socks5"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.0", features = ["cargo", "derive"] }
|
||||
dirs = "4.0"
|
||||
futures = "0.3"
|
||||
lazy_static = "1.4.0"
|
||||
log = { workspace = true }
|
||||
pin-project = "1.0"
|
||||
pretty_env_logger = "0.4"
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
serde = { workspace = true, features = ["derive"] } # for config serialization/deserialization
|
||||
serde_json = { workspace = true }
|
||||
tap = "1.0.1"
|
||||
@@ -27,28 +19,21 @@ tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal"] }
|
||||
url = "2.2"
|
||||
|
||||
# internal
|
||||
nym-bin-common = { path = "../../common/bin-common" }
|
||||
client-core = { path = "../client-core", features = ["fs-surb-storage"] }
|
||||
coconut-interface = { path = "../../common/coconut-interface" }
|
||||
nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] }
|
||||
nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage"] }
|
||||
nym-coconut-interface = { path = "../../common/coconut-interface" }
|
||||
nym-config = { path = "../../common/config" }
|
||||
credential-storage = { path = "../../common/credential-storage", optional = true }
|
||||
mobile-storage = { path = "../../common/mobile-storage", optional = true }
|
||||
credentials = { path = "../../common/credentials" }
|
||||
nym-credentials = { path = "../../common/credentials" }
|
||||
nym-crypto = { path = "../../common/crypto" }
|
||||
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
||||
gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||
nym-sphinx = { path = "../../common/nymsphinx" }
|
||||
ordered-buffer = { path = "../../common/socks5/ordered-buffer" }
|
||||
nym-ordered-buffer = { path = "../../common/socks5/ordered-buffer" }
|
||||
nym-pemstore = { path = "../../common/pemstore" }
|
||||
proxy-helpers = { path = "../../common/socks5/proxy-helpers" }
|
||||
service-providers-common = { path = "../../service-providers/common" }
|
||||
socks5-requests = { path = "../../common/socks5/requests" }
|
||||
nym-task = { path = "../../common/task" }
|
||||
nym-topology = { path = "../../common/topology" }
|
||||
validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
|
||||
nym-socks5-client-core = { path = "../../common/socks5-client-core" }
|
||||
|
||||
[features]
|
||||
default = ["credential-storage"]
|
||||
default = []
|
||||
eth = []
|
||||
mobile = ["mobile-storage", "gateway-client/mobile"]
|
||||
|
||||
@@ -1,255 +0,0 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::Config;
|
||||
use crate::error::Socks5ClientError;
|
||||
use crate::socks;
|
||||
use crate::socks::{
|
||||
authentication::{AuthenticationMethods, Authenticator, User},
|
||||
server::SphinxSocksServer,
|
||||
};
|
||||
|
||||
#[cfg(feature = "mobile")]
|
||||
use client_core::client::base_client::helpers::setup_empty_reply_surb_backend;
|
||||
#[cfg(not(feature = "mobile"))]
|
||||
use client_core::client::base_client::non_wasm_helpers;
|
||||
use client_core::client::base_client::{BaseClientBuilder, ClientInput, ClientOutput, ClientState};
|
||||
use client_core::client::key_manager::KeyManager;
|
||||
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||
use futures::channel::mpsc;
|
||||
use futures::StreamExt;
|
||||
#[cfg(not(feature = "mobile"))]
|
||||
use gateway_client::bandwidth::BandwidthController;
|
||||
use log::*;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_task::{TaskClient, TaskManager};
|
||||
use std::error::Error;
|
||||
use validator_client::nyxd::QueryNyxdClient;
|
||||
|
||||
pub mod config;
|
||||
|
||||
// Channels used to control the main task from outside
|
||||
pub type Socks5ControlMessageSender = mpsc::UnboundedSender<Socks5ControlMessage>;
|
||||
pub type Socks5ControlMessageReceiver = mpsc::UnboundedReceiver<Socks5ControlMessage>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Socks5ControlMessage {
|
||||
/// Tell the main task to stop
|
||||
Stop,
|
||||
}
|
||||
|
||||
pub struct NymClient {
|
||||
/// Client configuration options, including, among other things, packet sending rates,
|
||||
/// key filepaths, etc.
|
||||
config: Config,
|
||||
|
||||
/// KeyManager object containing smart pointers to all relevant keys used by the client.
|
||||
key_manager: KeyManager,
|
||||
}
|
||||
|
||||
impl NymClient {
|
||||
pub fn new(config: Config) -> Self {
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
let key_manager = KeyManager::load_keys(&pathfinder).expect("failed to load stored keys");
|
||||
|
||||
NymClient {
|
||||
config,
|
||||
key_manager,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_keys(config: Config, key_manager: Option<KeyManager>) -> Self {
|
||||
let key_manager = key_manager.unwrap_or_else(|| {
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
KeyManager::load_keys(&pathfinder).expect("failed to load stored keys")
|
||||
});
|
||||
|
||||
NymClient {
|
||||
config,
|
||||
key_manager,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "mobile"))]
|
||||
async fn create_bandwidth_controller(config: &Config) -> BandwidthController<QueryNyxdClient> {
|
||||
let details = nym_network_defaults::NymNetworkDetails::new_from_env();
|
||||
let mut client_config = validator_client::Config::try_from_nym_network_details(&details)
|
||||
.expect("failed to construct validator client config");
|
||||
let nyxd_url = config
|
||||
.get_base()
|
||||
.get_validator_endpoints()
|
||||
.pop()
|
||||
.expect("No nyxd validator endpoint provided");
|
||||
let api_url = config
|
||||
.get_base()
|
||||
.get_nym_api_endpoints()
|
||||
.pop()
|
||||
.expect("No validator api endpoint provided");
|
||||
// overwrite env configuration with config URLs
|
||||
client_config = client_config.with_urls(nyxd_url, api_url);
|
||||
let client = validator_client::Client::new_query(client_config)
|
||||
.expect("Could not construct query client");
|
||||
|
||||
#[cfg(not(feature = "mobile"))]
|
||||
let storage =
|
||||
credential_storage::initialise_storage(config.get_base().get_database_path()).await;
|
||||
|
||||
#[cfg(feature = "mobile")]
|
||||
let storage = mobile_storage::PersistentStorage {};
|
||||
|
||||
BandwidthController::new(storage, client)
|
||||
}
|
||||
|
||||
fn start_socks5_listener(
|
||||
config: &Config,
|
||||
client_input: ClientInput,
|
||||
client_output: ClientOutput,
|
||||
client_status: ClientState,
|
||||
self_address: Recipient,
|
||||
shutdown: TaskClient,
|
||||
) {
|
||||
info!("Starting socks5 listener...");
|
||||
let auth_methods = vec![AuthenticationMethods::NoAuth as u8];
|
||||
let allowed_users: Vec<User> = Vec::new();
|
||||
|
||||
let ClientInput {
|
||||
connection_command_sender,
|
||||
input_sender,
|
||||
} = client_input;
|
||||
|
||||
let ClientOutput {
|
||||
received_buffer_request_sender,
|
||||
} = client_output;
|
||||
|
||||
let ClientState {
|
||||
shared_lane_queue_lengths,
|
||||
reply_controller_sender: _,
|
||||
} = client_status;
|
||||
|
||||
let authenticator = Authenticator::new(auth_methods, allowed_users);
|
||||
let mut sphinx_socks = SphinxSocksServer::new(
|
||||
config.get_listening_port(),
|
||||
authenticator,
|
||||
config.get_provider_mix_address(),
|
||||
self_address,
|
||||
shared_lane_queue_lengths,
|
||||
socks::client::Config::new(
|
||||
config.get_provider_interface_version(),
|
||||
config.get_socks5_protocol_version(),
|
||||
config.get_send_anonymously(),
|
||||
config.get_connection_start_surbs(),
|
||||
config.get_per_request_surbs(),
|
||||
),
|
||||
shutdown.clone(),
|
||||
);
|
||||
nym_task::spawn_with_report_error(
|
||||
async move {
|
||||
sphinx_socks
|
||||
.serve(
|
||||
input_sender,
|
||||
received_buffer_request_sender,
|
||||
connection_command_sender,
|
||||
)
|
||||
.await
|
||||
},
|
||||
shutdown,
|
||||
);
|
||||
}
|
||||
|
||||
/// blocking version of `start` method. Will run forever (or until SIGINT is sent)
|
||||
pub async fn run_forever(self) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
let shutdown = self.start().await?;
|
||||
|
||||
let res = shutdown.catch_interrupt().await;
|
||||
log::info!("Stopping nym-socks5-client");
|
||||
res
|
||||
}
|
||||
|
||||
// Variant of `run_forever` that listends for remote control messages
|
||||
pub async fn run_and_listen(
|
||||
self,
|
||||
mut receiver: Socks5ControlMessageReceiver,
|
||||
sender: nym_task::StatusSender,
|
||||
) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
// Start the main task
|
||||
let mut shutdown = self.start().await?;
|
||||
|
||||
// Listen to status messages from task, that we forward back to the caller
|
||||
shutdown.start_status_listener(sender).await;
|
||||
|
||||
let res = tokio::select! {
|
||||
biased;
|
||||
message = receiver.next() => {
|
||||
log::debug!("Received message: {:?}", message);
|
||||
match message {
|
||||
Some(Socks5ControlMessage::Stop) => {
|
||||
log::info!("Received stop message");
|
||||
}
|
||||
None => {
|
||||
log::info!("Channel closed, stopping");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Some(msg) = shutdown.wait_for_error() => {
|
||||
log::info!("Task error: {:?}", msg);
|
||||
Err(msg)
|
||||
}
|
||||
_ = tokio::signal::ctrl_c() => {
|
||||
log::info!("Received SIGINT");
|
||||
Ok(())
|
||||
},
|
||||
};
|
||||
|
||||
log::info!("Sending shutdown");
|
||||
shutdown.signal_shutdown().ok();
|
||||
|
||||
log::info!("Waiting for tasks to finish... (Press ctrl-c to force)");
|
||||
shutdown.wait_for_shutdown().await;
|
||||
|
||||
log::info!("Stopping nym-socks5-client");
|
||||
res
|
||||
}
|
||||
|
||||
pub async fn start(self) -> Result<TaskManager, Socks5ClientError> {
|
||||
#[cfg(not(feature = "mobile"))]
|
||||
let base_builder = BaseClientBuilder::new_from_base_config(
|
||||
self.config.get_base(),
|
||||
self.key_manager,
|
||||
Some(Self::create_bandwidth_controller(&self.config).await),
|
||||
non_wasm_helpers::setup_fs_reply_surb_backend(
|
||||
Some(self.config.get_base().get_reply_surb_database_path()),
|
||||
self.config.get_debug_settings(),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
|
||||
#[cfg(feature = "mobile")]
|
||||
let base_builder = BaseClientBuilder::<_, QueryNyxdClient>::new_from_base_config(
|
||||
self.config.get_base(),
|
||||
self.key_manager,
|
||||
None,
|
||||
setup_empty_reply_surb_backend(self.config.get_debug_settings()),
|
||||
);
|
||||
|
||||
let self_address = base_builder.as_mix_recipient();
|
||||
let mut started_client = base_builder.start_base().await?;
|
||||
let client_input = started_client.client_input.register_producer();
|
||||
let client_output = started_client.client_output.register_consumer();
|
||||
let client_state = started_client.client_state;
|
||||
|
||||
Self::start_socks5_listener(
|
||||
&self.config,
|
||||
client_input,
|
||||
client_output,
|
||||
client_state,
|
||||
self_address,
|
||||
started_client.task_manager.subscribe(),
|
||||
);
|
||||
|
||||
info!("Client startup finished!");
|
||||
info!("The address of this client is: {}", self_address);
|
||||
|
||||
Ok(started_client.task_manager)
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,17 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::try_upgrade_v1_1_13_config;
|
||||
use crate::{
|
||||
client::config::Config,
|
||||
commands::{override_config, OverrideConfig},
|
||||
error::Socks5ClientError,
|
||||
};
|
||||
use clap::Args;
|
||||
use nym_bin_common::output_format::OutputFormat;
|
||||
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
|
||||
use nym_config::NymConfig;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_socks5_client_core::config::Config;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use serde::Serialize;
|
||||
use std::fmt::Display;
|
||||
@@ -37,6 +40,11 @@ pub(crate) struct Init {
|
||||
#[clap(long)]
|
||||
gateway: Option<identity::PublicKey>,
|
||||
|
||||
/// Specifies whether the new gateway should be determined based by latency as opposed to being chosen
|
||||
/// uniformly.
|
||||
#[clap(long, conflicts_with = "gateway")]
|
||||
latency_based_selection: bool,
|
||||
|
||||
/// Force register gateway. WARNING: this will overwrite any existing keys for the given id,
|
||||
/// potentially causing loss of access.
|
||||
#[clap(long)]
|
||||
@@ -69,9 +77,8 @@ pub(crate) struct Init {
|
||||
#[clap(long, hide = true)]
|
||||
enabled_credentials_mode: Option<bool>,
|
||||
|
||||
/// Save a summary of the initialization to a json file
|
||||
#[clap(long)]
|
||||
output_json: bool,
|
||||
#[clap(short, long, default_value_t = OutputFormat::default())]
|
||||
output: OutputFormat,
|
||||
}
|
||||
|
||||
impl From<Init> for OverrideConfig {
|
||||
@@ -84,6 +91,7 @@ impl From<Init> for OverrideConfig {
|
||||
no_cover: init_config.no_cover,
|
||||
nyxd_urls: init_config.nyxd_urls,
|
||||
enabled_credentials_mode: init_config.enabled_credentials_mode,
|
||||
outfox: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,15 +99,17 @@ impl From<Init> for OverrideConfig {
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct InitResults {
|
||||
#[serde(flatten)]
|
||||
client_core: client_core::init::InitResults,
|
||||
client_core: nym_client_core::init::InitResults,
|
||||
socks5_listening_port: String,
|
||||
client_address: String,
|
||||
}
|
||||
|
||||
impl InitResults {
|
||||
fn new(config: &Config, address: &Recipient) -> Self {
|
||||
Self {
|
||||
client_core: client_core::init::InitResults::new(config.get_base(), address),
|
||||
socks5_listening_port: config.get_listening_port().to_string(),
|
||||
client_core: nym_client_core::init::InitResults::new(config.get_base(), address),
|
||||
socks5_listening_port: config.get_socks5().get_listening_port().to_string(),
|
||||
client_address: address.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,26 +117,30 @@ impl InitResults {
|
||||
impl Display for InitResults {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
writeln!(f, "{}", self.client_core)?;
|
||||
write!(f, "SOCKS5 listening port: {}", self.socks5_listening_port)
|
||||
writeln!(f, "SOCKS5 listening port: {}", self.socks5_listening_port)?;
|
||||
write!(f, "Address of this client: {}", self.client_address)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
|
||||
println!("Initialising client...");
|
||||
eprintln!("Initialising client...");
|
||||
|
||||
let id = &args.id;
|
||||
let provider_address = &args.provider;
|
||||
|
||||
let already_init = Config::default_config_file_path(id).exists();
|
||||
if already_init {
|
||||
println!("SOCKS5 client \"{id}\" was already initialised before");
|
||||
// in case we're using old config, try to upgrade it
|
||||
// (if we're using the current version, it's a no-op)
|
||||
try_upgrade_v1_1_13_config(id)?;
|
||||
eprintln!("SOCKS5 client \"{id}\" was already initialised before");
|
||||
}
|
||||
|
||||
// Usually you only register with the gateway on the first init, however you can force
|
||||
// re-registering if wanted.
|
||||
let user_wants_force_register = args.force_register_gateway;
|
||||
if user_wants_force_register {
|
||||
println!("Instructed to force registering gateway. This might overwrite keys!");
|
||||
eprintln!("Instructed to force registering gateway. This might overwrite keys!");
|
||||
}
|
||||
|
||||
// If the client was already initialized, don't generate new keys and don't re-register with
|
||||
@@ -145,10 +159,13 @@ pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
|
||||
|
||||
// Setup gateway by either registering a new one, or creating a new config from the selected
|
||||
// one but with keys kept, or reusing the gateway configuration.
|
||||
let gateway = client_core::init::setup_gateway_from_config::<Config, _>(
|
||||
let key_store = OnDiskKeys::from_config(config.get_base());
|
||||
let gateway = nym_client_core::init::setup_gateway_from_config::<Config, _, _>(
|
||||
&key_store,
|
||||
register_gateway,
|
||||
user_chosen_gateway_id,
|
||||
config.get_base(),
|
||||
args.latency_based_selection,
|
||||
)
|
||||
.await
|
||||
.tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?;
|
||||
@@ -163,28 +180,23 @@ pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
|
||||
|
||||
print_saved_config(&config);
|
||||
|
||||
let address = client_core::init::get_client_address_from_stored_keys(config.get_base())?;
|
||||
let address =
|
||||
nym_client_core::init::get_client_address_from_stored_ondisk_keys(config.get_base())?;
|
||||
let init_results = InitResults::new(&config, &address);
|
||||
println!("{}", init_results);
|
||||
println!("{}", args.output.format(&init_results));
|
||||
|
||||
// Output summary to a json file, if specified
|
||||
if args.output_json {
|
||||
client_core::init::output_to_json(&init_results, "socks5_client_init_results.json");
|
||||
}
|
||||
|
||||
println!("\nThe address of this client is: {}\n", address);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_saved_config(config: &Config) {
|
||||
let config_save_location = config.get_config_file_save_location();
|
||||
println!("Saved configuration file to {:?}", config_save_location);
|
||||
println!("Using gateway: {}", config.get_base().get_gateway_id());
|
||||
eprintln!("Saved configuration file to {:?}", config_save_location);
|
||||
eprintln!("Using gateway: {}", config.get_base().get_gateway_id());
|
||||
log::debug!("Gateway id: {}", config.get_base().get_gateway_id());
|
||||
log::debug!("Gateway owner: {}", config.get_base().get_gateway_owner());
|
||||
log::debug!(
|
||||
"Gateway listener: {}",
|
||||
config.get_base().get_gateway_listener()
|
||||
);
|
||||
println!("Client configuration completed.\n");
|
||||
eprintln!("Client configuration completed.\n");
|
||||
}
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::{BaseConfig, Config};
|
||||
use clap::CommandFactory;
|
||||
use clap::{Parser, Subcommand};
|
||||
use lazy_static::lazy_static;
|
||||
use log::info;
|
||||
use nym_bin_common::build_information::BinaryBuildInformation;
|
||||
use nym_bin_common::completions::{fig_generate, ArgShell};
|
||||
use nym_config::OptionalSet;
|
||||
use nym_config::{NymConfig, OptionalSet};
|
||||
use nym_socks5_client_core::config::old_config_v1_1_13::OldConfigV1_1_13;
|
||||
use nym_socks5_client_core::config::{BaseConfig, Config};
|
||||
use nym_sphinx::params::PacketType;
|
||||
use std::error::Error;
|
||||
|
||||
pub mod init;
|
||||
@@ -62,6 +65,7 @@ pub(crate) struct OverrideConfig {
|
||||
no_cover: bool,
|
||||
nyxd_urls: Option<Vec<url::Url>>,
|
||||
enabled_credentials_mode: Option<bool>,
|
||||
outfox: bool,
|
||||
}
|
||||
|
||||
pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
@@ -78,9 +82,15 @@ pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Syn
|
||||
}
|
||||
|
||||
pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
|
||||
let packet_type = if args.outfox {
|
||||
PacketType::Outfox
|
||||
} else {
|
||||
PacketType::Mix
|
||||
};
|
||||
config
|
||||
.with_base(BaseConfig::with_high_default_traffic_volume, args.fastmode)
|
||||
.with_base(BaseConfig::with_disabled_cover_traffic, args.no_cover)
|
||||
.with_base(BaseConfig::with_packet_type, packet_type)
|
||||
.with_optional(Config::with_anonymous_replies, args.use_anonymous_replies)
|
||||
.with_optional(Config::with_port, args.port)
|
||||
.with_optional_custom_env_ext(
|
||||
@@ -101,6 +111,20 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
|
||||
)
|
||||
}
|
||||
|
||||
fn try_upgrade_v1_1_13_config(id: &str) -> std::io::Result<()> {
|
||||
// explicitly load it as v1.1.13 (which is incompatible with the current, i.e. 1.1.14+)
|
||||
let Ok(old_config) = OldConfigV1_1_13::load_from_file(id) else {
|
||||
// if we failed to load it, there might have been nothing to upgrade
|
||||
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
|
||||
return Ok(());
|
||||
};
|
||||
info!("It seems the client is using <= v1.1.13 config template.");
|
||||
info!("It is going to get updated to the current specification.");
|
||||
|
||||
let updated: Config = old_config.into();
|
||||
updated.save_to_file(None)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::try_upgrade_v1_1_13_config;
|
||||
use crate::{
|
||||
client::{config::Config, NymClient},
|
||||
commands::{override_config, OverrideConfig},
|
||||
error::Socks5ClientError,
|
||||
};
|
||||
|
||||
use clap::Args;
|
||||
use log::*;
|
||||
use nym_bin_common::version_checker::is_minor_version_compatible;
|
||||
use nym_client_core::client::base_client::storage::OnDiskPersistent;
|
||||
use nym_config::NymConfig;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_socks5_client_core::{config::Config, NymClient};
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
|
||||
#[derive(Args, Clone)]
|
||||
@@ -67,6 +68,9 @@ pub(crate) struct Run {
|
||||
/// with bandwidth credential requirement.
|
||||
#[clap(long, hide = true)]
|
||||
enabled_credentials_mode: Option<bool>,
|
||||
|
||||
#[clap(long, hide = true, action)]
|
||||
outfox: bool,
|
||||
}
|
||||
|
||||
impl From<Run> for OverrideConfig {
|
||||
@@ -79,6 +83,7 @@ impl From<Run> for OverrideConfig {
|
||||
no_cover: run_config.no_cover,
|
||||
nyxd_urls: run_config.nyxd_urls,
|
||||
enabled_credentials_mode: run_config.enabled_credentials_mode,
|
||||
outfox: run_config.outfox,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,6 +113,10 @@ fn version_check(cfg: &Config) -> bool {
|
||||
pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let id = &args.id;
|
||||
|
||||
// in case we're using old config, try to upgrade it
|
||||
// (if we're using the current version, it's a no-op)
|
||||
try_upgrade_v1_1_13_config(id)?;
|
||||
|
||||
let mut config = match Config::load_from_file(id) {
|
||||
Ok(cfg) => cfg,
|
||||
Err(err) => {
|
||||
@@ -118,6 +127,10 @@ pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn std::error::Error
|
||||
}
|
||||
};
|
||||
|
||||
if !config.validate() {
|
||||
return Err(Box::new(Socks5ClientError::ConfigValidationFailure));
|
||||
}
|
||||
|
||||
let override_config_fields = OverrideConfig::from(args.clone());
|
||||
config = override_config(config, override_config_fields);
|
||||
|
||||
@@ -130,5 +143,6 @@ pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn std::error::Error
|
||||
return Err(Box::new(Socks5ClientError::FailedLocalVersionCheck));
|
||||
}
|
||||
|
||||
NymClient::new(config).run_forever().await
|
||||
let storage = OnDiskPersistent::from_config(config.get_base()).await?;
|
||||
NymClient::new(config, storage).run_forever().await
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::{Config, MISSING_VALUE};
|
||||
|
||||
use nym_bin_common::version_checker::Version;
|
||||
use nym_config::NymConfig;
|
||||
use nym_socks5_client_core::config::{Config, MISSING_VALUE};
|
||||
|
||||
use clap::Args;
|
||||
use std::{fmt::Display, process};
|
||||
|
||||
@@ -1,39 +1,23 @@
|
||||
use crate::socks::types::SocksProxyError;
|
||||
use client_core::error::ClientCoreError;
|
||||
use socks5_requests::{ConnectionError, ConnectionId};
|
||||
use nym_client_core::error::ClientCoreError;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Socks5ClientError {
|
||||
#[error("I/O error: {0}")]
|
||||
IoError(#[from] std::io::Error),
|
||||
|
||||
#[error("client-core error: {0}")]
|
||||
ClientCoreError(#[from] ClientCoreError),
|
||||
|
||||
#[error("SOCKS proxy error")]
|
||||
SocksProxyError(SocksProxyError),
|
||||
|
||||
#[error("Failed to load config for: {0}")]
|
||||
FailedToLoadConfig(String),
|
||||
|
||||
// TODO: add more details here
|
||||
#[error("Failed to validate the loaded config")]
|
||||
ConfigValidationFailure,
|
||||
|
||||
#[error("Failed local version check, client and config mismatch")]
|
||||
FailedLocalVersionCheck,
|
||||
|
||||
#[error("Fail to bind address")]
|
||||
FailToBindAddress,
|
||||
|
||||
#[error("Network requester: connection id {connection_id}: {error}")]
|
||||
NetworkRequesterError {
|
||||
connection_id: ConnectionId,
|
||||
error: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<ConnectionError> for Socks5ClientError {
|
||||
fn from(value: ConnectionError) -> Self {
|
||||
Socks5ClientError::NetworkRequesterError {
|
||||
connection_id: value.connection_id,
|
||||
error: value.network_requester_error,
|
||||
}
|
||||
}
|
||||
#[error("client-core error: {0}")]
|
||||
ClientCoreError(#[from] ClientCoreError),
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod client;
|
||||
pub mod error;
|
||||
pub mod socks;
|
||||
@@ -4,18 +4,16 @@
|
||||
use std::error::Error;
|
||||
|
||||
use clap::{crate_name, crate_version, Parser};
|
||||
use nym_bin_common::logging::{banner, setup_logging};
|
||||
use nym_bin_common::logging::{maybe_print_banner, setup_logging};
|
||||
use nym_network_defaults::setup_env;
|
||||
|
||||
pub mod client;
|
||||
mod commands;
|
||||
pub mod error;
|
||||
pub mod socks;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
setup_logging();
|
||||
println!("{}", banner(crate_name!(), crate_version!()));
|
||||
maybe_print_banner(crate_name!(), crate_version!());
|
||||
|
||||
let args = commands::Cli::parse();
|
||||
setup_env(args.config_env_file.as_ref());
|
||||
|
||||
@@ -1,83 +1,71 @@
|
||||
{
|
||||
"root": true,
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
"node": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2019,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"globals": {
|
||||
"Atomics": "readonly",
|
||||
"SharedArrayBuffer": "readonly"
|
||||
},
|
||||
"plugins": ["prettier", "mocha"],
|
||||
"extends": [
|
||||
"airbnb-base",
|
||||
"airbnb-typescript/base",
|
||||
"prettier"],
|
||||
"rules": {
|
||||
"prettier/prettier": "error",
|
||||
"import/prefer-default-export": "off",
|
||||
"import/no-extraneous-dependencies": [
|
||||
"error",
|
||||
{
|
||||
"devDependencies": [
|
||||
"**/*.test.[jt]s",
|
||||
"**/*.spec.[jt]s"
|
||||
]
|
||||
}
|
||||
],
|
||||
"import/extensions": [
|
||||
"error",
|
||||
"ignorePackages",
|
||||
{
|
||||
"ts": "never",
|
||||
"js": "never"
|
||||
}
|
||||
]
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": "**/*.ts",
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"plugins": ["@typescript-eslint/eslint-plugin"],
|
||||
"extends": [
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
"no-use-before-define": [0],
|
||||
"@typescript-eslint/no-use-before-define": [1],
|
||||
"import/no-unresolved": 0,
|
||||
"import/no-extraneous-dependencies": [
|
||||
"error",
|
||||
{
|
||||
"devDependencies": [
|
||||
"**/*.test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
],
|
||||
"quotes": "off",
|
||||
"@typescript-eslint/quotes": [
|
||||
2,
|
||||
"single",
|
||||
{
|
||||
"avoidEscape": true
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/no-unused-vars": [2, { "argsIgnorePattern": "^_" }]
|
||||
}
|
||||
}
|
||||
"root": true,
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
"node": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2019,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"globals": {
|
||||
"Atomics": "readonly",
|
||||
"SharedArrayBuffer": "readonly"
|
||||
},
|
||||
"plugins": ["prettier", "mocha"],
|
||||
"extends": ["airbnb-base", "airbnb-typescript/base", "prettier"],
|
||||
"rules": {
|
||||
"prettier/prettier": "error",
|
||||
"import/prefer-default-export": "off",
|
||||
"import/no-extraneous-dependencies": [
|
||||
"error",
|
||||
{
|
||||
"devDependencies": ["**/*.test.[jt]s", "**/*.spec.[jt]s"]
|
||||
}
|
||||
],
|
||||
"import/extensions": [
|
||||
"error",
|
||||
"ignorePackages",
|
||||
{
|
||||
"ts": "never",
|
||||
"js": "never"
|
||||
}
|
||||
]
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": "**/*.ts",
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"plugins": ["@typescript-eslint/eslint-plugin"],
|
||||
"extends": ["plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended", "prettier"],
|
||||
"rules": {
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
"no-use-before-define": [0],
|
||||
"@typescript-eslint/no-use-before-define": [1],
|
||||
"import/no-unresolved": 0,
|
||||
"import/no-extraneous-dependencies": [
|
||||
"error",
|
||||
{
|
||||
"devDependencies": ["**/*.test.ts", "**/*.spec.ts"]
|
||||
}
|
||||
],
|
||||
"quotes": "off",
|
||||
"@typescript-eslint/quotes": [
|
||||
2,
|
||||
"single",
|
||||
{
|
||||
"avoidEscape": true
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/no-unused-vars": [2, { "argsIgnorePattern": "^_" }]
|
||||
}
|
||||
}
|
||||
],
|
||||
"ignorePatterns": ["tsconfig.json", "*.d.ts", "dist/**/*", "dist", "node_modules"]
|
||||
}
|
||||
|
||||
@@ -4,4 +4,5 @@ coverage
|
||||
dist
|
||||
docs
|
||||
examples/accounts
|
||||
node_modules
|
||||
node_modules
|
||||
.env
|
||||
@@ -1,3 +1,5 @@
|
||||
coverage
|
||||
node_modules
|
||||
tests
|
||||
tests
|
||||
src
|
||||
type
|
||||
|
||||
+24
-25
@@ -1,40 +1,39 @@
|
||||
Nym Validator Client
|
||||
====================
|
||||
# Nym Validator Client (Typescript)
|
||||
|
||||
A TypeScript client for interacting with CosmWasm smart contracts in Nym validators.
|
||||
A TypeScript client for interacting with CosmWasm smart contracts in Nym validators.
|
||||
|
||||
Running examples
|
||||
-----------------
|
||||
|
||||
With the code checked out, `cd examples`. This folder contains runnable example code that will set up a blockchain and allow you to interact with it through the client.
|
||||
|
||||
Running tests
|
||||
-------------
|
||||
Include the Nym Validator in your project:
|
||||
|
||||
```
|
||||
npm test
|
||||
yarn add @nymproject/nym-validator-client
|
||||
```
|
||||
|
||||
You can also trigger test execution with a test watcher. I don't have the centuries of life left to me that are needed to fight through the arcana of wiring up a working TypeScript mocha triggered execution setup, so for now my Cargo-based hack is:
|
||||
|
||||
Connect to validator and make queries
|
||||
|
||||
```
|
||||
cargo watch -s "cd clients/validator && npm test"
|
||||
import Validator from '@nymproject/nym-validator-client'
|
||||
|
||||
const main = async () => {
|
||||
|
||||
const client = await Validator.connectForQuery(rpcAddress, validatorAddress, prefix, mixnetContractAddress, vestingContractAddress, denom)
|
||||
|
||||
client.getBalance(address)
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
It's ugly but works fine if you have Cargo installed. TypeScript setup help happily accepted here.
|
||||
Connect to validator for performing actions
|
||||
|
||||
Generating Documentation
|
||||
------------------------
|
||||
```
|
||||
import Validator from '@nymproject/nym-validator-client'
|
||||
|
||||
You can generate docs by running `npm run docs`. Generated output will appear in the `docs` directory.
|
||||
const main = async () => {
|
||||
|
||||
Packaging
|
||||
------------------------
|
||||
const client = await Validator.connect(mnemonic, rpcAddress, validatorAddress, prefix, mixnetContractAddress, vestingContractAddress, denom)
|
||||
|
||||
If you're a Nym platform developer who's made changes to the client and wants to re-publish the package to NPM, here's how you do it:
|
||||
const res = await client.send(address, [{ amount: '10000000', denom: 'unym' }]);
|
||||
|
||||
1. Bump the version number (use SemVer)
|
||||
1. `npm run build`
|
||||
1. `npm login` (if you haven't already)
|
||||
1. `npm publish`
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -4,15 +4,23 @@
|
||||
"description": "A TypeScript client for interacting with smart contracts in Nym validators",
|
||||
"repository": "https://github.com/nymtech/nym",
|
||||
"main": "./dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"types": "./dist/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "ts-mocha tests/**/*.test.ts",
|
||||
"build": "rollup -c ./rollup.config.mjs",
|
||||
"build:types": "rollup-type-bundler --dist ./dist/nym-validator-client",
|
||||
"build:prod": "sh ./scripts/build-prod.sh",
|
||||
"test": "ts-mocha -p ./tsconfig.test.json ./src/tests/**/*.test.ts",
|
||||
"testmock": "ts-mocha -p ./tsconfig.test.json ./src/tests/mock/*.test.ts",
|
||||
"coverage": "nyc npm test",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"clean": "rm -rf ./dist",
|
||||
"lint": "eslint",
|
||||
"lint:fix": "eslint --fix",
|
||||
"lint:tsc": "tsc --noEmit",
|
||||
"docs": "typedoc --out docs src/index.ts"
|
||||
},
|
||||
"files": [
|
||||
"./dist/*"
|
||||
],
|
||||
"keywords": [],
|
||||
"author": "Nym Technologies SA (https://nymtech.net)",
|
||||
"contributors": [
|
||||
@@ -21,6 +29,14 @@
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@favware/rollup-type-bundler": "^2.0.0",
|
||||
"@nymproject/types": "^1.0.0",
|
||||
"@rollup/plugin-commonjs": "^24.0.1",
|
||||
"@rollup/plugin-json": "^6.0.0",
|
||||
"@rollup/plugin-typescript": "^11.0.0",
|
||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||
"rollup": "^3.17.2",
|
||||
"rollup-plugin-dts": "^5.2.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.7.0",
|
||||
"@typescript-eslint/parser": "^5.7.0",
|
||||
"eslint": "^7.18.0",
|
||||
@@ -31,21 +47,21 @@
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-mocha": "^10.0.3",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"expect": "^28.1.3",
|
||||
"mocha": "^10.0.0",
|
||||
"prettier": "^2.5.1",
|
||||
"typedoc": "^0.22.13",
|
||||
"prettier": "^2.8.7",
|
||||
"ts-mocha": "^10.0.0",
|
||||
"typescript": "^4.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cosmjs/cosmwasm-stargate": "^0.28.0",
|
||||
"@cosmjs/crypto": "^0.28.0",
|
||||
"@cosmjs/math": "^0.28.0",
|
||||
"@cosmjs/proto-signing": "^0.28.0",
|
||||
"@cosmjs/stargate": "^0.28.0",
|
||||
"@cosmjs/tendermint-rpc": "^0.28.0",
|
||||
"axios": "^0.26.1",
|
||||
"cosmjs-types": "^0.4.1"
|
||||
"typedoc": "^0.22.13",
|
||||
"typescript": "^4.6.2",
|
||||
"cosmjs-types": "^0.4.1",
|
||||
"dotenv": "^16.0.3",
|
||||
"expect": "^28.1.3",
|
||||
"moq.ts": "^7.3.4",
|
||||
"@cosmjs/cosmwasm-stargate": "^0.29.5",
|
||||
"@cosmjs/crypto": "^0.29.5",
|
||||
"@cosmjs/math": "^0.29.5",
|
||||
"@cosmjs/proto-signing": "^0.29.5",
|
||||
"@cosmjs/stargate": "^0.29.5",
|
||||
"@cosmjs/tendermint-rpc": "^0.29.5",
|
||||
"axios": "^1.3.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import typescript from '@rollup/plugin-typescript';
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import json from '@rollup/plugin-json';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
|
||||
export default [
|
||||
{
|
||||
input: './src/index.ts',
|
||||
output: {
|
||||
dir: 'dist/nym-validator-client',
|
||||
format: 'cjs',
|
||||
},
|
||||
plugins: [resolve(), typescript(), commonjs(), json()],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
|
||||
rm -rf ./dist || true
|
||||
rm -rf ../../dist || true
|
||||
|
||||
|
||||
# Bundle application
|
||||
|
||||
yarn build
|
||||
|
||||
# Bundle types
|
||||
|
||||
yarn build:types
|
||||
|
||||
# Build package.json for bundle
|
||||
|
||||
node ./scripts/buildPackageJson.mjs
|
||||
|
||||
# Copy README
|
||||
|
||||
cp README.md dist/nym-validator-client
|
||||
|
||||
# move the output outside of the yarn/npm workspaces
|
||||
|
||||
mv ./dist ../../
|
||||
|
||||
echo "Output can be found in:"
|
||||
realpath ../../dist
|
||||
@@ -0,0 +1,20 @@
|
||||
import * as fs from 'fs';
|
||||
|
||||
// parse the package.json from the SDK, so we can keep fields like the name and version
|
||||
const json = JSON.parse(fs.readFileSync('./package.json').toString());
|
||||
|
||||
// defaults (NB: these are in the output file locations)
|
||||
const main = 'index.js';
|
||||
const types = 'index.d.ts';
|
||||
|
||||
// make a package.json for the bundle
|
||||
const packageJson = {
|
||||
name: json.name,
|
||||
version: json.version,
|
||||
license: json.license,
|
||||
author: json.author,
|
||||
main,
|
||||
types,
|
||||
};
|
||||
|
||||
fs.writeFileSync('./dist/nym-validator-client/package.json', JSON.stringify(packageJson, null, 2));
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Decimal } from '@cosmjs/math';
|
||||
import { Coin } from '@cosmjs/stargate';
|
||||
import { CoinMap } from './types/shared';
|
||||
|
||||
// NARROW NO-BREAK SPACE (U+202F)
|
||||
const thinSpace = '\u202F';
|
||||
@@ -34,15 +35,6 @@ export function nativeToPrintable(nativeValue: string): string {
|
||||
return Decimal.fromAtomics(nativeValue, 6).toString();
|
||||
}
|
||||
|
||||
export interface MappedCoin {
|
||||
readonly denom: string;
|
||||
readonly fractionalDigits: number;
|
||||
}
|
||||
|
||||
export interface CoinMap {
|
||||
readonly [key: string]: MappedCoin;
|
||||
}
|
||||
|
||||
export function nativeCoinToDisplay(coin: Coin, coinMap: CoinMap): Coin {
|
||||
if (!coinMap) return coin;
|
||||
|
||||
|
||||
+248
-75
@@ -1,6 +1,3 @@
|
||||
import { Bip39, Random } from '@cosmjs/crypto';
|
||||
import { DirectSecp256k1HdWallet, EncodeObject } from '@cosmjs/proto-signing';
|
||||
import { coin as cosmosCoin, Coin, DeliverTxResponse, isDeliverTxFailure, StdFee } from '@cosmjs/stargate';
|
||||
import {
|
||||
ExecuteResult,
|
||||
InstantiateOptions,
|
||||
@@ -8,45 +5,47 @@ import {
|
||||
MigrateResult,
|
||||
UploadResult,
|
||||
} from '@cosmjs/cosmwasm-stargate';
|
||||
import SigningClient, { ISigningClient } from './signing-client';
|
||||
import { Bip39, Random } from '@cosmjs/crypto';
|
||||
import { DirectSecp256k1HdWallet, EncodeObject } from '@cosmjs/proto-signing';
|
||||
import { Coin, coin as cosmosCoin, DeliverTxResponse, isDeliverTxFailure, StdFee } from '@cosmjs/stargate';
|
||||
import {
|
||||
ContractStateParams,
|
||||
Delegation,
|
||||
Gateway,
|
||||
GatewayBond,
|
||||
GatewayOwnershipResponse,
|
||||
LayerDistribution,
|
||||
MixnetContractVersion,
|
||||
MixNode,
|
||||
MixNodeBond,
|
||||
MixNodeCostParams,
|
||||
MixNodeDetails,
|
||||
MixNodeRewarding,
|
||||
MixOwnershipResponse,
|
||||
OriginalVestingResponse,
|
||||
PagedAllDelegationsResponse,
|
||||
PagedDelegatorDelegationsResponse,
|
||||
PagedGatewayResponse,
|
||||
PagedMixDelegationsResponse,
|
||||
PagedMixnodeResponse,
|
||||
} from './types';
|
||||
import {
|
||||
CoinMap,
|
||||
displayAmountToNative,
|
||||
MappedCoin,
|
||||
nativeCoinToDisplay,
|
||||
nativeToPrintable,
|
||||
printableBalance,
|
||||
printableCoin,
|
||||
} from './currency';
|
||||
PagedMixNodeBondResponse,
|
||||
PagedMixNodeDetailsResponse,
|
||||
PagedUnbondedMixnodesResponse,
|
||||
RewardingParams,
|
||||
StakeSaturationResponse,
|
||||
UnbondedMixnodeResponse,
|
||||
VestingAccountInfo,
|
||||
ContractState,
|
||||
VestingAccountsCoinPaged,
|
||||
VestingAccountsPaged,
|
||||
DelegationTimes,
|
||||
Delegations,
|
||||
Period,
|
||||
VestingAccountNode,
|
||||
DelegationBlock,
|
||||
} from '@nymproject/types';
|
||||
import QueryClient from './query-client';
|
||||
import { nymGasPrice } from './stargate-helper';
|
||||
|
||||
export { coins, coin } from '@cosmjs/stargate';
|
||||
export { Coin };
|
||||
export {
|
||||
displayAmountToNative,
|
||||
nativeCoinToDisplay,
|
||||
printableCoin,
|
||||
printableBalance,
|
||||
nativeToPrintable,
|
||||
MappedCoin,
|
||||
CoinMap,
|
||||
};
|
||||
export { nymGasPrice };
|
||||
import SigningClient, { ISigningClient } from './signing-client';
|
||||
// import { DelegationBlock } from './types/shared';
|
||||
|
||||
export interface INymClient {
|
||||
readonly mixnetContract: string;
|
||||
@@ -147,7 +146,7 @@ export default class ValidatorClient implements INymClient {
|
||||
return DirectSecp256k1HdWallet.fromMnemonic(mnemonic, signerOptions);
|
||||
}
|
||||
|
||||
getBalance(address: string): Promise<Coin> {
|
||||
async getBalance(address: string): Promise<Coin> {
|
||||
return this.client.getBalance(address, this.denom);
|
||||
}
|
||||
|
||||
@@ -159,15 +158,39 @@ export default class ValidatorClient implements INymClient {
|
||||
return this.client.getCachedMixnodes();
|
||||
}
|
||||
|
||||
async getActiveMixnodes(): Promise<MixNodeBond[]> {
|
||||
async getStakeSaturation(mixId: number): Promise<StakeSaturationResponse> {
|
||||
return this.client.getStakeSaturation(this.mixnetContract, mixId);
|
||||
}
|
||||
|
||||
async getActiveMixnodes(): Promise<MixNodeDetails[]> {
|
||||
return this.client.getActiveMixnodes();
|
||||
}
|
||||
|
||||
async getUnbondedMixNodeInformation(mixId: number): Promise<UnbondedMixnodeResponse> {
|
||||
return this.client.getUnbondedMixNodeInformation(this.mixnetContract, mixId);
|
||||
}
|
||||
|
||||
async getRewardedMixnodes(): Promise<MixNodeBond[]> {
|
||||
return this.client.getRewardedMixnodes();
|
||||
}
|
||||
|
||||
public async getMixnetContractSettings(): Promise<ContractStateParams> {
|
||||
async getMixnodeRewardingDetails(mixId: number): Promise<MixNodeRewarding> {
|
||||
return this.client.getMixnodeRewardingDetails(this.mixnetContract, mixId);
|
||||
}
|
||||
|
||||
async getOwnedMixnode(address: string): Promise<MixOwnershipResponse> {
|
||||
return this.client.getOwnedMixnode(this.mixnetContract, address);
|
||||
}
|
||||
|
||||
async ownsGateway(address: string): Promise<GatewayOwnershipResponse> {
|
||||
return this.client.ownsGateway(this.mixnetContract, address);
|
||||
}
|
||||
|
||||
async getLayerDistribution(): Promise<LayerDistribution> {
|
||||
return this.client.getLayerDistribution(this.mixnetContract);
|
||||
}
|
||||
|
||||
public async getMixnetContractSettings(): Promise<ContractState> {
|
||||
return this.client.getStateParams(this.mixnetContract);
|
||||
}
|
||||
|
||||
@@ -175,29 +198,74 @@ export default class ValidatorClient implements INymClient {
|
||||
return this.client.getContractVersion(this.mixnetContract);
|
||||
}
|
||||
|
||||
public async getRewardPool(): Promise<string> {
|
||||
return this.client.getRewardPool(this.mixnetContract);
|
||||
public async getVestingContractVersion(): Promise<MixnetContractVersion> {
|
||||
return this.client.getContractVersion(this.vestingContract);
|
||||
}
|
||||
|
||||
public async getCirculatingSupply(): Promise<string> {
|
||||
return this.client.getCirculatingSupply(this.mixnetContract);
|
||||
public async getSpendableCoins(vestingAccountAddress: string): Promise<MixnetContractVersion> {
|
||||
return this.client.getSpendableCoins(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getSybilResistancePercent(): Promise<number> {
|
||||
return this.client.getSybilResistancePercent(this.mixnetContract);
|
||||
public async getRewardParams(): Promise<RewardingParams> {
|
||||
return this.client.getRewardParams(this.mixnetContract);
|
||||
}
|
||||
|
||||
public async getIntervalRewardPercent(): Promise<number> {
|
||||
return this.client.getIntervalRewardPercent(this.mixnetContract);
|
||||
async getUnbondedMixNodes(): Promise<UnbondedMixnodeResponse[]> {
|
||||
let mixNodes: UnbondedMixnodeResponse[] = [];
|
||||
const limit = 50;
|
||||
let startAfter;
|
||||
for (;;) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pagedResponse: PagedUnbondedMixnodesResponse = await this.client.getUnbondedMixNodes(
|
||||
this.mixnetContract,
|
||||
limit,
|
||||
startAfter,
|
||||
);
|
||||
|
||||
mixNodes = mixNodes.concat(pagedResponse.nodes);
|
||||
startAfter = pagedResponse.start_next_after;
|
||||
// if `start_next_after` is not set, we're done
|
||||
if (!startAfter) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return mixNodes;
|
||||
}
|
||||
|
||||
public async getAllNyxdMixnodes(): Promise<MixNodeBond[]> {
|
||||
public async getMixNodeBonds(): Promise<MixNodeBond[]> {
|
||||
let mixNodes: MixNodeBond[] = [];
|
||||
const limit = 50;
|
||||
let startAfter;
|
||||
for (; ;) {
|
||||
for (;;) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pagedResponse: PagedMixnodeResponse = await this.client.getMixNodesPaged(this.mixnetContract, limit);
|
||||
const pagedResponse: PagedMixNodeBondResponse = await this.client.getMixNodeBonds(
|
||||
this.mixnetContract,
|
||||
limit,
|
||||
startAfter,
|
||||
);
|
||||
mixNodes = mixNodes.concat(pagedResponse.nodes);
|
||||
startAfter = pagedResponse.start_next_after;
|
||||
// if `start_next_after` is not set, we're done
|
||||
if (!startAfter) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return mixNodes;
|
||||
}
|
||||
|
||||
public async getMixNodesDetailed(): Promise<MixNodeDetails[]> {
|
||||
let mixNodes: MixNodeDetails[] = [];
|
||||
const limit = 50;
|
||||
let startAfter;
|
||||
for (;;) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pagedResponse: PagedMixNodeDetailsResponse = await this.client.getMixNodesDetailed(
|
||||
this.mixnetContract,
|
||||
limit,
|
||||
startAfter,
|
||||
);
|
||||
mixNodes = mixNodes.concat(pagedResponse.nodes);
|
||||
startAfter = pagedResponse.start_next_after;
|
||||
// if `start_next_after` is not set, we're done
|
||||
@@ -210,37 +278,24 @@ export default class ValidatorClient implements INymClient {
|
||||
}
|
||||
|
||||
public async getAllNyxdGateways(): Promise<GatewayBond[]> {
|
||||
let gateways: GatewayBond[] = [];
|
||||
const limit = 50;
|
||||
let startAfter;
|
||||
for (; ;) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pagedResponse: PagedGatewayResponse = await this.client.getGatewaysPaged(this.mixnetContract, limit);
|
||||
gateways = gateways.concat(pagedResponse.nodes);
|
||||
startAfter = pagedResponse.start_next_after;
|
||||
// if `start_next_after` is not set, we're done
|
||||
if (!startAfter) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return gateways;
|
||||
const pagedResponse: PagedGatewayResponse = await this.client.getGatewaysPaged(this.mixnetContract);
|
||||
return pagedResponse.nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets list of all delegations towards particular mixnode.
|
||||
*
|
||||
* @param mixIdentity identity of the node to which the delegation was sent
|
||||
* @param mix_id identity of the node to which the delegation was sent
|
||||
*/
|
||||
public async getAllNyxdSingleMixnodeDelegations(mixIdentity: string): Promise<Delegation[]> {
|
||||
public async getAllNyxdSingleMixnodeDelegations(mix_id: number): Promise<Delegation[]> {
|
||||
let delegations: Delegation[] = [];
|
||||
const limit = 250;
|
||||
let startAfter;
|
||||
for (; ;) {
|
||||
for (;;) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pagedResponse: PagedMixDelegationsResponse = await this.client.getMixNodeDelegationsPaged(
|
||||
this.mixnetContract,
|
||||
mixIdentity,
|
||||
mix_id,
|
||||
limit,
|
||||
startAfter,
|
||||
);
|
||||
@@ -259,7 +314,7 @@ export default class ValidatorClient implements INymClient {
|
||||
let delegations: Delegation[] = [];
|
||||
const limit = 250;
|
||||
let startAfter;
|
||||
for (; ;) {
|
||||
for (;;) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pagedResponse: PagedDelegatorDelegationsResponse = await this.client.getDelegatorDelegationsPaged(
|
||||
this.mixnetContract,
|
||||
@@ -278,13 +333,13 @@ export default class ValidatorClient implements INymClient {
|
||||
return delegations;
|
||||
}
|
||||
|
||||
public async getAllNyxdNetworkDelegations(): Promise<Delegation[]> {
|
||||
public async getAllNyxdDelegations(): Promise<Delegation[]> {
|
||||
let delegations: Delegation[] = [];
|
||||
const limit = 250;
|
||||
let startAfter;
|
||||
for (; ;) {
|
||||
for (;;) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pagedResponse: PagedAllDelegationsResponse = await this.client.getAllNetworkDelegationsPaged(
|
||||
const pagedResponse: PagedAllDelegationsResponse = await this.client.getAllDelegationsPaged(
|
||||
this.mixnetContract,
|
||||
limit,
|
||||
startAfter,
|
||||
@@ -300,6 +355,10 @@ export default class ValidatorClient implements INymClient {
|
||||
return delegations;
|
||||
}
|
||||
|
||||
public async getDelegationDetails(mix_id: number, delegator: string): Promise<Delegation> {
|
||||
return this.client.getDelegationDetails(this.mixnetContract, mix_id, delegator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a minimum gateway bond required to create a fresh mixnode.
|
||||
*
|
||||
@@ -308,7 +367,7 @@ export default class ValidatorClient implements INymClient {
|
||||
public async minimumMixnodePledge(): Promise<Coin> {
|
||||
const stateParams = await this.getMixnetContractSettings();
|
||||
// we trust the contract to return a valid number
|
||||
return cosmosCoin(stateParams.minimum_mixnode_pledge, this.prefix);
|
||||
return cosmosCoin(stateParams.params.minimum_mixnode_pledge, this.prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -319,7 +378,7 @@ export default class ValidatorClient implements INymClient {
|
||||
public async minimumGatewayPledge(): Promise<Coin> {
|
||||
const stateParams = await this.getMixnetContractSettings();
|
||||
// we trust the contract to return a valid number
|
||||
return cosmosCoin(stateParams.minimum_gateway_pledge, this.prefix);
|
||||
return cosmosCoin(stateParams.params.minimum_gateway_pledge, this.prefix);
|
||||
}
|
||||
|
||||
public async send(
|
||||
@@ -393,12 +452,21 @@ export default class ValidatorClient implements INymClient {
|
||||
public async bondMixNode(
|
||||
mixNode: MixNode,
|
||||
ownerSignature: string,
|
||||
costParams: MixNodeCostParams,
|
||||
pledge: Coin,
|
||||
fee?: StdFee | 'auto' | number,
|
||||
memo?: string,
|
||||
): Promise<ExecuteResult> {
|
||||
this.assertSigning();
|
||||
return (this.client as ISigningClient).bondMixNode(this.mixnetContract, mixNode, ownerSignature, pledge, fee, memo);
|
||||
return (this.client as ISigningClient).bondMixNode(
|
||||
this.mixnetContract,
|
||||
mixNode,
|
||||
costParams,
|
||||
ownerSignature,
|
||||
pledge,
|
||||
fee,
|
||||
memo,
|
||||
);
|
||||
}
|
||||
|
||||
public async unbondMixNode(fee?: StdFee | 'auto' | number, memo?: string): Promise<ExecuteResult> {
|
||||
@@ -423,29 +491,29 @@ export default class ValidatorClient implements INymClient {
|
||||
}
|
||||
|
||||
public async delegateToMixNode(
|
||||
mixIdentity: string,
|
||||
mixId: number,
|
||||
amount: Coin,
|
||||
fee?: StdFee | 'auto' | number,
|
||||
memo?: string,
|
||||
): Promise<ExecuteResult> {
|
||||
this.assertSigning();
|
||||
return (this.client as ISigningClient).delegateToMixNode(this.mixnetContract, mixIdentity, amount, fee, memo);
|
||||
return (this.client as ISigningClient).delegateToMixNode(this.mixnetContract, mixId, amount, fee, memo);
|
||||
}
|
||||
|
||||
public async undelegateFromMixNode(
|
||||
mixIdentity: string,
|
||||
mixId: number,
|
||||
fee?: StdFee | 'auto' | number,
|
||||
memo?: string,
|
||||
): Promise<ExecuteResult> {
|
||||
return (this.client as ISigningClient).undelegateFromMixNode(this.mixnetContract, mixIdentity, fee, memo);
|
||||
return (this.client as ISigningClient).undelegateFromMixNode(this.mixnetContract, mixId, fee, memo);
|
||||
}
|
||||
|
||||
public async updateMixnodeConfig(
|
||||
mixIdentity: string,
|
||||
mixId: number,
|
||||
fee: StdFee | 'auto' | number,
|
||||
profitPercentage: number,
|
||||
): Promise<ExecuteResult> {
|
||||
return (this.client as ISigningClient).updateMixnodeConfig(this.mixnetContract, mixIdentity, profitPercentage, fee);
|
||||
return (this.client as ISigningClient).updateMixnodeConfig(this.mixnetContract, mixId, profitPercentage, fee);
|
||||
}
|
||||
|
||||
public async updateContractStateParams(
|
||||
@@ -456,4 +524,109 @@ export default class ValidatorClient implements INymClient {
|
||||
this.assertSigning();
|
||||
return (this.client as ISigningClient).updateContractStateParams(this.mixnetContract, newParams, fee, memo);
|
||||
}
|
||||
|
||||
// VESTING
|
||||
// TODO - MOVE TO A DIFFERENT FILE
|
||||
|
||||
public async getVestingAccountsPaged(): Promise<VestingAccountsPaged> {
|
||||
return this.client.getVestingAccountsPaged(this.vestingContract);
|
||||
}
|
||||
|
||||
public async getVestingAmountsAccountsPaged(): Promise<VestingAccountsCoinPaged> {
|
||||
return this.client.getVestingAmountsAccountsPaged(this.vestingContract);
|
||||
}
|
||||
|
||||
public async getLockedTokens(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getLockedTokens(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getSpendableTokens(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getSpendableTokens(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getVestedTokens(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getVestedTokens(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getVestingTokens(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getVestingTokens(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getSpendableVestedTokens(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getSpendableVestedTokens(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getSpendableRewards(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getSpendableRewards(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getDelegatedCoins(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getDelegatedCoins(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getPledgedCoins(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getPledgedCoins(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getStakedCoins(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getStakedCoins(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getWithdrawnCoins(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getWithdrawnCoins(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getStartTime(vestingAccountAddress: string): Promise<string> {
|
||||
return this.client.getStartTime(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getEndTime(vestingAccountAddress: string): Promise<string> {
|
||||
return this.client.getEndTime(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getOriginalVestingDetails(vestingAccountAddress: string): Promise<OriginalVestingResponse> {
|
||||
return this.client.getOriginalVestingDetails(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getHistoricStakingRewards(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getHistoricStakingRewards(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getAccountDetails(address: string): Promise<VestingAccountInfo> {
|
||||
return this.client.getAccountDetails(this.vestingContract, address);
|
||||
}
|
||||
|
||||
public async getMixnode(address: string): Promise<VestingAccountNode> {
|
||||
return this.client.getMixnode(this.vestingContract, address);
|
||||
}
|
||||
|
||||
public async getGateway(address: string): Promise<VestingAccountNode> {
|
||||
return this.client.getGateway(this.vestingContract, address);
|
||||
}
|
||||
|
||||
public async getDelegationTimes(mix_id: number, delegatorAddress: string): Promise<DelegationTimes> {
|
||||
return this.client.getDelegationTimes(this.vestingContract, mix_id, delegatorAddress);
|
||||
}
|
||||
|
||||
public async getAllDelegations(): Promise<Delegations> {
|
||||
return this.client.getAllDelegations(this.vestingContract);
|
||||
}
|
||||
|
||||
public async getDelegation(address: string, mix_id: number): Promise<DelegationBlock> {
|
||||
return this.client.getDelegation(this.vestingContract, address, mix_id);
|
||||
}
|
||||
|
||||
public async getTotalDelegationAmount(address: string, mix_id: number, block_timestamp_sec: number): Promise<Coin> {
|
||||
return this.client.getTotalDelegationAmount(this.vestingContract, address, mix_id, block_timestamp_sec);
|
||||
}
|
||||
|
||||
public async getCurrentVestingPeriod(address: string): Promise<Period> {
|
||||
return this.client.getCurrentVestingPeriod(this.vestingContract, address);
|
||||
}
|
||||
|
||||
// SIMULATE
|
||||
|
||||
public async simulateSend(signingAddress: string, from: string, to: string, amount: Coin[]) {
|
||||
return (this.client as SigningClient).simulateSend(signingAddress, from, to, amount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
* Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import axios from 'axios';
|
||||
import { GatewayBond, MixNodeBond } from './types';
|
||||
import { GatewayBond, MixNodeBond, MixNodeDetails } from '@nymproject/types';
|
||||
|
||||
export const NYM_API_VERSION = '/v1';
|
||||
export const NYM_API_GATEWAYS_PATH = `${NYM_API_VERSION}/gateways`;
|
||||
@@ -17,7 +16,7 @@ export interface INymApiQuery {
|
||||
|
||||
getCachedGateways(): Promise<GatewayBond[]>;
|
||||
|
||||
getActiveMixnodes(): Promise<MixNodeBond[]>;
|
||||
getActiveMixnodes(): Promise<MixNodeDetails[]>;
|
||||
|
||||
getRewardedMixnodes(): Promise<MixNodeBond[]>;
|
||||
}
|
||||
@@ -51,7 +50,7 @@ export default class NymApiQuerier implements INymApiQuery {
|
||||
throw new Error('None of the provided validator APIs seem to be alive');
|
||||
}
|
||||
|
||||
async getActiveMixnodes(): Promise<MixNodeBond[]> {
|
||||
async getActiveMixnodes(): Promise<MixNodeDetails[]> {
|
||||
const url = new URL(this.nymApiUrl);
|
||||
url.pathname += NYM_API_ACTIVE_MIXNODES_PATH;
|
||||
|
||||
|
||||
@@ -2,28 +2,26 @@
|
||||
* Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { JsonObject } from '@cosmjs/cosmwasm-stargate';
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
import { INyxdQuery } from './query-client';
|
||||
import {
|
||||
ContractStateParams,
|
||||
Delegation,
|
||||
Delegation, OriginalVestingResponse, RewardingParams, StakeSaturationResponse, VestingAccountInfo,
|
||||
UnbondedMixnodeResponse,
|
||||
GatewayOwnershipResponse,
|
||||
LayerDistribution,
|
||||
MixnetContractVersion,
|
||||
MixOwnershipResponse,
|
||||
PagedAllDelegationsResponse,
|
||||
PagedDelegatorDelegationsResponse,
|
||||
PagedGatewayResponse,
|
||||
PagedMixDelegationsResponse,
|
||||
PagedMixnodeResponse,
|
||||
RewardingStatus,
|
||||
} from './types';
|
||||
|
||||
interface SmartContractQuery {
|
||||
queryContractSmart(address: string, queryMsg: Record<string, unknown>): Promise<JsonObject>;
|
||||
}
|
||||
PagedMixNodeBondResponse,
|
||||
PagedMixNodeDetailsResponse,
|
||||
PagedUnbondedMixnodesResponse,
|
||||
LayerDistribution,
|
||||
ContractState, VestingAccountsCoinPaged, VestingAccountsPaged, DelegationTimes, Delegations, Period, VestingAccountNode, DelegationBlock
|
||||
} from '@nymproject/types';
|
||||
import { SmartContractQuery } from './types/shared';
|
||||
import { Coin } from 'cosmjs-types/cosmos/base/v1beta1/coin';
|
||||
|
||||
export default class NyxdQuerier implements INyxdQuery {
|
||||
client: SmartContractQuery;
|
||||
@@ -38,15 +36,44 @@ export default class NyxdQuerier implements INyxdQuery {
|
||||
});
|
||||
}
|
||||
|
||||
getMixNodesPaged(mixnetContractAddress: string, limit?: number, startAfter?: string): Promise<PagedMixnodeResponse> {
|
||||
getMixNodeBonds(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixNodeBondResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_mix_nodes: {
|
||||
get_mix_node_bonds: {
|
||||
limit,
|
||||
start_after: startAfter,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
getMixNodesDetailed(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixNodeDetailsResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_mix_nodes_detailed: {
|
||||
limit,
|
||||
start_after: startAfter,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
getStakeSaturation(mixnetContractAddress: string, mixId: number): Promise<StakeSaturationResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_stake_saturation: { mix_id: mixId },
|
||||
});
|
||||
}
|
||||
|
||||
getMixnodeRewardingDetails(mixnetContractAddress: string, mixId: number): Promise<any> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_mixnode_rewarding_details: { mix_id: mixId },
|
||||
});
|
||||
}
|
||||
|
||||
getGatewaysPaged(mixnetContractAddress: string, limit?: number, startAfter?: string): Promise<PagedGatewayResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_gateways: {
|
||||
@@ -56,35 +83,51 @@ export default class NyxdQuerier implements INyxdQuery {
|
||||
});
|
||||
}
|
||||
|
||||
ownsMixNode(mixnetContractAddress: string, address: string): Promise<MixOwnershipResponse> {
|
||||
getOwnedMixnode(mixnetContractAddress: string, address: string): Promise<MixOwnershipResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
owns_mixnode: {
|
||||
get_owned_mixnode: {
|
||||
address,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
getUnbondedMixNodes(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedUnbondedMixnodesResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_unbonded_mix_nodes: { limit, start_after: startAfter },
|
||||
});
|
||||
}
|
||||
|
||||
getUnbondedMixNodeInformation(mixnetContractAddress: string, mixId: number): Promise<UnbondedMixnodeResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_unbonded_mix_node_information: { mix_id: mixId },
|
||||
});
|
||||
}
|
||||
|
||||
ownsGateway(mixnetContractAddress: string, address: string): Promise<GatewayOwnershipResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
owns_gateway: {
|
||||
get_owned_gateway: {
|
||||
address,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
getStateParams(mixnetContractAddress: string): Promise<ContractStateParams> {
|
||||
getStateParams(mixnetContractAddress: string): Promise<ContractState> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
state_params: {},
|
||||
get_state: {},
|
||||
});
|
||||
}
|
||||
|
||||
getAllNetworkDelegationsPaged(
|
||||
getAllDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: [string, string],
|
||||
): Promise<PagedAllDelegationsResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_all_network_delegations: {
|
||||
get_all_delegations: {
|
||||
start_after: startAfter,
|
||||
limit,
|
||||
},
|
||||
@@ -93,13 +136,13 @@ export default class NyxdQuerier implements INyxdQuery {
|
||||
|
||||
getMixNodeDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
mixIdentity: string,
|
||||
mix_id: number,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixDelegationsResponse> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_mixnode_delegations: {
|
||||
mix_identity: mixIdentity,
|
||||
mix_id: mix_id,
|
||||
start_after: startAfter,
|
||||
limit,
|
||||
},
|
||||
@@ -121,10 +164,10 @@ export default class NyxdQuerier implements INyxdQuery {
|
||||
});
|
||||
}
|
||||
|
||||
getDelegationDetails(mixnetContractAddress: string, mixIdentity: string, delegator: string): Promise<Delegation> {
|
||||
getDelegationDetails(mixnetContractAddress: string, mix_id: number, delegator: string): Promise<Delegation> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_delegation_details: {
|
||||
mix_identity: mixIdentity,
|
||||
mix_id: mix_id,
|
||||
delegator,
|
||||
},
|
||||
});
|
||||
@@ -132,44 +175,163 @@ export default class NyxdQuerier implements INyxdQuery {
|
||||
|
||||
getLayerDistribution(mixnetContractAddress: string): Promise<LayerDistribution> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
layer_distribution: {},
|
||||
get_layer_distribution: {},
|
||||
});
|
||||
}
|
||||
|
||||
getRewardPool(mixnetContractAddress: string): Promise<string> {
|
||||
getRewardParams(mixnetContractAddress: string): Promise<RewardingParams> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_reward_pool: {},
|
||||
get_rewarding_params: {},
|
||||
});
|
||||
}
|
||||
|
||||
getCirculatingSupply(mixnetContractAddress: string): Promise<string> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_circulating_supply: {},
|
||||
getSpendableCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<any> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
vesting_account_address: vestingAccountAddress,
|
||||
});
|
||||
}
|
||||
|
||||
getIntervalRewardPercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_interval_reward_percent: {},
|
||||
getVestingAccountsPaged(vestingContractAddress: string): Promise<VestingAccountsPaged> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_accounts_paged: {}
|
||||
});
|
||||
}
|
||||
|
||||
getSybilResistancePercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_sybil_resistance_percent: {},
|
||||
getVestingAmountsAccountsPaged(vestingContractAddress: string): Promise<VestingAccountsCoinPaged> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_accounts_vesting_coins_paged: {}
|
||||
});
|
||||
}
|
||||
|
||||
getRewardingStatus(
|
||||
mixnetContractAddress: string,
|
||||
mixIdentity: string,
|
||||
rewardingIntervalNonce: number,
|
||||
): Promise<RewardingStatus> {
|
||||
return this.client.queryContractSmart(mixnetContractAddress, {
|
||||
get_rewarding_status: {
|
||||
mix_identity: mixIdentity,
|
||||
rewarding_interval_nonce: rewardingIntervalNonce,
|
||||
},
|
||||
getLockedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
locked_coins: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getSpendableTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
spendable_coins: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getVestedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_vested_coins: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getVestingTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_vesting_coins: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getSpendableVestedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_spendable_vested_coins: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getSpendableRewards(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_spendable_reward_coins: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getDelegatedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_delegated_coins: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getPledgedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_pledged_coins: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getStakedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_staked_coins: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getWithdrawnCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_withdrawn_coins: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getStartTime(vestingContractAddress: string, vestingAccountAddress: string): Promise<string> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_start_time: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getEndTime(vestingContractAddress: string, vestingAccountAddress: string): Promise<string> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_end_time: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getOriginalVestingDetails(vestingContractAddress: string, vestingAccountAddress: string): Promise<OriginalVestingResponse> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_original_vesting: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getHistoricStakingRewards(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_historical_vesting_staking_reward: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getAccountDetails(vestingContractAddress: string, address: string): Promise<VestingAccountInfo> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_account: { address: address }
|
||||
});
|
||||
}
|
||||
|
||||
getMixnode(vestingContractAddress: string, address: string): Promise<VestingAccountNode> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_mixnode: { address: address }
|
||||
});
|
||||
}
|
||||
|
||||
getGateway(vestingContractAddress: string, address: string): Promise<VestingAccountNode> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_gateway: { address: address }
|
||||
});
|
||||
}
|
||||
|
||||
getDelegationTimes(vestingContractAddress: string, mix_id: number, address: string): Promise<DelegationTimes> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_delegation_times: { mix_id: mix_id, address: address }
|
||||
});
|
||||
}
|
||||
|
||||
getAllDelegations(vestingContractAddress: string): Promise<Delegations> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_all_delegations: {}
|
||||
});
|
||||
}
|
||||
|
||||
getDelegation(vestingContractAddress: string, address: string, mix_id: number): Promise<DelegationBlock> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_all_delegations: {address: address, mix_id: mix_id}
|
||||
});
|
||||
}
|
||||
|
||||
getTotalDelegationAmount(vestingContractAddress: string, address: string, mix_id: number, block_timestamp_sec: number): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_all_delegations: {address: address, mix_id: mix_id, block_timestamp_sec: block_timestamp_sec}
|
||||
});
|
||||
}
|
||||
|
||||
getCurrentVestingPeriod(vestingContractAddress: string, address: string): Promise<Period> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_current_vesting_period: { address: address }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,75 +1,60 @@
|
||||
import { CosmWasmClient, JsonObject } from '@cosmjs/cosmwasm-stargate';
|
||||
import { Tendermint34Client } from '@cosmjs/tendermint-rpc';
|
||||
import {
|
||||
Account,
|
||||
Block,
|
||||
Coin,
|
||||
DeliverTxResponse,
|
||||
IndexedTx,
|
||||
SearchTxFilter,
|
||||
SearchTxQuery,
|
||||
SequenceResponse,
|
||||
} from '@cosmjs/stargate';
|
||||
import { Code, CodeDetails, Contract, ContractCodeHistoryEntry } from '@cosmjs/cosmwasm-stargate/build/cosmwasmclient';
|
||||
import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate';
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
import NyxdQuerier from './nyxd-querier';
|
||||
import {
|
||||
ContractStateParams,
|
||||
Delegation,
|
||||
GatewayBond,
|
||||
GatewayOwnershipResponse,
|
||||
LayerDistribution,
|
||||
MixnetContractVersion,
|
||||
MixNodeBond,
|
||||
MixNodeDetails,
|
||||
MixOwnershipResponse,
|
||||
PagedAllDelegationsResponse,
|
||||
PagedDelegatorDelegationsResponse,
|
||||
PagedGatewayResponse,
|
||||
PagedMixDelegationsResponse,
|
||||
PagedMixnodeResponse,
|
||||
RewardingStatus,
|
||||
} from './types';
|
||||
import NymApiQuerier, { INymApiQuery as INymApiQuery } from './nym-api-querier';
|
||||
|
||||
export interface ICosmWasmQuery {
|
||||
// methods exposed by `CosmWasmClient`
|
||||
getChainId(): Promise<string>;
|
||||
getHeight(): Promise<number>;
|
||||
getAccount(searchAddress: string): Promise<Account | null>;
|
||||
getSequence(address: string): Promise<SequenceResponse>;
|
||||
getBlock(height?: number): Promise<Block>;
|
||||
getBalance(address: string, searchDenom: string): Promise<Coin>;
|
||||
getTx(id: string): Promise<IndexedTx | null>;
|
||||
searchTx(query: SearchTxQuery, filter?: SearchTxFilter): Promise<readonly IndexedTx[]>;
|
||||
disconnect(): void;
|
||||
broadcastTx(tx: Uint8Array, timeoutMs?: number, pollIntervalMs?: number): Promise<DeliverTxResponse>;
|
||||
getCodes(): Promise<readonly Code[]>;
|
||||
getCodeDetails(codeId: number): Promise<CodeDetails>;
|
||||
getContracts(codeId: number): Promise<readonly string[]>;
|
||||
getContract(address: string): Promise<Contract>;
|
||||
getContractCodeHistory(address: string): Promise<readonly ContractCodeHistoryEntry[]>;
|
||||
queryContractRaw(address: string, key: Uint8Array): Promise<Uint8Array | null>;
|
||||
queryContractSmart(address: string, queryMsg: Record<string, unknown>): Promise<JsonObject>;
|
||||
}
|
||||
PagedMixNodeBondResponse,
|
||||
PagedMixNodeDetailsResponse,
|
||||
PagedUnbondedMixnodesResponse,
|
||||
StakeSaturationResponse,
|
||||
UnbondedMixnodeResponse,
|
||||
MixNodeBond,
|
||||
MixNodeRewarding,
|
||||
OriginalVestingResponse,
|
||||
VestingAccountInfo,
|
||||
ContractState, VestingAccountsCoinPaged, VestingAccountsPaged, DelegationTimes, Delegations, Period, VestingAccountNode, DelegationBlock
|
||||
} from '@nymproject/types';
|
||||
import NymApiQuerier, { INymApiQuery } from './nym-api-querier';
|
||||
import { ICosmWasmQuery } from './types/shared';
|
||||
import { RewardingParams } from '@nymproject/types';
|
||||
import { Tendermint34Client } from '@cosmjs/tendermint-rpc';
|
||||
import { Coin } from 'cosmjs-types/cosmos/base/v1beta1/coin';
|
||||
|
||||
export interface INyxdQuery {
|
||||
// nym-specific implemented inside NymQuerier
|
||||
getContractVersion(mixnetContractAddress: string): Promise<MixnetContractVersion>;
|
||||
|
||||
getMixNodesPaged(mixnetContractAddress: string, limit?: number, startAfter?: string): Promise<PagedMixnodeResponse>;
|
||||
getMixNodeBonds(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixNodeBondResponse>;
|
||||
getMixNodesDetailed(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixNodeDetailsResponse>;
|
||||
getGatewaysPaged(mixnetContractAddress: string, limit?: number, startAfter?: string): Promise<PagedGatewayResponse>;
|
||||
ownsMixNode(mixnetContractAddress: string, address: string): Promise<MixOwnershipResponse>;
|
||||
getOwnedMixnode(mixnetContractAddress: string, address: string): Promise<MixOwnershipResponse>;
|
||||
ownsGateway(mixnetContractAddress: string, address: string): Promise<GatewayOwnershipResponse>;
|
||||
getStateParams(mixnetContractAddress: string): Promise<ContractStateParams>;
|
||||
|
||||
getAllNetworkDelegationsPaged(
|
||||
getStateParams(mixnetContractAddress: string): Promise<ContractState>;
|
||||
getAllDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: [string, string],
|
||||
): Promise<PagedAllDelegationsResponse>;
|
||||
getMixNodeDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
mixIdentity: string,
|
||||
mix_id: number,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixDelegationsResponse>;
|
||||
@@ -79,18 +64,12 @@ export interface INyxdQuery {
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedDelegatorDelegationsResponse>;
|
||||
getDelegationDetails(mixnetContractAddress: string, mixIdentity: string, delegator: string): Promise<Delegation>;
|
||||
|
||||
getDelegationDetails(mixnetContractAddress: string, mix_id: number, delegator: string): Promise<Delegation>;
|
||||
getLayerDistribution(mixnetContractAddress: string): Promise<LayerDistribution>;
|
||||
getRewardPool(mixnetContractAddress: string): Promise<string>;
|
||||
getCirculatingSupply(mixnetContractAddress: string): Promise<string>;
|
||||
getIntervalRewardPercent(mixnetContractAddress: string): Promise<number>;
|
||||
getSybilResistancePercent(mixnetContractAddress: string): Promise<number>;
|
||||
getRewardingStatus(
|
||||
mixnetContractAddress: string,
|
||||
mixIdentity: string,
|
||||
rewardingIntervalNonce: number,
|
||||
): Promise<RewardingStatus>;
|
||||
getRewardParams(mixnetContractAddress: string): Promise<RewardingParams>;
|
||||
getStakeSaturation(mixnetContractAddress: string, mixId: number): Promise<StakeSaturationResponse>;
|
||||
getUnbondedMixNodeInformation(mixnetContractAddress: string, mixId: number): Promise<UnbondedMixnodeResponse>;
|
||||
getMixnodeRewardingDetails(mixnetContractAddress: string, mixId: number): Promise<MixNodeRewarding>;
|
||||
}
|
||||
|
||||
export interface IQueryClient extends ICosmWasmQuery, INyxdQuery, INymApiQuery { }
|
||||
@@ -115,41 +94,73 @@ export default class QueryClient extends CosmWasmClient implements IQueryClient
|
||||
return this.nyxdQuerier.getContractVersion(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getMixNodesPaged(mixnetContractAddress: string, limit?: number, startAfter?: string): Promise<PagedMixnodeResponse> {
|
||||
return this.nyxdQuerier.getMixNodesPaged(mixnetContractAddress, limit, startAfter);
|
||||
getMixNodeBonds(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixNodeBondResponse> {
|
||||
return this.nyxdQuerier.getMixNodeBonds(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
getMixNodesDetailed(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixNodeDetailsResponse> {
|
||||
return this.nyxdQuerier.getMixNodesDetailed(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
getStakeSaturation(mixnetContractAddress: string, mixId: number): Promise<StakeSaturationResponse> {
|
||||
return this.nyxdQuerier.getStakeSaturation(mixnetContractAddress, mixId);
|
||||
}
|
||||
|
||||
getMixnodeRewardingDetails(mixnetContractAddress: string, mixId: number): Promise<MixNodeRewarding> {
|
||||
return this.nyxdQuerier.getMixnodeRewardingDetails(mixnetContractAddress, mixId);
|
||||
}
|
||||
|
||||
getGatewaysPaged(mixnetContractAddress: string, limit?: number, startAfter?: string): Promise<PagedGatewayResponse> {
|
||||
return this.nyxdQuerier.getGatewaysPaged(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
ownsMixNode(mixnetContractAddress: string, address: string): Promise<MixOwnershipResponse> {
|
||||
return this.nyxdQuerier.ownsMixNode(mixnetContractAddress, address);
|
||||
getOwnedMixnode(mixnetContractAddress: string, address: string): Promise<MixOwnershipResponse> {
|
||||
return this.nyxdQuerier.getOwnedMixnode(mixnetContractAddress, address);
|
||||
}
|
||||
|
||||
ownsGateway(mixnetContractAddress: string, address: string): Promise<GatewayOwnershipResponse> {
|
||||
return this.nyxdQuerier.ownsGateway(mixnetContractAddress, address);
|
||||
}
|
||||
|
||||
getStateParams(mixnetContractAddress: string): Promise<ContractStateParams> {
|
||||
getUnbondedMixNodes(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedUnbondedMixnodesResponse> {
|
||||
return this.nyxdQuerier.getUnbondedMixNodes(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
getUnbondedMixNodeInformation(mixnetContractAddress: string, mixId: number): Promise<UnbondedMixnodeResponse> {
|
||||
return this.nyxdQuerier.getUnbondedMixNodeInformation(mixnetContractAddress, mixId);
|
||||
}
|
||||
|
||||
getStateParams(mixnetContractAddress: string): Promise<ContractState> {
|
||||
return this.nyxdQuerier.getStateParams(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getAllNetworkDelegationsPaged(
|
||||
getAllDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: [string, string],
|
||||
): Promise<PagedAllDelegationsResponse> {
|
||||
return this.nyxdQuerier.getAllNetworkDelegationsPaged(mixnetContractAddress, limit, startAfter);
|
||||
return this.nyxdQuerier.getAllDelegationsPaged(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
getMixNodeDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
mixIdentity: string,
|
||||
mix_id: number,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixDelegationsResponse> {
|
||||
return this.nyxdQuerier.getMixNodeDelegationsPaged(mixnetContractAddress, mixIdentity, limit, startAfter);
|
||||
return this.nyxdQuerier.getMixNodeDelegationsPaged(mixnetContractAddress, mix_id, limit, startAfter);
|
||||
}
|
||||
|
||||
getDelegatorDelegationsPaged(
|
||||
@@ -161,36 +172,16 @@ export default class QueryClient extends CosmWasmClient implements IQueryClient
|
||||
return this.nyxdQuerier.getDelegatorDelegationsPaged(mixnetContractAddress, delegator, limit, startAfter);
|
||||
}
|
||||
|
||||
getDelegationDetails(mixnetContractAddress: string, mixIdentity: string, delegator: string): Promise<Delegation> {
|
||||
return this.nyxdQuerier.getDelegationDetails(mixnetContractAddress, mixIdentity, delegator);
|
||||
getDelegationDetails(mixnetContractAddress: string, mix_id: number, delegator: string): Promise<Delegation> {
|
||||
return this.nyxdQuerier.getDelegationDetails(mixnetContractAddress, mix_id, delegator);
|
||||
}
|
||||
|
||||
getLayerDistribution(mixnetContractAddress: string): Promise<LayerDistribution> {
|
||||
return this.nyxdQuerier.getLayerDistribution(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getRewardPool(mixnetContractAddress: string): Promise<string> {
|
||||
return this.nyxdQuerier.getRewardPool(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getCirculatingSupply(mixnetContractAddress: string): Promise<string> {
|
||||
return this.nyxdQuerier.getCirculatingSupply(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getIntervalRewardPercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.nyxdQuerier.getIntervalRewardPercent(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getSybilResistancePercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.nyxdQuerier.getSybilResistancePercent(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getRewardingStatus(
|
||||
mixnetContractAddress: string,
|
||||
mixIdentity: string,
|
||||
rewardingIntervalNonce: number,
|
||||
): Promise<RewardingStatus> {
|
||||
return this.nyxdQuerier.getRewardingStatus(mixnetContractAddress, mixIdentity, rewardingIntervalNonce);
|
||||
getRewardParams(mixnetContractAddress: string): Promise<RewardingParams> {
|
||||
return this.nyxdQuerier.getRewardParams(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getCachedGateways(): Promise<GatewayBond[]> {
|
||||
@@ -201,11 +192,111 @@ export default class QueryClient extends CosmWasmClient implements IQueryClient
|
||||
return this.nymApiQuerier.getCachedMixnodes();
|
||||
}
|
||||
|
||||
getActiveMixnodes(): Promise<MixNodeBond[]> {
|
||||
getActiveMixnodes(): Promise<MixNodeDetails[]> {
|
||||
return this.nymApiQuerier.getActiveMixnodes();
|
||||
}
|
||||
|
||||
getRewardedMixnodes(): Promise<MixNodeBond[]> {
|
||||
return this.nymApiQuerier.getRewardedMixnodes();
|
||||
}
|
||||
|
||||
getSpendableCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<any> {
|
||||
return this.nyxdQuerier.getSpendableCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getVestingAccountsPaged(vestingContractAddress: string): Promise<VestingAccountsPaged> {
|
||||
return this.nyxdQuerier.getVestingAccountsPaged(vestingContractAddress);
|
||||
}
|
||||
|
||||
getVestingAmountsAccountsPaged(vestingContractAddress: string): Promise<VestingAccountsCoinPaged> {
|
||||
return this.nyxdQuerier.getVestingAmountsAccountsPaged(vestingContractAddress);
|
||||
}
|
||||
|
||||
getLockedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getLockedTokens(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getSpendableTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getSpendableTokens(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getVestedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getVestedTokens(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getVestingTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getVestingTokens(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getSpendableVestedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getSpendableVestedTokens(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getSpendableRewards(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getSpendableRewards(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getDelegatedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getDelegatedCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getPledgedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getPledgedCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getStakedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getStakedCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getWithdrawnCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getWithdrawnCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getStartTime(vestingContractAddress: string, vestingAccountAddress: string): Promise<string> {
|
||||
return this.nyxdQuerier.getStartTime(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getEndTime(vestingContractAddress: string, vestingAccountAddress: string): Promise<string> {
|
||||
return this.nyxdQuerier.getEndTime(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getOriginalVestingDetails(vestingContractAddress: string, vestingAccountAddress: string): Promise<OriginalVestingResponse> {
|
||||
return this.nyxdQuerier.getOriginalVestingDetails(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getHistoricStakingRewards(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getHistoricStakingRewards(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getAccountDetails(vestingContractAddress: string, address: string): Promise<VestingAccountInfo> {
|
||||
return this.nyxdQuerier.getAccountDetails(vestingContractAddress, address);
|
||||
}
|
||||
|
||||
getMixnode(vestingContractAddress: string, address: string): Promise<VestingAccountNode> {
|
||||
return this.nyxdQuerier.getMixnode(vestingContractAddress, address);
|
||||
}
|
||||
|
||||
getGateway(vestingContractAddress: string, address: string): Promise<VestingAccountNode> {
|
||||
return this.nyxdQuerier.getGateway(vestingContractAddress, address);
|
||||
}
|
||||
|
||||
getDelegationTimes(vestingContractAddress: string, mix_id: number, delegatorAddress: string): Promise<DelegationTimes> {
|
||||
return this.nyxdQuerier.getDelegationTimes(vestingContractAddress, mix_id, delegatorAddress);
|
||||
}
|
||||
|
||||
getAllDelegations(vestingContractAddress: string): Promise<Delegations> {
|
||||
return this.nyxdQuerier.getAllDelegations(vestingContractAddress);
|
||||
}
|
||||
|
||||
getDelegation(vestingContractAddress: string, vestingAccountAddress: string, mix_id: number): Promise<DelegationBlock> {
|
||||
return this.nyxdQuerier.getDelegation(vestingContractAddress, vestingAccountAddress, mix_id);
|
||||
}
|
||||
|
||||
getTotalDelegationAmount(vestingContractAddress: string, vestingAccountAddress: string, mix_id: number, block_timestamp_sec: number): Promise<Coin> {
|
||||
return this.nyxdQuerier.getTotalDelegationAmount(vestingContractAddress, vestingAccountAddress, mix_id, block_timestamp_sec);
|
||||
}
|
||||
|
||||
getCurrentVestingPeriod(vestingContractAddress: string, address: string): Promise<Period> {
|
||||
return this.nyxdQuerier.getCurrentVestingPeriod(vestingContractAddress, address);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,15 +25,33 @@ import {
|
||||
MixnetContractVersion,
|
||||
MixNode,
|
||||
MixNodeBond,
|
||||
MixNodeCostParams,
|
||||
MixNodeDetails,
|
||||
MixNodeRewarding,
|
||||
MixOwnershipResponse,
|
||||
OriginalVestingResponse,
|
||||
PagedAllDelegationsResponse,
|
||||
PagedDelegatorDelegationsResponse,
|
||||
PagedGatewayResponse,
|
||||
PagedMixDelegationsResponse,
|
||||
PagedMixnodeResponse,
|
||||
RewardingStatus,
|
||||
} from './types';
|
||||
PagedMixNodeBondResponse,
|
||||
PagedMixNodeDetailsResponse,
|
||||
PagedUnbondedMixnodesResponse,
|
||||
RewardingParams,
|
||||
UnbondedMixnodeResponse,
|
||||
VestingAccountInfo,
|
||||
ContractState,
|
||||
VestingAccountsCoinPaged,
|
||||
VestingAccountsPaged,
|
||||
DelegationTimes,
|
||||
Delegations,
|
||||
Period,
|
||||
VestingAccountNode,
|
||||
DelegationBlock,
|
||||
} from '@nymproject/types';
|
||||
import NymApiQuerier from './nym-api-querier';
|
||||
import { makeBankMsgSend } from './utils';
|
||||
import { ISimulateClient } from './types/simulate';
|
||||
|
||||
// methods exposed by `SigningCosmWasmClient`
|
||||
export interface ICosmWasmSigning {
|
||||
@@ -139,10 +157,11 @@ export interface INymSigning {
|
||||
clientAddress: string;
|
||||
}
|
||||
|
||||
export interface ISigningClient extends IQueryClient, ICosmWasmSigning, INymSigning {
|
||||
export interface ISigningClient extends IQueryClient, ICosmWasmSigning, INymSigning, ISimulateClient {
|
||||
bondMixNode(
|
||||
mixnetContractAddress: string,
|
||||
mixNode: MixNode,
|
||||
costParams: MixNodeCostParams,
|
||||
ownerSignature: string,
|
||||
pledge: Coin,
|
||||
fee?: StdFee | 'auto' | number,
|
||||
@@ -164,7 +183,7 @@ export interface ISigningClient extends IQueryClient, ICosmWasmSigning, INymSign
|
||||
|
||||
delegateToMixNode(
|
||||
mixnetContractAddress: string,
|
||||
mixIdentity: string,
|
||||
mixId: number,
|
||||
amount: Coin,
|
||||
fee?: StdFee | 'auto' | number,
|
||||
memo?: string,
|
||||
@@ -172,14 +191,14 @@ export interface ISigningClient extends IQueryClient, ICosmWasmSigning, INymSign
|
||||
|
||||
undelegateFromMixNode(
|
||||
mixnetContractAddress: string,
|
||||
mixIdentity: string,
|
||||
mixId: number,
|
||||
fee?: StdFee | 'auto' | number,
|
||||
memo?: string,
|
||||
): Promise<ExecuteResult>;
|
||||
|
||||
updateMixnodeConfig(
|
||||
mixnetContractAddress: string,
|
||||
mixIdentity: string,
|
||||
mixId: number,
|
||||
profitMarginPercent: number,
|
||||
fee: StdFee | 'auto' | number,
|
||||
): Promise<ExecuteResult>;
|
||||
@@ -238,41 +257,73 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
return this.nyxdQuerier.getContractVersion(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getMixNodesPaged(mixnetContractAddress: string, limit?: number, startAfter?: string): Promise<PagedMixnodeResponse> {
|
||||
return this.nyxdQuerier.getMixNodesPaged(mixnetContractAddress, limit, startAfter);
|
||||
getMixNodeBonds(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixNodeBondResponse> {
|
||||
return this.nyxdQuerier.getMixNodeBonds(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
getMixNodesDetailed(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixNodeDetailsResponse> {
|
||||
return this.nyxdQuerier.getMixNodesDetailed(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
getStakeSaturation(mixnetContractAddress: string, mixId: number) {
|
||||
return this.nyxdQuerier.getStakeSaturation(mixnetContractAddress, mixId);
|
||||
}
|
||||
|
||||
getUnbondedMixNodeInformation(mixnetContractAddress: string, mixId: number): Promise<UnbondedMixnodeResponse> {
|
||||
return this.nyxdQuerier.getUnbondedMixNodeInformation(mixnetContractAddress, mixId);
|
||||
}
|
||||
|
||||
getMixnodeRewardingDetails(mixnetContractAddress: string, mixId: number): Promise<MixNodeRewarding> {
|
||||
return this.nyxdQuerier.getMixnodeRewardingDetails(mixnetContractAddress, mixId);
|
||||
}
|
||||
|
||||
getGatewaysPaged(mixnetContractAddress: string, limit?: number, startAfter?: string): Promise<PagedGatewayResponse> {
|
||||
return this.nyxdQuerier.getGatewaysPaged(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
ownsMixNode(mixnetContractAddress: string, address: string): Promise<MixOwnershipResponse> {
|
||||
return this.nyxdQuerier.ownsMixNode(mixnetContractAddress, address);
|
||||
getOwnedMixnode(mixnetContractAddress: string, address: string): Promise<MixOwnershipResponse> {
|
||||
return this.nyxdQuerier.getOwnedMixnode(mixnetContractAddress, address);
|
||||
}
|
||||
|
||||
ownsGateway(mixnetContractAddress: string, address: string): Promise<GatewayOwnershipResponse> {
|
||||
return this.nyxdQuerier.ownsGateway(mixnetContractAddress, address);
|
||||
}
|
||||
|
||||
getStateParams(mixnetContractAddress: string): Promise<ContractStateParams> {
|
||||
getStateParams(mixnetContractAddress: string): Promise<ContractState> {
|
||||
return this.nyxdQuerier.getStateParams(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getAllNetworkDelegationsPaged(
|
||||
getAllDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: [string, string],
|
||||
): Promise<PagedAllDelegationsResponse> {
|
||||
return this.nyxdQuerier.getAllNetworkDelegationsPaged(mixnetContractAddress, limit, startAfter);
|
||||
return this.getAllDelegationsPaged(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
getUnbondedMixNodes(
|
||||
mixnetContractAddress: string,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedUnbondedMixnodesResponse> {
|
||||
return this.nyxdQuerier.getUnbondedMixNodes(mixnetContractAddress, limit, startAfter);
|
||||
}
|
||||
|
||||
getMixNodeDelegationsPaged(
|
||||
mixnetContractAddress: string,
|
||||
mixIdentity: string,
|
||||
mix_id: number,
|
||||
limit?: number,
|
||||
startAfter?: string,
|
||||
): Promise<PagedMixDelegationsResponse> {
|
||||
return this.nyxdQuerier.getMixNodeDelegationsPaged(mixnetContractAddress, mixIdentity, limit, startAfter);
|
||||
return this.nyxdQuerier.getMixNodeDelegationsPaged(mixnetContractAddress, mix_id, limit, startAfter);
|
||||
}
|
||||
|
||||
getDelegatorDelegationsPaged(
|
||||
@@ -284,36 +335,16 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
return this.nyxdQuerier.getDelegatorDelegationsPaged(mixnetContractAddress, delegator, limit, startAfter);
|
||||
}
|
||||
|
||||
getDelegationDetails(mixnetContractAddress: string, mixIdentity: string, delegator: string): Promise<Delegation> {
|
||||
return this.nyxdQuerier.getDelegationDetails(mixnetContractAddress, mixIdentity, delegator);
|
||||
getDelegationDetails(mixnetContractAddress: string, mix_id: number, delegator: string): Promise<Delegation> {
|
||||
return this.nyxdQuerier.getDelegationDetails(mixnetContractAddress, mix_id, delegator);
|
||||
}
|
||||
|
||||
getLayerDistribution(mixnetContractAddress: string): Promise<LayerDistribution> {
|
||||
return this.nyxdQuerier.getLayerDistribution(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getRewardPool(mixnetContractAddress: string): Promise<string> {
|
||||
return this.nyxdQuerier.getRewardPool(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getCirculatingSupply(mixnetContractAddress: string): Promise<string> {
|
||||
return this.nyxdQuerier.getCirculatingSupply(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getIntervalRewardPercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.nyxdQuerier.getIntervalRewardPercent(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getSybilResistancePercent(mixnetContractAddress: string): Promise<number> {
|
||||
return this.nyxdQuerier.getSybilResistancePercent(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getRewardingStatus(
|
||||
mixnetContractAddress: string,
|
||||
mixIdentity: string,
|
||||
rewardingIntervalNonce: number,
|
||||
): Promise<RewardingStatus> {
|
||||
return this.nyxdQuerier.getRewardingStatus(mixnetContractAddress, mixIdentity, rewardingIntervalNonce);
|
||||
getRewardParams(mixnetContractAddress: string): Promise<RewardingParams> {
|
||||
return this.nyxdQuerier.getRewardParams(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getCachedGateways(): Promise<GatewayBond[]> {
|
||||
@@ -324,7 +355,7 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
return this.nymApiQuerier.getCachedMixnodes();
|
||||
}
|
||||
|
||||
getActiveMixnodes(): Promise<MixNodeBond[]> {
|
||||
getActiveMixnodes(): Promise<MixNodeDetails[]> {
|
||||
return this.nymApiQuerier.getActiveMixnodes();
|
||||
}
|
||||
|
||||
@@ -332,11 +363,16 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
return this.nymApiQuerier.getRewardedMixnodes();
|
||||
}
|
||||
|
||||
getSpendableCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<any> {
|
||||
return this.nyxdQuerier.getSpendableCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
// signing related:
|
||||
|
||||
bondMixNode(
|
||||
mixnetContractAddress: string,
|
||||
mixNode: MixNode,
|
||||
costParams: MixNodeCostParams,
|
||||
ownerSignature: string,
|
||||
pledge: Coin,
|
||||
fee: StdFee | 'auto' | number = 'auto',
|
||||
@@ -348,6 +384,7 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
{
|
||||
bond_mixnode: {
|
||||
mix_node: mixNode,
|
||||
cost_params: costParams,
|
||||
owner_signature: ownerSignature,
|
||||
},
|
||||
},
|
||||
@@ -414,7 +451,7 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
|
||||
delegateToMixNode(
|
||||
mixnetContractAddress: string,
|
||||
mixIdentity: string,
|
||||
mixId: number,
|
||||
amount: Coin,
|
||||
fee: StdFee | 'auto' | number = 'auto',
|
||||
memo = 'Default MixNode Delegation from Typescript',
|
||||
@@ -424,7 +461,7 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
mixnetContractAddress,
|
||||
{
|
||||
delegate_to_mixnode: {
|
||||
mix_identity: mixIdentity,
|
||||
mix_id: mixId,
|
||||
},
|
||||
},
|
||||
fee,
|
||||
@@ -435,7 +472,7 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
|
||||
undelegateFromMixNode(
|
||||
mixnetContractAddress: string,
|
||||
mixIdentity: string,
|
||||
mixId: number,
|
||||
fee: StdFee | 'auto' | number = 'auto',
|
||||
memo = 'Default MixNode Undelegation from Typescript',
|
||||
): Promise<ExecuteResult> {
|
||||
@@ -444,7 +481,7 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
mixnetContractAddress,
|
||||
{
|
||||
undelegate_from_mixnode: {
|
||||
mix_identity: mixIdentity,
|
||||
mix_id: mixId,
|
||||
},
|
||||
},
|
||||
fee,
|
||||
@@ -454,14 +491,14 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
|
||||
updateMixnodeConfig(
|
||||
mixnetContractAddress: string,
|
||||
mixIdentity: string,
|
||||
mixId: number,
|
||||
profitMarginPercent: number,
|
||||
fee: StdFee | 'auto' | number,
|
||||
): Promise<ExecuteResult> {
|
||||
return this.execute(
|
||||
this.clientAddress,
|
||||
mixnetContractAddress,
|
||||
{ update_mixnode_config: { profit_margin_percent: profitMarginPercent, mix_identity: mixIdentity } },
|
||||
{ update_mixnode_config: { profit_margin_percent: profitMarginPercent, mix_id: mixId } },
|
||||
fee,
|
||||
);
|
||||
}
|
||||
@@ -482,4 +519,132 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
memo,
|
||||
);
|
||||
}
|
||||
|
||||
// vesting related
|
||||
|
||||
getVestingAccountsPaged(vestingContractAddress: string): Promise<VestingAccountsPaged> {
|
||||
return this.nyxdQuerier.getVestingAccountsPaged(vestingContractAddress);
|
||||
}
|
||||
|
||||
getVestingAmountsAccountsPaged(vestingContractAddress: string): Promise<VestingAccountsCoinPaged> {
|
||||
return this.nyxdQuerier.getVestingAmountsAccountsPaged(vestingContractAddress);
|
||||
}
|
||||
|
||||
getLockedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getLockedTokens(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getSpendableTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getSpendableTokens(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getVestedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getVestedTokens(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getVestingTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getVestingTokens(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getSpendableVestedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getSpendableVestedTokens(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getSpendableRewards(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getSpendableRewards(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getDelegatedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getDelegatedCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getPledgedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getPledgedCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getStakedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getStakedCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getWithdrawnCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getWithdrawnCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getStartTime(vestingContractAddress: string, vestingAccountAddress: string): Promise<string> {
|
||||
return this.nyxdQuerier.getStartTime(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getEndTime(vestingContractAddress: string, vestingAccountAddress: string): Promise<string> {
|
||||
return this.nyxdQuerier.getEndTime(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getOriginalVestingDetails(
|
||||
vestingContractAddress: string,
|
||||
vestingAccountAddress: string,
|
||||
): Promise<OriginalVestingResponse> {
|
||||
return this.nyxdQuerier.getOriginalVestingDetails(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getHistoricStakingRewards(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getHistoricStakingRewards(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getAccountDetails(vestingContractAddress: string, address: string): Promise<VestingAccountInfo> {
|
||||
return this.nyxdQuerier.getAccountDetails(vestingContractAddress, address);
|
||||
}
|
||||
|
||||
getMixnode(vestingContractAddress: string, address: string): Promise<VestingAccountNode> {
|
||||
return this.nyxdQuerier.getMixnode(vestingContractAddress, address);
|
||||
}
|
||||
|
||||
getGateway(vestingContractAddress: string, address: string): Promise<VestingAccountNode> {
|
||||
return this.nyxdQuerier.getGateway(vestingContractAddress, address);
|
||||
}
|
||||
|
||||
getDelegationTimes(
|
||||
vestingContractAddress: string,
|
||||
mix_id: number,
|
||||
delegatorAddress: string,
|
||||
): Promise<DelegationTimes> {
|
||||
return this.nyxdQuerier.getDelegationTimes(vestingContractAddress, mix_id, delegatorAddress);
|
||||
}
|
||||
|
||||
getAllDelegations(vestingContractAddress: string): Promise<Delegations> {
|
||||
return this.nyxdQuerier.getAllDelegations(vestingContractAddress);
|
||||
}
|
||||
|
||||
getDelegation(
|
||||
vestingContractAddress: string,
|
||||
vestingAccountAddress: string,
|
||||
mix_id: number,
|
||||
): Promise<DelegationBlock> {
|
||||
return this.nyxdQuerier.getDelegation(vestingContractAddress, vestingAccountAddress, mix_id);
|
||||
}
|
||||
|
||||
getTotalDelegationAmount(
|
||||
vestingContractAddress: string,
|
||||
vestingAccountAddress: string,
|
||||
mix_id: number,
|
||||
block_timestamp_sec: number,
|
||||
): Promise<Coin> {
|
||||
return this.nyxdQuerier.getTotalDelegationAmount(
|
||||
vestingContractAddress,
|
||||
vestingAccountAddress,
|
||||
mix_id,
|
||||
block_timestamp_sec,
|
||||
);
|
||||
}
|
||||
|
||||
getCurrentVestingPeriod(vestingContractAddress: string, address: string): Promise<Period> {
|
||||
return this.nyxdQuerier.getCurrentVestingPeriod(vestingContractAddress, address);
|
||||
}
|
||||
|
||||
// simulation
|
||||
|
||||
// TODO consider adding multipling factor
|
||||
|
||||
simulateSend(signingAddress: string, from: string, to: string, amount: Coin[]) {
|
||||
const sendMsg = makeBankMsgSend(from, to, amount);
|
||||
return this.simulate(signingAddress, [sendMsg], 'simulate send tx');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,254 @@
|
||||
import { Coin } from 'cosmjs-types/cosmos/base/v1beta1/coin';
|
||||
import expect from 'expect';
|
||||
|
||||
export const amountDemon = {
|
||||
denom: expect.any(String),
|
||||
amount: expect.any(String)
|
||||
}
|
||||
|
||||
export const delegation = {
|
||||
owner: expect.any(String),
|
||||
mix_id: expect.any(Number),
|
||||
cumulative_reward_ratio: expect.any(String),
|
||||
amount: amountDemon,
|
||||
height: expect.any(Number || BigInt),
|
||||
proxy: expect.any(String || null)
|
||||
}
|
||||
|
||||
export const detailedDelegation = {
|
||||
delegation: delegation,
|
||||
mixnode_still_bonded: expect.any(Boolean)
|
||||
}
|
||||
|
||||
export const gateway = {
|
||||
pledge_amount: amountDemon,
|
||||
owner: expect.any(String),
|
||||
block_height: expect.any(Number || BigInt),
|
||||
gateway: {
|
||||
host: expect.any(String),
|
||||
mix_port: expect.any(Number),
|
||||
clients_port: expect.any(Number),
|
||||
location: expect.any(String),
|
||||
sphinx_key: expect.any(String),
|
||||
identity_key: expect.any(String),
|
||||
version: expect.any(String),
|
||||
},
|
||||
proxy: expect.any(String || null)
|
||||
}
|
||||
|
||||
export const pagedGateway = {
|
||||
nodes: gateway,
|
||||
per_page: expect.any(Number),
|
||||
start_next_after: expect.any(Number)
|
||||
}
|
||||
|
||||
export const ownGateway = {
|
||||
address: expect.any(String),
|
||||
gateway: gateway
|
||||
}
|
||||
|
||||
export const rewardingdetails = {
|
||||
cost_params: {
|
||||
profit_margin_percent: expect.any(String),
|
||||
interval_operating_cost: {
|
||||
denom: expect.any(String),
|
||||
amount: expect.any(String)
|
||||
}
|
||||
},
|
||||
operator: expect.any(String),
|
||||
delegates: expect.any(String),
|
||||
total_unit_reward: expect.any(String),
|
||||
unit_delegation: expect.any(String),
|
||||
last_rewarded_epoch: expect.any(Number),
|
||||
unique_delegations: expect.any(Number)
|
||||
}
|
||||
|
||||
export const mix_node = {
|
||||
host: expect.any(String),
|
||||
mix_port: expect.any(Number),
|
||||
verloc_port: expect.any(Number),
|
||||
http_api_port: expect.any(Number),
|
||||
sphinx_key: expect.any(String),
|
||||
identity_key: expect.any(String),
|
||||
version: expect.any(String)
|
||||
}
|
||||
|
||||
export const mixnodebond = {
|
||||
mix_id: expect.any(Number),
|
||||
owner: expect.any(String),
|
||||
original_pledge: {
|
||||
denom: expect.any(String),
|
||||
amount: expect.any(String)
|
||||
},
|
||||
layer: expect.any(String),
|
||||
mix_node: mix_node,
|
||||
proxy: expect.any(String) || null,
|
||||
bonding_height: expect.any(Number || BigInt),
|
||||
is_unbonding: expect.any(Boolean)
|
||||
}
|
||||
|
||||
export const mixnode = {
|
||||
bond_information: mixnodebond,
|
||||
rewarding_details: rewardingdetails
|
||||
}
|
||||
|
||||
export const ownedNode = {
|
||||
address: expect.any(String),
|
||||
mixnode_details: {
|
||||
bond_information: mixnodebond,
|
||||
rewarding_details: rewardingdetails
|
||||
}
|
||||
}
|
||||
|
||||
export const saturation = {
|
||||
mix_id: expect.any(Number),
|
||||
current_saturation: expect.any(String),
|
||||
uncapped_saturation: expect.any(String)
|
||||
}
|
||||
|
||||
export const contractVersion = {
|
||||
build_timestamp: expect.any(String),
|
||||
build_version: expect.any(String),
|
||||
commit_sha: expect.any(String),
|
||||
commit_timestamp: expect.any(String),
|
||||
commit_branch: expect.any(String),
|
||||
rustc_version: expect.any(String)
|
||||
};
|
||||
|
||||
export const stateParams = {
|
||||
minimum_gateway_pledge: amountDemon,
|
||||
minimum_mixnode_pledge: expect.any(String),
|
||||
mixnode_rewarded_set_size: expect.any(Number),
|
||||
mixnode_active_set_size: expect.any(Number)
|
||||
}
|
||||
|
||||
export const contract = {
|
||||
owner: expect.any(Number),
|
||||
rewarding_validator_address: expect.any(Number),
|
||||
vesting_contract_address: expect.any(Number),
|
||||
rewarding_denom: expect.any(String),
|
||||
params: stateParams
|
||||
}
|
||||
|
||||
export const rewardingnode = {
|
||||
mix_id: expect.any(Number),
|
||||
rewarding_details: rewardingdetails
|
||||
}
|
||||
|
||||
export const unbondednode = {
|
||||
mix_id: expect.any(Number),
|
||||
unbonded_info: {
|
||||
identity_key: expect.any(String),
|
||||
owner: expect.any(String),
|
||||
proxy: expect.any(String) || null,
|
||||
unbonding_height: expect.any(Number)
|
||||
}
|
||||
}
|
||||
|
||||
export const allunbondednodes = [
|
||||
expect.any(Number), {
|
||||
identity_key: expect.any(String),
|
||||
owner: expect.any(String),
|
||||
proxy: expect.any(String) || null,
|
||||
unbonding_height: expect.any(Number)
|
||||
}
|
||||
]
|
||||
|
||||
export const layerDistribution = {
|
||||
layer1: expect.any(Number),
|
||||
layer2: expect.any(Number),
|
||||
layer3: expect.any(Number)
|
||||
}
|
||||
|
||||
export const intervalRewardParams = {
|
||||
reward_pool: expect.any(Number),
|
||||
staking_supply: expect.any(Number),
|
||||
staking_supply_scale_factor: expect.any(Number),
|
||||
epoch_reward_budget: expect.any(Number),
|
||||
stake_saturation_point: expect.any(Number),
|
||||
sybil_resistance: expect.any(Number),
|
||||
active_set_work_factor: expect.any(Number),
|
||||
interval_pool_emission: expect.any(Number)
|
||||
}
|
||||
|
||||
export const rewardingParams = {
|
||||
interval: intervalRewardParams,
|
||||
rewarded_set_size: expect.any(Number),
|
||||
active_set_size: expect.any(Number)
|
||||
}
|
||||
|
||||
export const VestAccounts = [{
|
||||
account_id: expect.any(String),
|
||||
owner: expect.any(String)
|
||||
}]
|
||||
|
||||
export const VestAccountCoin = [{
|
||||
account_id: expect.any(String),
|
||||
owner: expect.any(String),
|
||||
still_vesting: Coin
|
||||
}]
|
||||
|
||||
export const vestingAccountsPaged = {
|
||||
accounts: VestAccounts,
|
||||
start_next_after: expect.any(String)
|
||||
}
|
||||
|
||||
export const VestingCoinAccounts = {
|
||||
accounts: VestAccountCoin,
|
||||
start_next_after: expect.any(String)
|
||||
}
|
||||
|
||||
export const OriginalVestingDetails = {
|
||||
amount: Coin,
|
||||
number_of_periods: expect.any(Number),
|
||||
period_duration: expect.any(Number)
|
||||
}
|
||||
|
||||
export const PledgeCap = {
|
||||
percent: expect.any(String) || null,
|
||||
};
|
||||
|
||||
export const Periods = [{
|
||||
period_seconds: expect.any(Number),
|
||||
start_time: expect.any(Number),
|
||||
}]
|
||||
|
||||
export const VestingAccountDetails = {
|
||||
owner_address: expect.any(String),
|
||||
staking_address: expect.any(String) || null,
|
||||
start_time: expect.any(String),
|
||||
periods: Periods,
|
||||
coin: Coin,
|
||||
storage_key: expect.any(Number),
|
||||
pledge_cap: PledgeCap
|
||||
}
|
||||
|
||||
export const Node = {
|
||||
amount: Coin,
|
||||
block_time: expect.any(String)
|
||||
}
|
||||
|
||||
export type VestingPeriod = 'Before' | { In: number } | 'After';
|
||||
|
||||
export const DelegationTimestamps = [
|
||||
expect.any(Number)
|
||||
]
|
||||
|
||||
export const DelegatorTimes = {
|
||||
owner: expect.any(String),
|
||||
account_id: expect.any(Number),
|
||||
mix_id: expect.any(Number),
|
||||
delegation_timestamps: DelegationTimestamps
|
||||
}
|
||||
|
||||
export const DelegationBlock = [{
|
||||
account_id: expect.any(Number),
|
||||
amount: expect.any(String),
|
||||
block_timestamp: expect.any(Number),
|
||||
mix_id: expect.any(Number)
|
||||
}]
|
||||
|
||||
export const Delegations = {
|
||||
delegations: DelegationBlock,
|
||||
start_next_after: expect.any(String) || null
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Mock, Times } from 'moq.ts';
|
||||
import expect from 'expect';
|
||||
import { INyxdQuery } from '../../query-client';
|
||||
|
||||
export class TestHelper {
|
||||
buildMethod = async <T>(methodName: string, args: any[], expectedResult: any): Promise<T> => {
|
||||
const client = new Mock<INyxdQuery>()
|
||||
.setup((nym) => nym[methodName](...args))
|
||||
.returns(Promise.resolve(expectedResult));
|
||||
const obj = client.object();
|
||||
const actualDetails = await obj[methodName](...args);
|
||||
|
||||
client.verify((nym) => nym[methodName](...args), Times.Exactly(1));
|
||||
expect(Object.keys([actualDetails])).toEqual(Object.keys(expectedResult));
|
||||
expect(actualDetails).toBeDefined();
|
||||
|
||||
return actualDetails;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import expect from 'expect';
|
||||
import { Delegation } from '@nymproject/types';
|
||||
import { PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse } from '../../types/shared-types';
|
||||
import { TestHelper } from './client';
|
||||
import { mixnet, mixnodeowneraddress, mix_id } from './testData';
|
||||
|
||||
describe('Delegation mock tests', () => {
|
||||
const testHelper = new TestHelper();
|
||||
|
||||
it('get Delegation Details', () => {
|
||||
const execute = testHelper.buildMethod('getDelegationDetails', [mixnet, mix_id, mixnodeowneraddress], <Delegation>{
|
||||
owner: mixnodeowneraddress,
|
||||
mix_id: 0,
|
||||
cumulative_reward_ratio: '',
|
||||
amount: {
|
||||
denom: 'nym',
|
||||
amount: '10',
|
||||
},
|
||||
height: 1314134144132n,
|
||||
proxy: 'null',
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get All Delegations Paged', () => {
|
||||
const execute = testHelper.buildMethod('getAllDelegationsPaged', [mixnet], <PagedAllDelegationsResponse>{
|
||||
delegations: [],
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get Delegator Delegations Paged', () => {
|
||||
const execute = testHelper.buildMethod('getDelegatorDelegationsPaged', [mixnet, mixnodeowneraddress], <
|
||||
PagedDelegatorDelegationsResponse
|
||||
>{
|
||||
delegations: [],
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
import expect from 'expect';
|
||||
import { GatewayOwnershipResponse, PagedGatewayResponse } from '../../types/shared-types';
|
||||
import { TestHelper } from './client';
|
||||
import { gatewayowneraddress, mixnet } from './testData';
|
||||
|
||||
describe('Gateway mock tests', () => {
|
||||
const testHelper = new TestHelper();
|
||||
|
||||
it('get Gateways Paged', () => {
|
||||
const execute = testHelper.buildMethod('getGatewaysPaged', [mixnet], <PagedGatewayResponse>{
|
||||
nodes: [],
|
||||
per_page: 25,
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('owns Gateway', () => {
|
||||
const execute = testHelper.buildMethod('ownsGateway', [mixnet, gatewayowneraddress], <GatewayOwnershipResponse>{
|
||||
address: gatewayowneraddress,
|
||||
gateway: {},
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,65 @@
|
||||
import expect from 'expect';
|
||||
import { LayerDistribution, MixnetContractVersion, StakeSaturationResponse } from '@nymproject/types';
|
||||
import { TestHelper } from './client';
|
||||
import { mixnet, mix_id } from './testData';
|
||||
import { RewardingParams } from '@nymproject/types';
|
||||
import { ContractState } from '../../types/shared';
|
||||
|
||||
describe('Mixnet mock tests', () => {
|
||||
const testHelper = new TestHelper();
|
||||
|
||||
it('get Layer Distribution', () => {
|
||||
const execute = testHelper.buildMethod('getLayerDistribution', [mixnet], <LayerDistribution>{
|
||||
layer1: 2,
|
||||
layer2: 2,
|
||||
layer3: 5,
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get Reward Params', () => {
|
||||
const execute = testHelper.buildMethod('getRewardParams', [mixnet], <RewardingParams>{
|
||||
interval: {},
|
||||
rewarded_set_size: 0,
|
||||
active_set_size: 0,
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get Stake Saturation', () => {
|
||||
const execute = testHelper.buildMethod('getStakeSaturation', [mixnet, mix_id], <StakeSaturationResponse>{
|
||||
mix_id: 0,
|
||||
current_saturation: '',
|
||||
uncapped_saturation: '',
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get State Params', () => {
|
||||
const execute = testHelper.buildMethod('getStateParams', [mixnet], <ContractState>{
|
||||
owner: '',
|
||||
rewarding_validator_address: '',
|
||||
vesting_contract_address: '',
|
||||
rewarding_denom: 'unym',
|
||||
params: {
|
||||
minimum_mixnode_pledge: '',
|
||||
minimum_gateway_pledge: '',
|
||||
mixnode_rewarded_set_size: 240,
|
||||
mixnode_active_set_size: 240,
|
||||
},
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get Contract Version', () => {
|
||||
const execute = testHelper.buildMethod('getContractVersion', [mixnet], <MixnetContractVersion>{
|
||||
build_timestamp: 'test',
|
||||
commit_branch: 'test',
|
||||
build_version: 'test',
|
||||
rustc_version: 'test',
|
||||
commit_sha: 'test',
|
||||
commit_timestamp: 'test',
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,71 @@
|
||||
import expect from 'expect';
|
||||
import {
|
||||
MixNodeRewarding,
|
||||
MixOwnershipResponse,
|
||||
PagedMixDelegationsResponse,
|
||||
PagedMixNodeBondResponse,
|
||||
PagedMixNodeDetailsResponse,
|
||||
UnbondedMixnodeResponse,
|
||||
} from '@nymproject/types';
|
||||
import { TestHelper } from './client';
|
||||
import { mixnet, mixnodeowneraddress, mix_id } from './testData';
|
||||
|
||||
describe('Mixnode mock tests', () => {
|
||||
const testHelper = new TestHelper();
|
||||
|
||||
it('get Mixnode Bonds', () => {
|
||||
const execute = testHelper.buildMethod('getMixNodeBonds', [mixnet], <PagedMixNodeBondResponse>{
|
||||
nodes: [],
|
||||
per_page: 25,
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get Mixnode Delegations Paged', () => {
|
||||
const execute = testHelper.buildMethod('getMixNodeDelegationsPaged', [mixnet, mix_id], <
|
||||
PagedMixDelegationsResponse
|
||||
>{
|
||||
delegations: [],
|
||||
per_page: 25,
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get Mixnodes Detailed', () => {
|
||||
const execute = testHelper.buildMethod('getMixNodesDetailed', [mixnet], <PagedMixNodeDetailsResponse>{
|
||||
nodes: [],
|
||||
per_page: 25,
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get Mixnode Rewarding Details', () => {
|
||||
const execute = testHelper.buildMethod('getMixnodeRewardingDetails', [mixnet, mix_id], <MixNodeRewarding>{
|
||||
cost_params: {},
|
||||
operator: '',
|
||||
delegates: '',
|
||||
total_unit_reward: '',
|
||||
unit_delegation: '',
|
||||
last_rewarded_epoch: 1,
|
||||
unique_delegations: 1,
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get Owned Mixnode', () => {
|
||||
const execute = testHelper.buildMethod('getOwnedMixnode', [mixnet, mixnodeowneraddress], <MixOwnershipResponse>{
|
||||
address: '',
|
||||
mixnode: {},
|
||||
});
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
|
||||
it('get Unbonded Mixnode Information', () => {
|
||||
const execute = testHelper.buildMethod(
|
||||
'getUnbondedMixNodeInformation',
|
||||
[mixnet, mix_id],
|
||||
<UnbondedMixnodeResponse>{},
|
||||
);
|
||||
expect(execute).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
export const mixnet = 'n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g';
|
||||
export const gatewayowneraddress = 'n16evnn8glr0sham3matj8rg2s24m6x56ayk87ts';
|
||||
// export const mixId = 436207616;
|
||||
export const mix_id = 26;
|
||||
export const nodeIdentityKey = 'ATmVJknZarDF6Yj53M7h8NS9LLCUvWuToXpk3pDvYUH1';
|
||||
export const mixnodeowneraddress = 'n1fzv4jc7fanl9s0qj02ge2ezk3kts545kjtek47';
|
||||
export const delegatorAddress = 'n1lemst75va9700tsrxq58adzujrh6h9s5x60h9h';
|
||||
export const rewardingIntervalNonce = 1;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user